diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2018-01-09 19:06:55 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2018-01-09 19:06:55 (GMT) |
commit | 01e0ebfe59d9028b0246ec4a549bd7528ada94eb (patch) | |
tree | a6c5b54db03177a1c8f3e7fb531990dfbc7bae39 /ast/cmpframe.c | |
parent | d64cf9c0bd23e752867b149be636d1bbd4501cf4 (diff) | |
download | blt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.zip blt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.tar.gz blt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.tar.bz2 |
update ast 8.6.2
Diffstat (limited to 'ast/cmpframe.c')
-rw-r--r-- | ast/cmpframe.c | 10846 |
1 files changed, 10846 insertions, 0 deletions
diff --git a/ast/cmpframe.c b/ast/cmpframe.c new file mode 100644 index 0000000..48e971a --- /dev/null +++ b/ast/cmpframe.c @@ -0,0 +1,10846 @@ +/* +*class++ +* Name: +* CmpFrame + +* Purpose: +* Compound Frame. + +* Constructor Function: +c astCmpFrame +f AST_CMPFRAME + +* Description: +* A CmpFrame is a compound Frame which allows two component Frames +* (of any class) to be merged together to form a more complex +* Frame. The axes of the two component Frames then appear together +* in the resulting CmpFrame (those of the first Frame, followed by +* those of the second Frame). +* +* Since a CmpFrame is itself a Frame, it can be used as a +* component in forming further CmpFrames. Frames of arbitrary +* complexity may be built from simple individual Frames in this +* way. +* +* Also since a Frame is a Mapping, a CmpFrame can also be used as a +* Mapping. Normally, a CmpFrame is simply equivalent to a UnitMap, +* but if either of the component Frames within a CmpFrame is a Region +* (a sub-class of Frame), then the CmpFrame will use the Region as a +* Mapping when transforming values for axes described by the Region. +* Thus input axis values corresponding to positions which are outside the +* Region will result in bad output axis values. + +* Inheritance: +* The CmpFrame class inherits from the Frame class. + +* Attributes: +* The CmpFrame class does not define any new attributes beyond +* those which are applicable to all Frames. However, the attributes +* of the component Frames can be accessed as if they were attributes +* of the CmpFrame. For instance, if a CmpFrame contains a SpecFrame +* and a SkyFrame, then the CmpFrame will recognise the "Equinox" +* attribute and forward access requests to the component SkyFrame. +* Likewise, it will recognise the "RestFreq" 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 CmpFrame class does not define any new functions beyond those +f The CmpFrame class does not define any new routines beyond those +* which are applicable to all Frames. + +* 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 Lesser General Public +* License as published by the Free Software Foundation, either +* version 3 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General +* License along with this program. If not, see +* <http://www.gnu.org/licenses/>. + +* Authors: +* RFWS: R.F. Warren-Smith (Starlink) +* DSB: David S. Berry (Starlink) + +* History: +* 4-MAR-1996 (RFWS): +* Original version. +* 27-FEB-1997 (RFWS): +* Improved public prologues. +* 25-FEB-1998 (RFWS): +* Over-ride the astUnformat method. +* 6-APR-1998 (RFWS): +* Fixed bug in returned value of GenAxisSelection. +* 22-SEP-1998 (RFWS): +* Fixed bug in Match function - was not checking Domain values +* for equality. +* 11-JUN-1999 (RFWS): +* Fixed bug in GenAxisSelection- some selections were being omitted. +* 5-FEB-2001 (DSB): +* Ensure that Title and Domain values appropriate to a CmpFrame +* are preserved if a CmpFrame result is generated by SubFrame. +* 27-FEB-2001 (DSB): +* Modified Match so that all the frames have some axes in order to +* match. Otherwise, null pointers are created (for zero axes), +* resulting in a seg vio. +* 21-JUN-2001 (DSB): +* Added astAngle. +* 7-SEP-2001 (DSB): +* Added astResolve. +* 26-SEP-2001 (DSB): +* Over-ride the astDecompose method. +* 20-DEC-2002 (DSB): +* Allows any attribute of a component frame to be accessed as though +* it were an attribute of the CmpFrame by including an axis index in +* the attribute name (e.g. "System(3)"). +* 8-JAN-2003 (DSB): +* - Changed private InitVtab method to protected astInitCmpFrameVtab +* method. +* - Override astGetAttrib, astClearAttrib, astTestAttrib, +* astSetAttrib to allow attributes to be set for individual +* axes. +* - Override astGetEpoch astGetSystem, astGetAlignSystem. +* astValidateSystem, astSystemString, astSystemCode. +* 27-FEB-2003 (DSB): +* - Modify the default Domain name for a CmpFrame to be the +* domains of the two subFrames separated by a "-". +* 24-JAN-2004 (DSB): +* o Override the astFields method. +* o Added argument "fmt" to Abbrev. +* 24-MAR-2004 (DSB): +* Over-ride the astSimplify and astTransform methods. +* 8-SEP-2004 (DSB): +* Over-ride astResolvePoints method. +* 21-JAN-2005 (DSB): +* Over-ride the astGetActiveUnit and astSetActiveUnit methods. +* 23-FEB-2005 (DSB): +* Modify GetDomain to avoid over-writing the static "buff" array +* if called recursively. +* 29-MAR-2005 (DSB): +* Override astSetEpoch and astClearEpoch by implementations which +* propagate the changed epoch value to the component Frames. +* 5-APR-2005 (DSB): +* Correct error checking in Clear/Get/Set/TestAttrib. +* 12-MAY-2005 (DSB): +* Override astNormBox method. +* 12-AUG-2005 (DSB): +* Override astSetObsLat/Lon and astClearObslat/Lon by implementations +* which propagate the changed value to the component Frames. +* 14-FEB-2006 (DSB): +* Override astGetObjSize. +* 3-APR-2006 (DSB): +* Modify Match so that an attempt is made to align the target with +* each of the two component Frames if the target cannot be matched +* with the CmpFrame as a whole. +* 3-MAY-2006 (DSB): +* Fix bug in Match that could cause segvio when matching a target +* against the second component of a CmpFrame. +* 31-OCT-2006 (DSB): +* Over-ride the SetFrameFlags method. +* 1-NOV-2005 (DSB): +* Override astSetDut1, astGetDut1 and astClearDut1. +* 15-MAR-2007 (DSB): +* Override astClearAlignSystem by an implementation that clears +* AlignSystem in the component Frames. +* 7-FEB-2008 (DSB): +* Allow the MaxAxes and MinAxes attributes to be specified for a +* CmpFrame (rather than just being the sum of the attribute values +* in the component frames). This enables, for instance, a (detector +* index,mjd) frame to match with a ((velocity,detector index),mjd) +* frame. +* 5-MAY-2009 (DSB): +* In GetAttrib, if an index is included in the attribute name, attempt +* to use the GetAttrib method of the primary frame before using the +* parent GetAttrib method. This is because the Frame getattrib +* method will dissociate axes from their parent class. Thus, a +* SkyAxis attribute such as AsTime will come out wrong since its +* value is managed by the SkyFrame class rather than the SkyAxis +* class. +* 18-JUN-2009 (DSB): +* Override astSetObsAlt and astClearObsAlt. +* 29-SEP-2009 (DSB): +* Ensure the astMatch method provided by this class honours the +* PreserveAxes, MaxAxes and MinAxes attribute settings. +* 22-MAR-2011 (DSB): +* Override astFrameGrid method. +* 29-APR-2011 (DSB): +* Prevent astFindFrame from matching a subclass template against a +* superclass target. +* 10-FEB-2015 (DSB): +* When checking attribute settings for attribute names that end with +* an axis index, stop looking for the axis index when the first equals +* sign is encountered. +* 26-MAR-2015 (DSB): +* Increase size of "buf2" buffer in SetAttrib, and trap buffer overflow. +* 11-JAN-2017 (GSB): +* Override astSetDtai, astGetDtai and astClearDtai. +*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 CmpFrame + +/* Define the first and last acceptable System values. */ +#define FIRST_SYSTEM AST__COMP +#define LAST_SYSTEM AST__COMP + +/* Define macros to implement member functions for accessing axis + attributes. */ +/* +* Name: +* MAKE_CLEAR + +* Purpose: +* Implement a function to clear an attribute value for a CmpFrame axis. + +* Type: +* Private macro. + +* Synopsis: +* #include "cmpframe.h" +* MAKE_CLEAR(attribute) + +* Class Membership: +* Defined by the CmpFrame class. + +* Description: +* This macro expands to an implementation of a private member +* function of the form: +* +* static void Clear<Attribute>( AstFrame *this, int axis ) +* +* which clears an attribute value for a specified axis of a CmpFrame. + +* Parameters: +* attribute +* The name of the attribute to be cleared, as it appears in the +* function name (e.g. Label in "ClearLabel"). + +* Notes: +* - This macro assumes the existence of a method of the form: +* +* void astClear<Attribute>( AstFrame *this, int axis ) +* +* which clears the required attribute for a Frame 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) \ +static void Clear##attribute( AstFrame *this_frame, int axis, int *status ) { \ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ \ + int naxes1; /* Number of axes in frame1 */ \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return; \ +\ +/* Obtain a pointer to the CmpFrame structure. */ \ + this = (AstCmpFrame *) this_frame; \ +\ +/* Validate and alidateAxispermute the axis index supplied. */ \ + axis = astValidateAxis( this, axis, 1, "astSet" #attribute ); \ +\ +/* Determine the number of axes in the first component Frame. */ \ + naxes1 = astGetNaxes( this->frame1 ); \ + if ( astOK ) { \ +\ +/* Decide which Frame contains the axis and invoke its astClear... method to \ + clear the attribute value. */ \ + if ( axis < naxes1 ) { \ + astClear##attribute( this->frame1, axis ); \ + } else { \ + astClear##attribute( this->frame2, axis - naxes1 ); \ + } \ + } \ +} + +/* +* Name: +* MAKE_GET + +* Purpose: +* Implement a function to get an attribute value for a CmpFrame axis. + +* Type: +* Private macro. + +* Synopsis: +# #include "cmpframe.h" +* MAKE_GET(attribute,type,bad_value,default,assign_default) + +* Class Membership: +* Defined by the CmpFrame class. + +* Description: +* This macro expands to an implementation of a private member +* function of the form: +* +* static <Type> Get<Attribute>( AstFrame *this, int axis ) +* +* which gets an attribute value for a specified axis of a +* CmpFrame. + +* Parameters: +* attribute +* The name of the attribute whose value is to be obtained, as +* it appears in the function name (e.g. Label in "GetLabel"). +* 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) value that indicates whether a new default +* value should be returned if the requested attribute has not +* been set for the appropriate axis of the appropriate +* component Frame. If this value is zero, the component Frame's +* default (for the appropriate axis) 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: +* +* <Type> astGet<Attribute>( AstFrame *this, int axis ) +* +* which gets the required attribute for a Frame 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) \ +static type Get##attribute( AstFrame *this_frame, int axis, int *status ) { \ + astDECLARE_GLOBALS /* Declare the thread specific global data */ \ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ \ + AstFrame *frame; /* Pointer to Frame containing axis */\ + int axis_p; /* Permuted axis index */ \ + int naxes1; /* Number of axes in frame1 */ \ + int set; /* Digits attribute set? */ \ + type result; /* Result value to return */ \ + \ +/* Initialise. */ \ + result = (bad_value); \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return result; \ +\ +/* Get a pointer to the structure holding thread-specific global data. */ \ + astGET_GLOBALS(this_frame); \ +\ +/* Obtain a pointer to the CmpFrame structure. */ \ + this = (AstCmpFrame *) this_frame; \ +\ +/* Validate and permute the axis index supplied. */ \ + axis_p = astValidateAxis( this, axis, 1, "astGet" #attribute ); \ +\ +/* Determine the number of axes in the first component Frame. */ \ + naxes1 = astGetNaxes( this->frame1 ); \ + if ( astOK ) { \ +\ +/* Decide which Frame contains the axis and adjust the axis index if \ + necessary. */ \ + frame = ( axis_p < naxes1 ) ? this->frame1 : this->frame2; \ + axis_p = ( axis_p < naxes1 ) ? axis_p : axis_p - naxes1; \ +\ +/* Since the component Frame is "managed" by the enclosing CmpFrame, we next \ + test if any Frame 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 CmpFrame. Only the Digits attribute \ + is relevant here. */ \ + set = astTestDigits( frame ); \ + if ( !set ) astSetDigits( frame, astGetDigits( this ) ); \ +\ +/* If the default value is to be over-ridden, test if the Frame's axis \ + attribute has been set. Then, if required, obtain the attribute value from \ + the Frame. */ \ + if ( !(default) || astTest##attribute( frame, axis_p ) ) { \ + result = astGet##attribute( frame, axis_p ); \ +\ +/* If required, assign the new default value. */ \ + } else { \ + result = (assign_default); \ + } \ +\ +/* Clear Frame attributes which were temporarily over-ridden. */ \ + if ( !set ) astClearDigits( frame ); \ + } \ +\ +/* If an error occurred, clear the result value. */ \ + if ( !astOK ) result = (bad_value); \ +\ +/* Return the result. */ \ + return result; \ +} + +/* +* Name: +* MAKE_SET + +* Purpose: +* Implement a function to set an attribute value for a CmpFrame axis. + +* Type: +* Private macro. + +* Synopsis: +* #include "cmpframe.h" +* MAKE_SET(attribute,type) + +* Class Membership: +* Defined by the CmpFrame class. + +* Description: +* This macro expands to an implementation of a private member +* function of the form: +* +* static void Set<Attribute>( AstFrame *this, int axis, <Type> value ) +* +* which sets an attribute value for a specified axis of a CmpFrame. + +* Parameters: +* attribute +* The name of the attribute to be set, as it appears in the +* function name (e.g. Label in "SetLabel"). +* type +* The C type of the attribute. + +* Notes: +* - This macro assumes the existence of a method of the form: +* +* void astSet<Attribute>( AstFrame *this, int axis, <Type> value ) +* +* which sets the required attribute for a Frame 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) \ +static void Set##attribute( AstFrame *this_frame, int axis, type value, int *status ) { \ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ \ + int naxes1; /* Number of axes in frame1 */ \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return; \ +\ +/* Obtain a pointer to the CmpFrame structure. */ \ + this = (AstCmpFrame *) this_frame; \ +\ +/* Validate and permute the axis index supplied. */ \ + axis = astValidateAxis( this, axis, 1, "astSet" #attribute ); \ +\ +/* Determine the number of axes in the first component Frame. */ \ + naxes1 = astGetNaxes( this->frame1 ); \ + if ( astOK ) { \ +\ +/* Decide which Frame contains the axis and invoke its astSet... method to \ + set the attribute value. */ \ + if ( axis < naxes1 ) { \ + astSet##attribute( this->frame1, axis, value ); \ + } else { \ + astSet##attribute( this->frame2, axis - naxes1, value ); \ + } \ + } \ +} + +/* +* Name: +* MAKE_TEST + +* Purpose: +* Implement a function to test if an attribute is set for a CmpFrame axis. + +* Type: +* Private macro. + +* Synopsis: +* #include "cmpframe.h" +* MAKE_TEST(attribute) + +* Class Membership: +* Defined by the CmpFrame class. + +* Description: +* This macro expands to an implementation of a private member +* function of the form: +* +* static int Test<Attribute>( AstFrame *this, int axis ) +* +* which tests whether an attribute value is set for a specified +* axis of a CmpFrame. + +* Parameters: +* attribute +* The name of the attribute to be tested, as it appears in the +* function name (e.g. Label in "TestLabel"). + +* Notes: +* - This macro assumes the existence of a method of the form: +* +* int astTest<Attribute>( AstFrame *this, int axis ) +* +* which tests the required attribute for a Frame 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) \ +static int Test##attribute( AstFrame *this_frame, int axis, int *status ) { \ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ \ + int naxes1; /* Number of axes in frame1 */ \ + int result; /* Result value to return */ \ +\ +/* Initialise. */ \ + result = 0; \ +\ +/* Check the global error status. */ \ + if ( !astOK ) return result; \ +\ +/* Obtain a pointer to the CmpFrame structure. */ \ + this = (AstCmpFrame *) this_frame; \ +\ +/* Validate and permute the axis index supplied. */ \ + axis = astValidateAxis( this, axis, 1, "astSet" #attribute ); \ +\ +/* Determine the number of axes in the first component Frame. */ \ + naxes1 = astGetNaxes( this->frame1 ); \ + if ( astOK ) { \ +\ +/* Decide which Frame contains the axis and invoke its astTest... method to \ + test the attribute. */ \ + if ( axis < naxes1 ) { \ + result = astTest##attribute( this->frame1, axis ); \ + } else { \ + result = astTest##attribute( this->frame2, axis - naxes1 ); \ + } \ + } \ +\ +/* Return the result. */ \ + return result; \ +} + +/* 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 "pointset.h" /* Sets of points */ +#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 "frame.h" /* Parent Frame class */ +#include "cmpframe.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 <limits.h> +#include <float.h> +#include <math.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* 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 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_gettitle)( AstFrame *, int * ); +static double (* parent_angle)( AstFrame *, const double[], const double[], const double[], int * ); +static double (* parent_getdtai)( AstFrame *, int * ); +static double (* parent_getdut1)( AstFrame *, int * ); +static double (* parent_getepoch)( AstFrame *, int * ); +static double (* parent_getobsalt)( AstFrame *, int * ); +static double (* parent_getobslat)( AstFrame *, int * ); +static double (* parent_getobslon)( AstFrame *, int * ); +static int (* parent_getactiveunit)( AstFrame *, int * ); +static int (* parent_getmaxaxes)( AstFrame *, int * ); +static int (* parent_getminaxes)( AstFrame *, int * ); +static int (* parent_getobjsize)( AstObject *, int * ); +static int (* parent_getusedefs)( AstObject *, int * ); +static int (* parent_testattrib)( AstObject *, const char *, int * ); +static void (* parent_clearalignsystem)( AstFrame *, int * ); +static void (* parent_clearattrib)( AstObject *, const char *, int * ); +static void (* parent_cleardtai)( AstFrame *, int * ); +static void (* parent_cleardut1)( AstFrame *, int * ); +static void (* parent_clearepoch)( AstFrame *, int * ); +static void (* parent_clearobsalt)( AstFrame *, int * ); +static void (* parent_clearobslat)( AstFrame *, int * ); +static void (* parent_clearobslon)( AstFrame *, int * ); +static void (* parent_overlay)( AstFrame *, const int *, AstFrame *, int * ); +static void (* parent_setactiveunit)( AstFrame *, int, int * ); +static void (* parent_setattrib)( AstObject *, const char *, int * ); +static void (* parent_setdtai)( AstFrame *, double, int * ); +static void (* parent_setdut1)( AstFrame *, double, int * ); +static void (* parent_setepoch)( AstFrame *, double, int * ); +static void (* parent_setframeflags)( AstFrame *, int, int * ); +static void (* parent_setobsalt)( AstFrame *, double, int * ); +static void (* parent_setobslat)( AstFrame *, double, int * ); +static void (* parent_setobslon)( AstFrame *, double, 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->Label_Buff[ 0 ] = 0; \ + globals->Symbol_Buff[ 0 ] = 0; \ + globals->GetDomain_Buff[ 0 ] = 0; \ + globals->GetTitle_Buff[ 0 ] = 0; + +/* Create the function that initialises global data for this module. */ +astMAKE_INITGLOBALS(CmpFrame) + +/* Define macros for accessing each item of thread specific global data. */ +#define class_init astGLOBAL(CmpFrame,Class_Init) +#define class_vtab astGLOBAL(CmpFrame,Class_Vtab) +#define getdomain_buff astGLOBAL(CmpFrame,GetDomain_Buff) +#define gettitle_buff astGLOBAL(CmpFrame,GetTitle_Buff) +#define label_buff astGLOBAL(CmpFrame,Label_Buff) +#define symbol_buff astGLOBAL(CmpFrame,Symbol_Buff) +#define qsort_axes astGLOBAL(CmpFrame,qsort_axes) + + + +/* If thread safety is not needed, declare and initialise globals at static + variables. */ +#else + +/* Pointer to axis index array accessed by "qsort". */ +static int *qsort_axes; + +/* Default Label string buffer */ +static char label_buff[ 101 ]; + +/* Default Symbol buffer */ +static char symbol_buff[ 51 ]; + +/* Buffer for returned domain name in GetDomain */ +static char getdomain_buff[ 101 ]; + +/* Buffer for returned title in GetTitle */ +static char gettitle_buff[ 101 ]; + + +/* Define the class virtual function table and its initialisation flag + as static variables. */ +static AstCmpFrameVtab 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. */ +AstCmpFrame *astCmpFrameId_( void *, void *, const char *, ... ); + +/* Prototypes for Private Member Functions. */ +/* ======================================== */ +static AstAxis *GetAxis( AstFrame *, int, int * ); +static AstMapping *RemoveRegions( AstMapping *, int * ); +static AstMapping *Simplify( AstMapping *, int * ); +static AstObject *Cast( AstObject *, AstObject *, 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 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 *Abbrev( AstFrame *, int, const char *, const char *, const char *, int * ); +static const char *Format( AstFrame *, int, double, int * ); +static const char *GetDomain( AstFrame *, int * ); +static const char *GetFormat( AstFrame *, int, 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 *SystemString( AstFrame *, AstSystemType, int * ); +static const int *GetPerm( AstFrame *, int * ); +static double Angle( AstFrame *, const double[], const double[], const double[], int * ); +static double Distance( AstFrame *, const double[], const double[], int * ); +static double Centre( AstFrame *, int, double, double, int * ); +static double Gap( AstFrame *, int, double, int *, int * ); +static int ComponentMatch( AstCmpFrame *, AstFrame *, int, int, int **, int **, AstMapping **, AstFrame **, int * ); +static int Fields( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * ); +static int GenAxisSelection( int, int, int [], int * ); +static int GetActiveUnit( AstFrame *, int * ); +static int GetDirection( AstFrame *, int, int * ); +static int GetMaxAxes( AstFrame *, int * ); +static int GetMinAxes( AstFrame *, int * ); +static int GetNaxes( AstFrame *, int * ); +static int GetObjSize( AstObject *, int * ); +static int GetUseDefs( AstObject *, int * ); +static int GoodPerm( int, const int [], int, const int [], int * ); +static int IsUnitFrame( AstFrame *, int * ); +static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); +static int PartMatch( AstCmpFrame *, AstFrame *, int, int, const int [], int, const int [], int **, int **, AstMapping **, AstFrame **, int * ); +static int QsortCmpAxes( const void *, const void * ); +static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); +static int TestDirection( AstFrame *, int, int * ); +static int TestFormat( AstFrame *, int, int * ); +static int TestLabel( AstFrame *, int, int * ); +static int TestSymbol( AstFrame *, int, int * ); +static int TestUnit( AstFrame *, int, int * ); +static int Unformat( AstFrame *, int, const char *, double *, int * ); +static void AddExtraAxes( int, int [], int, int, int, int * ); +static void ClearDirection( AstFrame *, int, int * ); +static void ClearFormat( AstFrame *, int, int * ); +static void ClearLabel( AstFrame *, int, int * ); +static void ClearSymbol( AstFrame *, int, int * ); +static void ClearUnit( AstFrame *, int, 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 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 PartitionSelection( int, const int [], const int [], int, int, int [], int, int * ); +static void PermAxes( AstFrame *, const int[], int * ); +static void PrimaryFrame( AstFrame *, int, AstFrame **, int *, int * ); +static void RenumberAxes( int, int [], int * ); +static void Resolve( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * ); +static void SetActiveUnit( AstFrame *, int, int * ); +static void SetAxis( AstFrame *, int, AstAxis *, int * ); +static void SetDirection( AstFrame *, int, int, 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 SetSymbol( AstFrame *, int, const char *, int * ); +static void SetUnit( AstFrame *, int, const char *, 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 double GetEpoch( AstFrame *, int * ); +static void ClearEpoch( AstFrame *, int * ); +static void SetEpoch( AstFrame *, double, int * ); + +static double GetDtai( AstFrame *, int * ); +static void ClearDtai( AstFrame *, int * ); +static void SetDtai( AstFrame *, double, int * ); + +static double GetDut1( AstFrame *, int * ); +static void ClearDut1( AstFrame *, int * ); +static void SetDut1( AstFrame *, double, int * ); + +static double GetObsLon( AstFrame *, int * ); +static void ClearObsLon( AstFrame *, int * ); +static void SetObsLon( AstFrame *, double, int * ); + +static double GetObsLat( AstFrame *, int * ); +static void ClearObsLat( AstFrame *, int * ); +static void SetObsLat( AstFrame *, double, int * ); + +static double GetObsAlt( AstFrame *, int * ); +static void ClearObsAlt( AstFrame *, int * ); +static void SetObsAlt( AstFrame *, double, int * ); + +static void ClearAlignSystem( AstFrame *, 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 CmpFrame axis value by skipping leading fields. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* const char *Abbrev( AstFrame *this, int axis, const char *fmt, +* const char *str1, const char *str2, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the protected astAbbrev +* method inherited from the Frame class). + +* Description: +* This function compares two CmpFrame 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 CmpFrame. +* axis +* The number of the CmpFrame 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. +* 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 CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstFrame *frame; /* Pointer to Frame containing axis */ + const char *result; /* Pointer value to return */ + int naxes1; /* Number of axes in frame1 */ + int set; /* Digits attribute set? */ + +/* Initialise. */ + result = str2; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis = astValidateAxis( this, axis, 1, "astAbbrev" ); + +/* Determine the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + if ( astOK ) { + +/* Decide which component Frame contains the axis and adjust the axis + index if necessary. */ + frame = ( axis < naxes1 ) ? this->frame1 : this->frame2; + axis = ( axis < naxes1 ) ? axis : axis - naxes1; + +/* Since the component Frame is "managed" by the enclosing CmpFrame, + we next test if any Frame 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 + CmpFrame. Only the Digits attribute is relevant here. */ + set = astTestDigits( frame ); + if ( !set ) astSetDigits( frame, astGetDigits( this ) ); + +/* Invoke the Frame's astAbbrev method to perform the processing. */ + result = astAbbrev( frame, axis, fmt, str1, str2 ); + +/* Clear Frame attributes which were temporarily over-ridden. */ + if ( !set ) astClearDigits( frame ); + } + +/* If an error occurred, clear the returned value. */ + if ( !astOK ) result = str2; + +/* Return the result. */ + return result; +} + +static void AddExtraAxes( int naxes, int axes[], int i1, int i2, + int following, int *status ) { +/* +* Name: +* AddExtraAxes + +* Purpose: +* Add extra axis indices in place of missing ones. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void AddExtraAxes( int naxes, int axes[], int i1, int i2, +* int following, int *status ) + +* Class Membership: +* CmpFrame member function. + +* Description: +* This function takes an array of axis indices that refer to the +* axes of a Frame, and which may have values missing (denoted by +* an index of -1). It replaces each occurrence of -1 by a new axis +* index (and re-numbers the others to avoid duplication) in such a +* way that the new indices introduced are "associated" with +* certain of the pre-existing indices, by virtue of being numbered +* consecutively with them. +* +* The purpose of this operation is to establish the relative +* location of new axes in relation to the pre-existing ones. +* +* Normally, each new axis will be associated with (i.e. numbered +* one more than) the pre-existing index which precedes +* it. However, if the "following" parameter is non-zero, it will +* instead be associated with (numbered one less than) the one +* which follows it. If there is no preceding (or following) +* pre-existing index, the following (or preceding) one is used +* instead. If several adjacent occurrences of -1 must be replaced, +* they are numbered consecutively in their order of occurrence. + +* Parameters: +* naxes +* The number of axis indices in the array. +* axes +* The array containing the axis indices. +* i1 +* Index of the first element of the array to be processed. +* i2 +* Index of the last element of the array to be processed. +* following +* Boolean flag to determine if new indices are associated with +* the preceding index (if zero) or the following index (if +* non-zero). +* status +* Pointer to the inherited status variable. + +* Notes: +* - The values of "i1" and "i2" dictate the range of array +* elements where values of -1 will be replaced, but all array +* elements are candidates for renumbering in order to avoid +* duplicate axis indices. +* - This function aims to establish the location of new axes only +* by means of the relative numerical value of the indices assigned +* to them. It does not constrain the actual indices assigned in +* any further way. +* - Because axis indices are always incremented (never +* decremented) in order to avoid duplicates, where a number of new +* indices have been introduced, the maximum index present in the +* result array may exceed the original maximum. +* - Some axis indices may remain unused (i.e. not present) in the +* result array. +*/ + +/* Local Variables: */ + int end; /* Loop termination value */ + int extra; /* Index to apply to next "extra" axis */ + int found; /* Default value found? */ + int i; /* Main loop counter */ + int inc; /* Loop increment value */ + int j; /* Loop counter for eliminating duplicates */ + int start; /* Loop starting value */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Initialise the default index of the next extra axis to add. This + will apply only if there are no valid axis indices from which to + obtain a better default. */ + extra = 0; + +/* Initialise loop parameters so as to scan the axis indices provided + in either the forward or reverse direction, according to the value + of "following". Start with the section of the array being processed, + but continue looking for a default right up to the end of the array + (this prevents the current section being numbered inconsistently + with respect to adjacent ones that may already have been + processed). */ + start = following ? i2 : i1; + end = following ? -1 : naxes; + inc = following ? -1 : 1; + +/* Search for the first (in whichever direction this is) valid axis + index and use it to set a new default index for the next extra axis + to add. If scanning forward, use the valid axis index (causing any + preceding extra axis to displace it upwards). If scanning + backwards, use one more than the valid axis index (causing any + following extra axis to tag on the end). */ + found = 0; + for ( i = start; i != end; i += inc ) { + if ( axes[ i ] != -1 ) { + found = 1; + extra = axes[ i ] + ( following ? 1 : 0 ); + break; + } + } + +/* If no default has yet been found, repeat the above process by + scanning in the opposite direction (by inverting the "following" + value used). Again, this prevents inconsistency with neighbouring + regions. This time a default must be found unless the entire array + is filled with -1's (in which case a default of zero is used). */ + if ( !found ) { + start = !following ? i2 : i1; + end = !following ? -1 : naxes; + inc = !following ? -1 : 1; + for ( i = start; i != end; i += inc ) { + if ( axes[ i ] != -1 ) { + extra = axes[ i ] + ( !following ? 1 : 0 ); + break; + } + } + } + +/* Reset the loop parameters to scan just the region of interest in + the original (correct) direction. */ + start = following ? i2 : i1; + end = following ? i1 - 1 : i2 + 1; + inc = following ? -1 : 1; + +/* Identify those indices which are not valid. */ + for ( i = start; i != end; i += inc ) { + if ( axes[ i ] == -1 ) { + +/* We wish to assign the value "extra" in place of this invalid axis + index. However, this may duplicate an index already present, so + increment by one all valid indices which are not less than the new + index. This eliminates any possibility duplication, although it may + leave an axis index value unused (if no duplication would actually + have occurred). */ + for ( j = 0; j < naxes; j++ ) { + if ( axes[ j ] != -1 ) { + if ( axes[ j ] >= extra ) axes[ j ]++; + } + } + +/* We can now assign the new axis index. */ + axes[ i ] = extra; + +/* Assign the value to be used for the next extra axis index. If + scanning forward, this will be one more than the last one used (so + it will follow it). If scanning backwards, it is equal to the last + one (so that it will displace the last one upwards). */ + extra += ( following ? 0 : 1 ); + +/* When a valid axis index is encountered, reset the value to be used + for the next extra axis index. If scanning forward, this is one + more than the last valid index (so the extra axis will follow + it). If scanning backwards, it is equal to the last valid index (so + it will displace the valid index upwards). */ + } else { + extra = axes[ i ] + ( following ? 0 : 1 ); + } + } +} + +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 "cmpframe.h" +* double Angle( AstFrame *this_frame, const double a[], +* const double b[], const double c[], int *status ) + +* Class Membership: +* CmpFrame 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, in the context +* of a CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* a +* An array of double, with one element for each CmpFrame axis, +* containing the coordinates of the first point. +* b +* An array of double, with one element for each CmpFrame axis, +* containing the coordinates of the second point. +* c +* An array of double, with one element for each CmpFrame axis, +* containing the coordinates of the third point. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The required angle, or AST__BAD if the angle is undefined. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + AstFrame *pframe; /* Pointer to the primary Frame for an axis */ + const int *perm; /* Pointer to axis permutation array */ + double *pa; /* Permuted coordinates for point a */ + double *pb; /* Permuted coordinates for point b */ + double *pc; /* Permuted coordinates for point c */ + double ang1; /* Angle between input points in frame1 */ + double ang2; /* Angle between input points in frame2 */ + double result; /* Required angle */ + int axis; /* Loop counter for axes */ + int iscart; /* Is the CmpFrame a Cartesian system? */ + int naxes1; /* Number of axes in frame1 */ + int naxes; /* Total number of axes in CmpFrame */ + int paxis; /* Axis index within primary Frame */ + +/* Initialise. */ + result = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Obtain the number of axes in the CmpFrame. */ + naxes = astGetNaxes( this ); + +/* See if all axes within the CmpFrame belong to a simple Frame, in which + case we assume that the CmpFrame describes a Cartesian coordinate system. */ + iscart = 1; + for( axis = 0; axis < naxes; axis++ ){ + PrimaryFrame( this_frame, axis, &pframe, &paxis, status ); + if( strcmp( astGetClass( pframe ), "Frame" ) ) { + iscart = 0; + pframe = astAnnul( pframe ); + break; + } + pframe = astAnnul( pframe ); + } + +/* If the CmpFrame describes a Cartesian coordinate system, we can use the + Angle method from the parent Frame class. */ + if( iscart ) { + result = (*parent_angle)( this_frame, a, b, c, status ); + +/* If the CmpFrame is not Cartesian... */ + } else { + +/* Obtain a pointer to the CmpFrame's axis permutation array. */ + perm = astGetPerm( this ); + +/* Get workspace. */ + pa = (double *) astMalloc( sizeof(double)*naxes ); + pb = (double *) astMalloc( sizeof(double)*naxes ); + pc = (double *) astMalloc( sizeof(double)*naxes ); + +/* If OK, apply the axis permutation array to obtain the coordinates in the + required order. */ + if( astOK ) { + for( axis = 0; axis < naxes; axis++ ) { + pa[ perm[ axis ] ] = a[ axis ]; + pb[ perm[ axis ] ] = b[ axis ]; + pc[ perm[ axis ] ] = c[ axis ]; + } + +/* Obtain the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + +/* Project the two input points into the two component Frames and + determine the angle between the points in each Frame. */ + ang1 = astAngle( this->frame1, pa, pb, pc ); + ang2 = astAngle( this->frame2, pa + naxes1, pb + naxes1, + pc + naxes1 ); + +/* The required angle is defined if one and only one of the two component + frames gives a defined angle between the two points. */ + if( ang1 == AST__BAD ) { + result = ang2; + } else if( ang2 == AST__BAD ) { + result = ang1; + } + } + +/* Free the workspace */ + pa = (double *) astFree( (void *) pa ); + pb = (double *) astFree( (void *) pb ); + pc = (double *) astFree( (void *) pc ); + } + +/* Return the result. */ + 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 "cmpframe.h" +* AstObject *Cast( AstObject *this, AstObject *obj, int *status ) + +* Class Membership: +* CmpFrame 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; */ + AstAxis *newaxis; + AstFrame *cfrm; + AstFrame *this; + AstObject *new; + astDECLARE_GLOBALS + int generation_gap; + int i; + int naxes; + +/* 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 (CmpFrame). A positive value is returned if CmpFrame + is a sub-class of "obj". A negative value is returned if "obj" is + a sub-class of CmpFrame. Zero is returned if "obj" is a CmpFrame. + AST__COUSIN is returned if "obj" is not on the same line of descent + as CmpFrame. */ + generation_gap = astClassCompare( (AstObjectVtab *) &class_vtab, + astVTAB( obj ) ); + +/* If "obj" is a CmpFrame or a sub-class of CmpFrame, 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 CmpFrame or a sub-class of CmpFrame (e.g. it's a + Frame), we create a basic Frame containing the same axes and attributes + as the CmpFrame, and then attempt to cast this Frame into the class + indicated by "obj". */ + } else { + this = (AstFrame *) this_object; + +/* Create a basic Frame with the right number of axes. */ + naxes = astGetNaxes( this ); + cfrm = astFrame( naxes, " ", status ); + +/* Replace the Axis structures in the basic Frame with those in the + CmpFrame. */ + for( i = 0; i < naxes; i++ ) { + newaxis = astGetAxis( this, i ); + astSetAxis( cfrm, i, newaxis ); + newaxis = astAnnul( newaxis ); + } + +/* Overlay the properties of the CmpFrame onto the basic Frame. */ + astOverlay( this, NULL, cfrm ); + +/* Try to cast the basic Frame to the class of "obj". */ + new = astCast( cfrm, obj ); + +/* Annull the basic Frame. */ + cfrm = astAnnul( cfrm ); + } + +/* Return the new pointer. */ + return new; +} + +static double Centre( AstFrame *this_frame, int axis, double value, double gap, int *status ) { +/* +* Name: +* Centre + +* Purpose: +* Find a "nice" central value for tabulating CmpFrame axis values. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* double Centre( AstFrame *this_frame, int axis, double value, +* double gap, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the protected astCentre method +* inherited from the Frame class). + +* Description: +* This function returns an axis value which produces a nice formatted +* value suitable for a major tick mark on a plot axis, close to the +* supplied axis value. + +* Parameters: +* this +* Pointer to the Frame. +* axis +* The number of the axis (zero-based) for which a central value +* is to be found. +* value +* An arbitrary axis value in the section that is being plotted. +* gap +* The gap size. + +* Returned Value: +* The nice central axis value. + +* Notes: +* - A value of zero is returned if the supplied gap size is zero. +* - 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstFrame *frame; /* Pointer to Frame containing axis */ + double result; /* Result value to return */ + int naxes1; /* Number of axes in frame1 */ + int set1; /* Digits attribute set? */ + int set2; /* Format attribute set? */ + +/* Initialise. */ + result = 0.0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis = astValidateAxis( this, axis, 1, "astCentre" ); + +/* Determine the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + if ( astOK ) { + +/* Decide which component Frame contains the axis and adjust the axis + index if necessary. */ + frame = ( axis < naxes1 ) ? this->frame1 : this->frame2; + axis = ( axis < naxes1 ) ? axis : axis - naxes1; + +/* Since the component Frame is "managed" by the enclosing CmpFrame, + we next test if any Frame 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 + CmpFrame. Only the Digits and Format attributes are relevant here. */ + set1 = astTestDigits( frame ); + if ( !set1 ) astSetDigits( frame, astGetDigits( this ) ); + + set2 = astTestFormat( frame, axis ); + if ( !set2 ) astSetFormat( frame, axis, astGetFormat( this, axis ) ); + +/* Invoke the Frame's astCentre method to find the central value. */ + result = astCentre( frame, axis, value, gap ); + +/* Clear Frame attributes which were temporarily over-ridden. */ + if ( !set1 ) astClearDigits( frame ); + if ( !set2 ) astClearFormat( frame, axis ); + } + +/* If an error occurred, clear the returned value. */ + if ( !astOK ) result = 0.0; + +/* Return the result. */ + return result; +} + +static void ClearAlignSystem( AstFrame *this_frame, int *status ) { +/* +* Name: +* ClearAlignSystem + +* Purpose: +* Clear the value of the AlignSystem attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void ClearAlignSystem( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astClearAlignSystem method +* inherited from the Frame class). + +* Description: +* This function clears the AlignSystem value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to clear the CmpFrame AlignSystem value. */ + (*parent_clearalignsystem)( this_frame, status ); + +/* Now clear the AlignSystem attribute in the two component Frames. */ + astClearAlignSystem( this->frame1 ); + astClearAlignSystem( this->frame2 ); +} + +static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* ClearAttrib + +* Purpose: +* Clear an attribute value for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void ClearAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* CmpFrame 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 +* CmpFrame, so that the default value will subsequently be used. + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + AstFrame *pfrm; /* Pointer to primary Frame containing axis */ + char buf1[80]; /* For for un-indexed attribute name */ + char buf2[80]; /* For for indexed attribute name */ + int axis; /* Sipplied (1-based) axis index */ + int len; /* Length of attrib string */ + int nc; /* Number of characters used so dar */ + int oldrep; /* Original error reporting state */ + int paxis; /* Index of primary Frame axis */ + int ok; /* Has the attribute been accessed succesfully? */ + + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_object; + +/* Obtain the length of the "attrib" string. */ + len = strlen( attrib ); + +/* Indicate we have not yet acessed the attribute succesfully. */ + ok = 0; + +/* First check the supplied attribute name against each of the attribute + names defined by this class. In fact there is nothing to do here + since the CmpFrame class currently defines no extra attributes, but + this may change in the future. */ + if( 0 ) { + + + +/* If the attribute is not a CmpFrame specific attribute... */ + } else if( astOK ) { + +/* We want to allow easy access to the attributes of the component Frames. + That is, we do not want it to be necessary to extract a Frame from + its parent CmpFrame in order to access its attributes. For this reason + we first temporarily switch off error reporting so that if an attempt + to access the attribute fails, we can try a different approach. */ + oldrep = astReporting( 0 ); + +/* Our first attempt is to see if the attribute is recognised by the parent + class (Frame). */ + (*parent_clearattrib)( this_object, attrib, status ); + +/* Indicate success. */ + if( astOK ) { + ok = 1; + +/* Otherwise, clear the error condition so that we can try a different + approach. */ + } else { + astClearStatus; + +/* If the attribute is qualified by an axis index, try accessing it as an + attribute of the primary Frame containing the specified index. */ + if ( nc = 0, + ( 2 == astSscanf( attrib, "%[^(](%d)%n", buf1, &axis, &nc ) ) + && ( nc >= len ) ) { + +/* Find the primary Frame containing the specified axis. */ + astPrimaryFrame( this, axis - 1, &pfrm, &paxis ); + if( astOK ) { + +/* 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" ); + +/* Create a new attribute with the same name but with the axis index + appropriate to the primary Frame. */ + sprintf( buf2, "%s(%d)", buf1, paxis + 1 ); + +/* Attempt to access the attribute. */ + astClearAttrib( pfrm, buf2 ); + +/* Indicate success. */ + if( astOK ) { + ok = 1; + +/* Otherwise clear the status value, and try again without any axis index. */ + } else { + astClearStatus; + astClearAttrib( pfrm, buf1 ); + +/* Indicate success, or clear the status value. */ + if( astOK ) { + ok = 1; + } else { + astClearStatus; + } + } + +/* Free the primary frame pointer. */ + pfrm = astAnnul( pfrm ); + } + +/* If the attribute is not qualified by an axis index, try accessing it + using the primary Frame of each axis in turn. */ + } else { + +/* Loop round all axes attribute. */ + for( axis = 0; axis < astGetNaxes( this ); axis++ ) { + +/* Get the primary Frame containing this axis. */ + astPrimaryFrame( this, axis, &pfrm, &paxis ); + +/* Attempt to access the attribute as an attribute of the primary Frame. */ + astClearAttrib( pfrm, attrib ); + +/* Free the primary Frame pointer. */ + pfrm = astAnnul( pfrm ); + +/* Indicate success, or clear the status value. */ + if( astOK ) { + ok = 1; + } else { + astClearStatus; + } + } + } + } + +/* Re-instate the original error reporting state. */ + astReporting( oldrep ); + + } + +/* Report an error if the attribute could not be accessed. */ + if( !ok && astOK ) { + astError( AST__BADAT, "astClear: The %s given does not have an attribute " + "called \"%s\".", status, astGetClass( this ), attrib ); + } + +} + +static void ClearDtai( AstFrame *this_frame, int *status ) { +/* +* Name: +* ClearDtai + +* Purpose: +* Clear the value of the Dtai attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void ClearDtai( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astClearDtai method +* inherited from the Frame class). + +* Description: +* This function clears the Dtai value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to clear the CmpFrame Dtai value. */ + (*parent_cleardtai)( this_frame, status ); + +/* Now clear the Dtai attribute in the two component Frames. */ + astClearDtai( this->frame1 ); + astClearDtai( this->frame2 ); +} + +static void ClearDut1( AstFrame *this_frame, int *status ) { +/* +* Name: +* ClearDut1 + +* Purpose: +* Clear the value of the Dut1 attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void ClearDut1( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astClearDut1 method +* inherited from the Frame class). + +* Description: +* This function clears the Dut1 value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to clear the CmpFrame Dut1 value. */ + (*parent_cleardut1)( this_frame, status ); + +/* Now clear the Dut1 attribute in the two component Frames. */ + astClearDut1( this->frame1 ); + astClearDut1( this->frame2 ); +} + +static void ClearEpoch( AstFrame *this_frame, int *status ) { +/* +* Name: +* ClearEpoch + +* Purpose: +* Clear the value of the Epoch attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void ClearEpoch( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astClearEpoch method +* inherited from the Frame class). + +* Description: +* This function clears the Epoch value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to clear the CmpFrame epoch. */ + (*parent_clearepoch)( this_frame, status ); + +/* Now clear the Epoch attribute in the two component Frames. */ + astClearEpoch( this->frame1 ); + astClearEpoch( this->frame2 ); +} + +static void ClearObsAlt( AstFrame *this_frame, int *status ) { +/* +* Name: +* ClearObsAlt + +* Purpose: +* Clear the value of the ObsAlt attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void ClearObsAlt( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astClearObsAlt method +* inherited from the Frame class). + +* Description: +* This function clears the ObsAlt value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to clear the CmpFrame ObsAlt. */ + (*parent_clearobsalt)( this_frame, status ); + +/* Now clear the ObsAlt attribute in the two component Frames. */ + astClearObsAlt( this->frame1 ); + astClearObsAlt( this->frame2 ); +} + +static void ClearObsLat( AstFrame *this_frame, int *status ) { +/* +* Name: +* ClearObsLat + +* Purpose: +* Clear the value of the ObsLat attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void ClearObsLat( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astClearObsLat method +* inherited from the Frame class). + +* Description: +* This function clears the ObsLat value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to clear the CmpFrame ObsLat. */ + (*parent_clearobslat)( this_frame, status ); + +/* Now clear the ObsLat attribute in the two component Frames. */ + astClearObsLat( this->frame1 ); + astClearObsLat( this->frame2 ); +} + +static void ClearObsLon( AstFrame *this_frame, int *status ) { +/* +* Name: +* ClearObsLon + +* Purpose: +* Clear the value of the ObsLon attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void ClearObsLon( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astClearObsLon method +* inherited from the Frame class). + +* Description: +* This function clears the ObsLon value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to clear the CmpFrame ObsLon. */ + (*parent_clearobslon)( this_frame, status ); + +/* Now clear the ObsLon attribute in the two component Frames. */ + astClearObsLon( this->frame1 ); + astClearObsLon( this->frame2 ); +} + +static int ComponentMatch( AstCmpFrame *template, AstFrame *target, int matchsub, + int icomp, int **template_axes, int **target_axes, + AstMapping **map, AstFrame **result, int *status ) { +/* +* Name: +* ComponentMatch + +* Purpose: +* Determine if conversion is possible between a component Frame in a +* template CmpFrame and another target Frame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int ComponentMatch( AstCmpFrame *template, AstFrame *target, int matchsub, +* int icomp, int **template_axes, int **target_axes, +* AstMapping **map, AstFrame **result, int *status ) + +* Class Membership: +* CmpFrame member function + +* Description: +* This function is like astMatch, but it compares the supplied target +* Frame with a specified component Frame of the supplied template +* CmpFrame, rather than with the entire template CmpFrame. If a match +* is found, the returned Mapping, Frame and axis lists are adjusted so +* that they refer to the entire template CmpFrame. + +* Parameters: +* template +* Pointer to the template CmpFrame. 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. +* icomp +* The index of the component Frame to use within the template +* CmpFrame; 0 or 1. +* 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 CmpFrame 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 +* CmpFrame. 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" CmpFrame. However, +* if the PreserveAxes attribute of the template CmpFrame 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: */ + AstFrame *ctemplate; + AstFrame *fother; + AstFrame *fresult; + AstMapping *fmap; + AstPermMap *pm; + const int *perm; + int *ftarget_axes; + int *ftemplate_axes; + int *inperm; + int *operm; + int *outperm; + int axis; + int match; + int nax1; + int nax2; + int naxr; + int prax; + int praxo; + int result_naxes; + int template_naxes; + +/* 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; + +/* Get a pointer to the requested component Frame of the template CmpFrame. */ + ctemplate = icomp ? template->frame2 :template->frame1; + +/* Temporarily set the component Frame PreserveAxes value to that of the + template CmpFrame. PreserveAxes determines whether astMatch returns a + result Frame that looks like the template or the target. */ + if( astTestPreserveAxes( ctemplate ) ) { + praxo = astGetPreserveAxes( ctemplate ) ? 1 : 0; + } else { + praxo = -1; + } + prax = astGetPreserveAxes( template ); + astSetPreserveAxes( ctemplate, prax ); + +/* Attempt to find a match between the axes of the supplied target Frame + and the axes of the selected component Frame in the template. */ + match = astMatch( ctemplate, target, matchsub, &ftemplate_axes, &ftarget_axes, + &fmap, &fresult ); + +/* Restore the original PreserveAxes value in the component template + Frame. */ + if( praxo == -1 ) { + astClearPreserveAxes( ctemplate ); + } else { + astSetPreserveAxes( ctemplate, praxo ); + } + +/* If a match was found, we need to adjust the Mapping, Frame and axis + lists returned by the above call to astMatch so that they refer to the + full template CmpFrame or target (depending on PreserveAxes). */ + if( match ) { + +/* Get the number of axes in each component Frame and the total number of + axes in the template CmpFrame. */ + nax1 = astGetNaxes( template->frame1 ); + nax2 = astGetNaxes( template->frame2 ); + template_naxes = nax1 + nax2; + +/* Get the axis permutation array from the template and get its inverse. + The "perm" array holds the internal axis index at each external axis + index. The "operm" array holds the external axis index at each + internal axis index. */ + perm = astGetPerm( template ); + operm = astMalloc( sizeof( int )*(size_t)template_naxes ); + if( astOK) { + for( axis = 0; axis < template_naxes; axis++ ) { + operm[ perm[ axis ] ] = axis; + } + +/* The PreserveAxes attribute is used by astMatch to decide whether the + result Frame should inherit its axes from the target frame or the + template frame. First deal with cases where the order and count of axes + in the result frame is the same as the target. */ + if( prax ) { + +/* Return the result Frame and Mapping unchanged since they already refer + to the full target Frame used in the above call to astMatch. */ + *result = astClone( fresult ); + *map = astClone( fmap ); + +/* Also return the lists of target axes unchanged. */ + *target_axes = ftarget_axes; + +/* The values in the template axes list refer to the component template + Frame, but we want to return values that refer to the full template + CmpFrame. This involve sup to two setps 1) for the second component + Frame only, increase the axis numbers by the number of axes in the + first component Frame, and 2) take account of any axis permutation in + the template. First allocate memory for the returned list (which, + because PreserveAxes is zero, will have an entry for each template axis). */ + *template_axes = astMalloc( sizeof( int )*template_naxes ); + +/* Now, if the second component of the template has been selected, increment + the template axes so that they give the internal axis indices of the + second component Frame within the CmpFrame. The first component axes + will be unchanged. */ + result_naxes = astGetNaxes( fresult ); + if( icomp ) { + for( axis = 0; axis < result_naxes; axis++ ) { + ftemplate_axes[ axis ] += nax1; + } + } + +/* Now copy the internal axis value into the returned array, modifying them + in the process from internal to external axis ordering. */ + for( axis = 0; axis < result_naxes; axis++ ) { + (*template_axes)[ axis ] = operm[ ftemplate_axes[ axis ] ]; + } + +/* If the order and count of axes in the result frame is the same as the + template CmpFrame... */ + } else { + +/* We need to adjust the Mapping, Frame and axis lists returned by the + above call to astMatch so that they refer to the supplied template + CmpFrame rather than to the selected component Frame. Get the number + of axes in the result Frame returned by astMatch (naxr) and the number + in the result Frame returned by this function (result-naxes). */ + naxr = astGetNaxes( fresult ); + result_naxes = ( icomp ? nax1 : nax2 ) + naxr; + +/* Create the full result Frame by combining the partial result Frame + returned by astMatch above with the other component Frame from the + template. */ + if( icomp ) { + fother = astCopy( template->frame1 ); + *result = (AstFrame *) astCmpFrame( fother, fresult, "", status ); + } else { + fother = astCopy( template->frame2 ); + *result = (AstFrame *) astCmpFrame( fresult, fother, "", status ); + } + fother = astAnnul( fother ); + +/* Modify the Mapping returned by the above call to astMatch so that it + produces positions within the full result Frame created above. */ + if( icomp ) { + inperm = astMalloc( sizeof( int )*(size_t) naxr ); + outperm = astMalloc( sizeof( int )*(size_t) result_naxes ); + if( astOK ) { + for( axis = 0; axis < nax1; axis++ ) outperm[ axis ] = -1; + for( axis = 0; axis < naxr; axis++ ) { + outperm[ axis + nax1 ] = axis; + inperm[ axis ] = axis + nax1; + } + } + + } else { + inperm = NULL; + outperm = NULL; + } + + pm = astPermMap( naxr, inperm, result_naxes, outperm, NULL, "", status ); + *map = (AstMapping *) astCmpMap( fmap, pm, 1, "", status ); + +/* Free resources. */ + pm = astAnnul( pm ); + if( inperm ) inperm = astFree( inperm ); + if( outperm ) outperm = astFree( outperm ); + +/* Allocate memory for the returned list of axes. */ + *template_axes = astMalloc( sizeof( int )*(size_t)result_naxes ); + *target_axes = astMalloc( sizeof( int )*(size_t)result_naxes ); + +/* The axis indices returned by astMatch above will refer to the selected + component Frame rather than the permuted (i.e. external) axis indices for + the template CmpFrame. Change the template axes list so that they describe + the axes in the full result Frame in terms of the external template axis + numbering. This involves shifting the indices for the second component + Frame to leave room for the axes of the first component Frame, and + also permuting the axis indices from internal to external order. */ + if( icomp ) { + for( axis = 0; axis < nax1; axis++ ) { + (*template_axes)[ axis ] = operm[ axis ]; + } + + for( ; axis < result_naxes; axis++ ) { + (*template_axes)[ axis ] = operm[ nax1 + ftemplate_axes[ axis - nax1 ] ]; + } + + } else { + for( axis = 0; axis < nax1; axis++ ) { + (*template_axes)[ axis ] = operm[ ftemplate_axes[ axis ] ]; + } + + for( ; axis < result_naxes; axis++ ) { + (*template_axes)[ axis ] = operm[ axis ]; + } + } + +/* Change the target axes list so that they describe the axes in the + full result Frame (this just means padding with -1 to indicate that + the extra axes do not correspond to any axis in the target). */ + for( axis = 0; axis < naxr; axis++ ) { + (*target_axes)[ axis ] = ftarget_axes[ axis ]; + } + + for( ; axis < result_naxes; axis++ ) { + (*target_axes)[ axis ] = -1; + } + +/* Free resources */ + ftarget_axes = astFree( ftarget_axes ); + } + } + + operm = astFree( operm ); + ftemplate_axes = astFree( ftemplate_axes ); + fmap = astAnnul( fmap ); + fresult = astAnnul( fresult ); + + } + +/* If an error occurred, free all allocated memory, annul the result + Object pointers and clear all returned values. */ + if ( !astOK ) { + *template_axes = astFree( *template_axes ); + *target_axes = astFree( *target_axes ); + *map = astAnnul( *map ); + *result = astAnnul( *result ); + match = 0; + } + +/* Return the result. */ + return match; +} + +static void Decompose( AstMapping *this_cmpframe, AstMapping **map1, + AstMapping **map2, int *series, int *invert1, + int *invert2, int *status ) { +/* +* +* Name: +* Decompose + +* Purpose: +* Decompose a CmpFrame into two component CmpFrames. + +* Type: +* Private function. + +* Synopsis: +* #include "mapping.h" +* void Decompose( AstMapping *this, AstMapping **map1, +* AstMapping **map2, int *series, +* int *invert1, int *invert2, int *status ) + +* Class Membership: +* CmpFrame 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 or CmpFrames. + +* 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: */ + AstCmpFrame *this; /* Pointer to CmpMap structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpMap structure. */ + this = (AstCmpFrame *) this_cmpframe; + +/* The components Frames of a CmpFrame are considered to be parallel + Mappings. */ + if( series ) *series = 0; + +/* The Frames are returned in their original order whether or not the + CmpFrame has been inverted. */ + if( map1 ) *map1 = astClone( this->frame1 ); + if( map2 ) *map2 = astClone( this->frame2 ); + +/* If the CmpFrame has been inverted, return inverted Invert flags. */ + if( astGetInvert( this ) ) { + if( invert1 ) *invert1 = astGetInvert( this->frame1 ) ? 0 : 1; + if( invert2 ) *invert2 = astGetInvert( this->frame2 ) ? 0 : 1; + +/* If the CmpFrame has not been inverted, return the current Invert flags. */ + } else { + if( invert1 ) *invert1 = astGetInvert( this->frame1 ); + if( invert2 ) *invert2 = astGetInvert( this->frame2 ); + } +} + +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 "cmpframe.h" +* double Distance( AstFrame *this, +* const double point1[], const double point2[], int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astDistance method +* inherited from the Frame class). + +* Description: +* This function finds the distance between two points whose +* CmpFrame coordinates are given. The distance calculated is that +* along the geodesic curve that joins the two points. This is +* computed as the Cartesian sum of the distances between the +* points when their coordinates are projected into each of the +* CmpFrame's component Frames. + +* Parameters: +* this +* Pointer to the CmpFrame. +* point1 +* An array of double, with one element for each CmpFrame axis, +* containing the coordinates of the first point. +* point2 +* An array of double, with one element for each CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + const int *perm; /* Axis permutation array */ + double *p1; /* Pointer to permuted point1 coordinates */ + double *p2; /* Pointer to permuted point2 coordinates */ + double dist1; /* Distance in frame1 */ + double dist2; /* Distance in frame2 */ + double result; /* Value to return */ + int axis; /* Loop counter for axes */ + int naxes1; /* Number of axes in frame1 */ + int naxes; /* Number of axes in CmpFrame */ + int ok; /* No "bad" coordinates found? */ + +/* Initialise. */ + result = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Obtain a pointer to the CmpFrame's axis permutation array. */ + perm = astGetPerm( this ); + +/* Obtain the number of axes in the CmpFrame and in the first + component Frame. */ + naxes = astGetNaxes( this ); + naxes1 = astGetNaxes( this->frame1 ); + +/* Allocate memory to hold the permuted coordinates of each point. */ + p1 = astMalloc( sizeof( double ) * (size_t) naxes ); + p2 = astMalloc( sizeof( double ) * (size_t) naxes ); + if ( astOK ) { + +/* Examine the coordinates of both points and note if any coordinate + value is "bad". */ + ok = 1; + for ( axis = 0; axis < naxes; axis++ ) { + if ( ( point1[ axis ] == AST__BAD ) || + ( point2[ axis ] == AST__BAD ) ) { + ok = 0; + break; + +/* Permute good coordinates using the CmpFrame's axis permutation + array to put them into the order required internally (i.e. by the + two component Frames). */ + } else { + p1[ perm[ axis ] ] = point1[ axis ]; + p2[ perm[ axis ] ] = point2[ axis ]; + } + } + +/* If no "bad" coordinates were found, obtain the distance between the + two points when their coordinates are projected into each component + Frame. */ + if ( ok ) { + dist1 = astDistance( this->frame1, p1, p2 ); + dist2 = astDistance( this->frame2, p1 + naxes1, p2 + naxes1 ); + +/* If the distances found were OK, compute the distance between the + two points as the Cartesian sum of the two component distances. */ + if ( astOK && ( dist1 != AST__BAD ) && ( dist2 != AST__BAD ) ) { + result = sqrt( ( dist1 * dist1 ) + ( dist2 * dist2 ) ); + } + } + } + +/* Free the memory used for the permuted coordinates. */ + p1 = astFree( p1 ); + p2 = astFree( p2 ); + +/* If an error occurred, clear the result value. */ + if ( !astOK ) result = AST__BAD; + +/* Return the result. */ + return result; +} + +static int Fields( AstFrame *this_frame, 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 CmpFrame axis value. + +* Type: +* Protected virtual function. + +* Synopsis: +* #include "cmpframe.h" +* int astFields( AstFrame *this, int axis, const char *fmt, +* const char *str, int maxfld, char **fields, +* int *nc, double *val ) + +* Class Membership: +* CmpFrame member function (over-rides the protected astFields +* method inherited from the Frame class). + +* Description: +* This function identifies the numerical fields within a CmpFrame 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 CmpFrame. +* axis +* The number of the CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstFrame *frame; /* Pointer to Frame containing axis */ + int naxes1; /* Number of axes in frame1 */ + int result; /* Result field count to return */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis = astValidateAxis( this, axis, 1, "astFields" ); + +/* Determine the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + if ( astOK ) { + +/* Decide which component Frame contains the axis and adjust the axis + index if necessary. */ + frame = ( axis < naxes1 ) ? this->frame1 : this->frame2; + axis = ( axis < naxes1 ) ? axis : axis - naxes1; + +/* Invoke the Frame's astFields method to perform the processing. */ + result = astFields( frame, axis, fmt, str, maxfld, fields, + nc, val ); + } + +/* If an error occurred, clear the returned value. */ + if ( !astOK ) result = 0; + +/* 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 CmpFrame axis. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* const char *Format( AstFrame *this, int axis, double value, int *status ) + +* Class Membership: +* CmpFrame 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 +* CmpFrame axis. The formatting applied is that specified by a +* previous invocation of the astSetFormat method (or a default +* format appropriate to the axis in question). + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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: +* - 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstFrame *frame; /* Pointer to Frame containing axis */ + const char *result; /* Pointer value to return */ + int naxes1; /* Number of axes in frame1 */ + int set; /* Digits attribute set? */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis = astValidateAxis( this, axis, 1, "astFormat" ); + +/* Determine the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + if ( astOK ) { + +/* Decide which component Frame contains the axis and adjust the axis + index if necessary. */ + frame = ( axis < naxes1 ) ? this->frame1 : this->frame2; + axis = ( axis < naxes1 ) ? axis : axis - naxes1; + +/* Since the component Frame is "managed" by the enclosing CmpFrame, + we next test if any Frame 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 + CmpFrame. Only the Digits attribute is relevant here. */ + set = astTestDigits( frame ); + if ( !set ) astSetDigits( frame, astGetDigits( this ) ); + +/* Invoke the Frame's astFormat method to format the value. */ + result = astFormat( frame, axis, value ); + +/* Clear Frame attributes which were temporarily over-ridden. */ + if ( !set ) astClearDigits( frame ); + } + +/* If an error occurred, clear the result 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 "cmpframe.h" +* AstPointSet *FrameGrid( AstFrame *this_frame, int size, +* const double *lbnd, const double *ubnd, +* int *status ) + +* Class Membership: +* CmpFrame 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: */ + AstCmpFrame *this; + AstPointSet *ps1; + AstPointSet *ps2; + AstPointSet *result; + const int *perm; + double **ptr1; + double **ptr2; + double **ptr; + double *lbnd1; + double *lbnd2; + double *p; + double *ubnd1; + double *ubnd2; + double v; + int axis; + int iax1; + int iax2; + int iaxis; + int ip1; + int ip2; + int nax1; + int nax2; + int naxes; + int npoint1; + int npoint2; + int npoint; + int size1; + int size2; + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_object; + +/* Get the number of axes in each component Frame, and the total number + of axes. */ + nax1 = astGetNaxes( this->frame1 ); + nax2 = astGetNaxes( this->frame2 ); + naxes = nax1 + nax2; + +/* Allocate memory to hold bounds for each component Frame */ + lbnd1 = astMalloc( nax1*sizeof( double ) ); + ubnd1 = astMalloc( nax1*sizeof( double ) ); + lbnd2 = astMalloc( nax2*sizeof( double ) ); + ubnd2 = astMalloc( nax2*sizeof( double ) ); + +/* Obtain a pointer to the CmpFrame's axis permutation array. This array + holds the original axis index for each current Frame axis index. */ + perm = astGetPerm( this ); + +/* Check pointers can be used safely, and check the supplied size value + is good. */ + if( astOK && size > 0 ) { + +/* Copy the supplied bounds into the work arrays, permuting them in the + process so that they use the internal axis numbering of the two + component Frames. */ + for( axis = 0; axis < naxes; axis++ ) { + iaxis = perm[ axis ]; + if( iaxis < nax1 ) { + lbnd1[ iaxis ] = lbnd[ axis ]; + ubnd1[ iaxis ] = ubnd[ axis ]; + } else { + iaxis -= nax1; + lbnd2[ iaxis ] = lbnd[ axis ]; + ubnd2[ iaxis ] = ubnd[ axis ]; + } + } + +/* Get the target number of points to be used in the grid that covers the + first Frame. */ + size1 = (int)( pow( size, (double)nax1/(double)naxes ) + 0.5 ); + +/* Get the target number of points to be used in the grid that covers the + second Frame. */ + size2 = (int)( (double)size/(double)size1 + 0.5 ); + +/* Get the grids covering the two component Frames, and get the actual sizes + of the resulting PointSets. */ + ps1 = astFrameGrid( this->frame1, size1, lbnd1, ubnd1 ); + ptr1 = astGetPoints( ps1 ); + npoint1 = astGetNpoint( ps1 ); + + ps2 = astFrameGrid( this->frame2, size2, lbnd2, ubnd2 ); + ptr2 = astGetPoints( ps2 ); + npoint2 = astGetNpoint( ps2 ); + +/* Get the number of points in the returned FrameSet, and then create a + PointSet large enough to hold them. */ + npoint = npoint1*npoint2; + result = astPointSet( npoint, naxes, " ", status ); + ptr = astGetPoints( result ); + if( astOK ) { + +/* For every point in the first Frame's PointSet, duplicate the second + Frame's entire PointSet, using the first Frame's axis values. */ + for( ip1 = 0; ip1 < npoint1; ip1++ ) { + for( iax1 = 0; iax1 < nax1; iax1++ ) { + p = ptr[ iax1 ]; + v = ptr1[ iax1 ][ ip1 ]; + for( ip2 = 0; ip2 < npoint2; ip2++ ) { + *(p++) = v; + } + ptr[ iax1 ] = p; + } + for( iax2 = 0; iax2 < nax2; iax2++ ) { + memcpy( ptr[ iax2 + nax1 ], ptr2[ iax2 ], npoint2*sizeof( double ) ); + ptr[ iax2 + nax1 ] += npoint2*sizeof( double ); + } + } + +/* Permute the returned PointSet so that it uses external axis numbering. */ + astPermPoints( result, 1, perm ); + } + +/* Free resources. */ + ps1 = astAnnul( ps1 ); + ps2 = astAnnul( ps2 ); + +/* Report error if supplied values were bad. */ + } else if( astOK ) { + astError( AST__ATTIN, "astFrameGrid(%s): The supplied grid " + "size (%d) is invalid (programming error).", + status, astGetClass( this ), size ); + } + +/* Free resources. */ + lbnd1 = astFree( lbnd1 ); + ubnd1 = astFree( ubnd1 ); + lbnd2 = astFree( lbnd2 ); + ubnd2 = astFree( ubnd2 ); + +/* 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 CmpFrame axis values. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status ) + +* Class Membership: +* CmpFrame 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 CmpFrame 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 CmpFrame. +* 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstFrame *frame; /* Pointer to Frame containing axis */ + double result; /* Result value to return */ + int naxes1; /* Number of axes in frame1 */ + int set; /* Digits attribute set? */ + +/* Initialise. */ + result = 0.0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis = astValidateAxis( this, axis, 1, "astGap" ); + +/* Determine the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + if ( astOK ) { + +/* Decide which component Frame contains the axis and adjust the axis + index if necessary. */ + frame = ( axis < naxes1 ) ? this->frame1 : this->frame2; + axis = ( axis < naxes1 ) ? axis : axis - naxes1; + +/* Since the component Frame is "managed" by the enclosing CmpFrame, + we next test if any Frame 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 + CmpFrame. Only the Digits attribute is relevant here. */ + set = astTestDigits( frame ); + if ( !set ) astSetDigits( frame, astGetDigits( this ) ); + +/* Invoke the Frame's astGap method to find the gap size. */ + result = astGap( frame, axis, gap, ntick ); + +/* Clear Frame attributes which were temporarily over-ridden. */ + if ( !set ) astClearDigits( frame ); + } + +/* 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 "cmpframe.h" +* int GetObjSize( AstObject *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetObjSize protected +* method inherited from the parent class). + +* Description: +* This function returns the in-memory size of the supplied CmpFrame, +* in bytes. + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + int result; /* Result value to return */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointers to the CmpFrame structure. */ + this = (AstCmpFrame *) 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->frame1 ); + result += astGetObjSize( this->frame2 ); + result += astTSizeOf( this->perm ); + +/* If an error occurred, clear the result value. */ + if ( !astOK ) result = 0; + +/* Return the result, */ + return result; +} + +static AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetAlignSystem + +* Purpose: +* Obtain the AlignSystem attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetAlignSystem protected +* method inherited from the Frame class). + +* Description: +* This function returns the AlignSystem attribute for a CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The AlignSystem value. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstSystemType result; /* Value to return */ + +/* Initialise. */ + result = AST__BADSYSTEM; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) 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__COMP; + } + +/* 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 CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "CmpFrame.h" +* const char *GetAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* CmpFrame 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 CmpFrame, formatted as a character string. + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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 CmpFrame, 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 CmpFrame. 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + AstFrame *pfrm; /* Pointer to primary Frame containing axis */ + char buf1[80]; /* For for un-indexed attribute name */ + char buf2[80]; /* For for indexed attribute name */ + const char *result; /* Pointer value to return */ + int axis; /* Supplied (1-base) axis index */ + int len; /* Length of attrib string */ + int nc; /* Length of string used so far */ + int ok; /* Has the attribute been accessed succesfully? */ + int oldrep; /* Original error reporting state */ + int paxis; /* Index of primary Frame axis */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_object; + +/* Obtain the length of the attrib string. */ + len = strlen( attrib ); + +/* Indicate we have not yet acessed the attribute succesfully. */ + ok = 0; + +/* First check the supplied attribute name against each of the attribute + names defined by this class. In fact there is nothing to do here + since the CmpFrame class currently defines no extra attributes, but + this may change in the future. */ + if( 0 ) { + +/* If the attribute is not a CmpFrame specific attribute... */ + } else if( astOK ) { + +/* We want to allow easy access to the attributes of the component Frames. + That is, we do not want it to be necessary to extract a Frame from + its parent CmpFrame in order to access its attributes. For this reason + we first temporarily switch off error reporting so that if an attempt + to access the attribute fails, we can try a different approach. */ + oldrep = astReporting( 0 ); + +/* If the attribute is qualified by an axis index, try accessing it as an + attribute of the primary Frame containing the specified index. */ + if ( nc = 0, + ( 2 == astSscanf( attrib, "%[^(](%d)%n", buf1, &axis, &nc ) ) + && ( nc >= len ) ) { + +/* Find the primary Frame containing the specified axis. */ + astPrimaryFrame( this, axis - 1, &pfrm, &paxis ); + if( astOK ) { + +/* 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" ); + +/* Create a new attribute with the same name but with the axis index + appropriate to the primary Frame. */ + sprintf( buf2, "%s(%d)", buf1, paxis + 1 ); + +/* Attempt to access the attribute. */ + result = astGetAttrib( pfrm, buf2 ); + +/* Indicate success. */ + if( astOK ) { + ok = 1; + +/* Otherwise clear the status value, and try again without any axis index. */ + } else { + astClearStatus; + result = astGetAttrib( pfrm, buf1 ); + +/* Indicate success, or clear the status value. */ + if( astOK ) { + ok = 1; + } else { + astClearStatus; + } + } + +/* Free the primary frame pointer. */ + pfrm = astAnnul( pfrm ); + } + +/* If the attribute is not qualified by an axis index, try accessing it + using the parent Frame method. */ + } else if( astOK ){ + result = (*parent_getattrib)( this_object, attrib, status ); + +/* Indicate success. */ + if( astOK ) { + ok = 1; + +/* Otherwise, clear the error condition so that we can try a different + approach. */ + } else { + astClearStatus; + +/* Next try accessing it using the primary Frame of each axis in turn. + Loop round all axes, until one is found which defines the specified + attribute. */ + for( axis = 0; axis < astGetNaxes( this ) && !ok; axis++ ) { + +/* Get the primary Frame containing this axis. */ + astPrimaryFrame( this, axis, &pfrm, &paxis ); + +/* Attempt to access the attribute as an attribute of the primary Frame. */ + result = astGetAttrib( pfrm, attrib ); + +/* Indicate success, or clear the status value. */ + if( astOK ) { + ok = 1; + } else { + astClearStatus; + } + +/* Free the primary Frame pointer. */ + pfrm = astAnnul( pfrm ); + + } + } + } + +/* Re-instate the original error reporting state. */ + astReporting( oldrep ); + + } + +/* Report an error if the attribute could not be accessed. */ + if( !ok && astOK ) { + astError( AST__BADAT, "astGet: The %s given does not have an attribute " + "called \"%s\".", status, astGetClass( this ), attrib ); + } + +/* Return the result. */ + return result; + +} + +static int GenAxisSelection( int naxes, int nselect, int axes[], int *status ) { +/* +* Name: +* GenAxisSelection + +* Purpose: +* Generate a sequence of axis selections. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int GenAxisSelection( int naxes, int nselect, int axes[], int *status ) + +* Class Membership: +* CmpFrame member function. + +* Description: +* This function generates a sequence of axis selections covering +* all possible ways of selecting a specified number of axes from a +* Frame. + +* Parameters: +* naxes +* The number of axes in the Frame. +* nselect +* The number of axes to be selected (between zero and "naxes"). +* axes +* An array with "nselect" elements. On entry it should contain +* the (zero-based) indices of the initial set of distinct axes +* to be selected, in increasing order (initiallly this should +* just be the sequence [0,1,...nselect-1]). On exit, these +* indices will be updated to identify the next possible axis +* selection. +* +* By invoking the function repeatedly, and passing this array +* each time, all possible selections will be covered. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* One if a new axis selection has been returned. Zero if all +* possible selections have already been returned (in which case +* the selection returned this time is not valid and should not 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: */ + int i; /* Loop counter for axes */ + int iselect; /* Selection index */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Start with the first axis index and loop until the selection has + been updated. */ + iselect = 0; + while ( 1 ) { + +/* Increment the current axis index if it is the final one or it can + be incremented without equalling the one which follows (this ensures + the indices remain in increasing order). */ + if ( ( iselect == ( nselect - 1 ) ) || + ( axes[ iselect + 1 ] > ( axes[ iselect ] + 1 ) ) ) { + axes[ iselect ]++; + +/* After incrementing an index, reset all previous indices to their + starting values. */ + for ( i = 0; i < iselect; i++ ) axes[ i ] = i; + break; + +/* If this axis index can't be incremented, consider the next one. + Quit if we go beyond the end of the selection array. */ + } else if ( ++iselect >= nselect ) { + break; + } + } + +/* Return a result to indicate if we've reached the final selection + (when the final axis index goes out of range). */ + return ( nselect > 0 ) && ( axes[ nselect - 1 ] < naxes ); +} + +static AstAxis *GetAxis( AstFrame *this_frame, int axis, int *status ) { +/* +* Name: +* GetAxis + +* Purpose: +* Obtain a pointer to a specified Axis from a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* AstAxis *GetAxis( AstFrame *this, int axis, int *status ) + +* Class Membership: +* CmpFrame 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 a CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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 Vaiables: */ + AstAxis *result; /* Pointer value to return */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + int naxes1; /* Number of axes for frame1 */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis = astValidateAxis( this, axis, 1, "astGetAxis" ); + +/* Obtain the number of axes for frame1. */ + naxes1 = astGetNaxes( this->frame1 ); + +/* Decide which Frame the axis belongs to and obtain the required + Axis pointer. */ + if ( axis < naxes1 ) { + result = astGetAxis( this->frame1, axis ); + } else { + result = astGetAxis( this->frame2, axis - naxes1 ); + } + +/* 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 CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* const char *GetDomain( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame 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 CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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 CmpFrame. +* - 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 */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + char *dom1; /* Pointer to first sub domain */ + char *dom2; /* Pointer to second sub domain */ + const char *result; /* Pointer value to return */ + const char *t; /* Temporary pointer */ + +/* 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_frame); + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) 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 { + +/* Get the Domain value for the two component Frames and store new + copies of them. This is necessary because the component Frames may + themselves be CmpFrames, resulting in this function being called + recursively and so causing the static "getdomain_buff" array to be used in + multiple contexts. */ + t = astGetDomain( this->frame1 ); + dom1 = t ? astStore( NULL, t, strlen(t) + 1 ) : NULL; + t = astGetDomain( this->frame2 ); + dom2 = t ? astStore( NULL, t, strlen(t) + 1 ) : NULL; + + if( dom2 ) { + if( strlen( dom1 ) > 0 || strlen( dom2 ) > 0 ) { + sprintf( (char *) getdomain_buff, "%s-%s", dom1, dom2 ); + result = getdomain_buff; + } else { + result = "CMP"; + } + } + + dom1 = astFree( dom1 ); + dom2 = astFree( dom2 ); + } + +/* Return the result. */ + return result; +} + +static int GetMaxAxes( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetMaxAxes + +* Purpose: +* Get a value for the MaxAxes attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int GetMaxAxes( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetMaxAxes method +* inherited from the Frame class). + +* Description: +* This function returns a value for the MaxAxes attribute of a +* CmpFrame. A large default value is supplied that is much larger +* than the maximum likely number of axes in a Frame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The MaxAxes 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + int result; /* Result value to return */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If a value has been set explicitly for the CmpFrame, return it. + Otherwise returned a large default value. */ + if( astTestMaxAxes( this ) ) { + result = (*parent_getmaxaxes)( this_frame, status ); + } else { + result = 1000000; + } + +/* Return the result. */ + return result; +} + +static int GetMinAxes( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetMinAxes + +* Purpose: +* Get a value for the MinAxes attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int GetMinAxes( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetMinAxes method +* inherited from the Frame class). + +* Description: +* This function returns a value for the MinAxes attribute of a +* CmpFrame. A default value of zero is used. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The MinAxes 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + int result; /* Result value to return */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If a value has been set explicitly for the CmpFrame, return it. + Otherwise returned a default value of zero. */ + if( astTestMinAxes( this ) ) { + result = (*parent_getminaxes)( this_frame, status ); + } else { + result = 0; + } + +/* Return the result. */ + return result; +} + +static double GetDtai( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetDtai + +* Purpose: +* Get a value for the Dtai attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* double GetDtai( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetDtai method +* inherited from the Frame class). + +* Description: +* This function returns a value for the Dtai attribute of a +* CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Dtai attribute value. + +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + double result; /* Result value to return */ + +/* Initialise. */ + result = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If an Dtai attribute value has been set, invoke the parent method + to obtain it. */ + if ( astTestDtai( this ) ) { + result = (*parent_getdtai)( this_frame, status ); + +/* Otherwise, if the Dtai value is set in the first component Frame, + return it. */ + } else if( astTestDtai( this->frame1 ) ){ + result = astGetDtai( this->frame1 ); + +/* Otherwise, if the Dtai value is set in the second component Frame, + return it. */ + } else if( astTestDtai( this->frame2 ) ){ + result = astGetDtai( this->frame2 ); + +/* Otherwise, return the default Dtai value from the first component + Frame. */ + } else { + result = astGetDtai( this->frame1 ); + } + +/* Return the result. */ + return result; +} + +static double GetDut1( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetDut1 + +* Purpose: +* Get a value for the Dut1 attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* double GetDut1( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetDut1 method +* inherited from the Frame class). + +* Description: +* This function returns a value for the Dut1 attribute of a +* CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Dut1 attribute value. + +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + double result; /* Result value to return */ + +/* Initialise. */ + result = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If an Dut1 attribute value has been set, invoke the parent method + to obtain it. */ + if ( astTestDut1( this ) ) { + result = (*parent_getdut1)( this_frame, status ); + +/* Otherwise, if the Dut1 value is set in the first component Frame, + return it. */ + } else if( astTestDut1( this->frame1 ) ){ + result = astGetDut1( this->frame1 ); + +/* Otherwise, if the Dut1 value is set in the second component Frame, + return it. */ + } else if( astTestDut1( this->frame2 ) ){ + result = astGetDut1( this->frame2 ); + +/* Otherwise, return the default Dut1 value from the first component + Frame. */ + } else { + result = astGetDut1( this->frame1 ); + } + +/* Return the result. */ + return result; +} + +static double GetEpoch( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetEpoch + +* Purpose: +* Get a value for the Epoch attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* double GetEpoch( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetEpoch method +* inherited from the Frame class). + +* Description: +* This function returns a value for the Epoch attribute of a +* CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Epoch attribute value. + +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + double result; /* Result value to return */ + +/* Initialise. */ + result = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If an Epoch attribute value has been set, invoke the parent method + to obtain it. */ + if ( astTestEpoch( this ) ) { + result = (*parent_getepoch)( this_frame, status ); + +/* Otherwise, if the Epoch value is set in the first component Frame, + return it. */ + } else if( astTestEpoch( this->frame1 ) ){ + result = astGetEpoch( this->frame1 ); + +/* Otherwise, if the Epoch value is set in the second component Frame, + return it. */ + } else if( astTestEpoch( this->frame2 ) ){ + result = astGetEpoch( this->frame2 ); + +/* Otherwise, return the default Epoch value from the first component + Frame. */ + } else { + result = astGetEpoch( this->frame1 ); + } + +/* Return the result. */ + return result; +} + +static double GetObsAlt( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetObsAlt + +* Purpose: +* Get a value for the ObsAlt attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* double GetObsAlt( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetObsAlt method +* inherited from the Frame class). + +* Description: +* This function returns a value for the ObsAlt attribute of a +* CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The ObsAlt attribute value. + +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + double result; /* Result value to return */ + +/* Initialise. */ + result = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If an ObsAlt attribute value has been set, invoke the parent method + to obtain it. */ + if ( astTestObsAlt( this ) ) { + result = (*parent_getobsalt)( this_frame, status ); + +/* Otherwise, if the ObsAlt value is set in the first component Frame, + return it. */ + } else if( astTestObsAlt( this->frame1 ) ){ + result = astGetObsAlt( this->frame1 ); + +/* Otherwise, if the ObsAlt value is set in the second component Frame, + return it. */ + } else if( astTestObsAlt( this->frame2 ) ){ + result = astGetObsAlt( this->frame2 ); + +/* Otherwise, return the default ObsAlt value from the first component + Frame. */ + } else { + result = astGetObsAlt( this->frame1 ); + } + +/* Return the result. */ + return result; +} + +static double GetObsLat( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetObsLat + +* Purpose: +* Get a value for the ObsLat attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* double GetObsLat( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetObsLat method +* inherited from the Frame class). + +* Description: +* This function returns a value for the ObsLat attribute of a +* CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The ObsLat attribute value. + +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + double result; /* Result value to return */ + +/* Initialise. */ + result = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If an ObsLat attribute value has been set, invoke the parent method + to obtain it. */ + if ( astTestObsLat( this ) ) { + result = (*parent_getobslat)( this_frame, status ); + +/* Otherwise, if the ObsLat value is set in the first component Frame, + return it. */ + } else if( astTestObsLat( this->frame1 ) ){ + result = astGetObsLat( this->frame1 ); + +/* Otherwise, if the ObsLat value is set in the second component Frame, + return it. */ + } else if( astTestObsLat( this->frame2 ) ){ + result = astGetObsLat( this->frame2 ); + +/* Otherwise, return the default ObsLat value from the first component + Frame. */ + } else { + result = astGetObsLat( this->frame1 ); + } + +/* Return the result. */ + return result; +} + +static double GetObsLon( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetObsLon + +* Purpose: +* Get a value for the ObsLon attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* double GetObsLon( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetObsLon method +* inherited from the Frame class). + +* Description: +* This function returns a value for the ObsLon attribute of a +* CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The ObsLon attribute value. + +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + double result; /* Result value to return */ + +/* Initialise. */ + result = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If an ObsLon attribute value has been set, invoke the parent method + to obtain it. */ + if ( astTestObsLon( this ) ) { + result = (*parent_getobslon)( this_frame, status ); + +/* Otherwise, if the ObsLon value is set in the first component Frame, + return it. */ + } else if( astTestObsLon( this->frame1 ) ){ + result = astGetObsLon( this->frame1 ); + +/* Otherwise, if the ObsLon value is set in the second component Frame, + return it. */ + } else if( astTestObsLon( this->frame2 ) ){ + result = astGetObsLon( this->frame2 ); + +/* Otherwise, return the default ObsLon value from the first component + Frame. */ + } else { + result = astGetObsLon( this->frame1 ); + } + +/* Return the result. */ + return result; +} + +static int GetNaxes( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetNaxes + +* Purpose: +* Determine how many axes a CmpFrame has. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int GetNaxes( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetNaxes method +* inherited from the Frame class). + +* Description: +* This function returns the number of axes for a CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The number of CmpFrame 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. +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + int naxes1; /* Number of axes for frame1 */ + int naxes2; /* Number of axes for frame2 */ + int result; /* Number of CmpFrame axes */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Obtain the number of axes for each component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + naxes2 = astGetNaxes( this->frame2 ); + +/* If OK, calculate the total number of axes. */ + if ( astOK ) result = naxes1 + naxes2; + +/* Return the result. */ + return result; +} + +static const int *GetPerm( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetPerm + +* Purpose: +* Access the axis permutation array for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* const int *astGetPerm( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the protected astGetPerm +* method inherited from the Frame class). + +* Description: +* This function returns a pointer to the axis permutation array +* for a CmpFrame. This array constitutes a lookup-table that +* converts between an axis number supplied externally and the +* corresponding index in the CmpFrame's internal data. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to the CmpFrame'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 CmpFrame +* 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 CmpFrame methods, and which therefore need to know +* how a CmpFrames's external axis index is converted for internal +* use. +* - The pointer returned by this function gives direct access to +* data internal to the CmpFrame object. It remains valid only so +* long as the CmpFrame exists. The permutation array contents may +* be modified by other functions which operate on the CmpFrame 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. + +* Implementation Notes: +* - This function performs essentially the same operation as the +* Frame member function which it over-rides. However, it returns a +* pointer to the "perm" array held in the CmpFrame structure +* (rather than the one in the parent Frame structure). This +* duplication of the array is necessary because the one in the +* Frame structure is of zero length, the number of axes in the +* Frame structure having been set to zero to prevent unnecessary +* allocation of Axis objects which are not needed by the CmpFrame. +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Return a pointer to the axis permutation array. */ + return this->perm; +} + +static AstSystemType GetSystem( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetSystem + +* Purpose: +* Obtain the System attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* AstSystemType GetSystem( AstFrame *this_frame, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetSystem protected +* method inherited from the Frame class). + +* Description: +* This function returns the System attribute for a CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstSystemType result; /* Value to return */ + +/* Initialise. */ + result = AST__BADSYSTEM; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) 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__COMP; + } + +/* Return the result. */ + return result; +} + +static const char *GetTitle( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetTitle + +* Purpose: +* Obtain a pointer to the Title attribute string for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* const char *GetTitle( AstFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetTitle protected +* method inherited from the Frame class). + +* Description: +* This function returns a pointer to the Title attribute string for +* a CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a constant null-terminated string containing the +* Title value. + +* Notes: +* - The returned pointer or the string it refers to may become +* invalid following further invocation of this function or +* modification of the CmpFrame. +* - 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 */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + const char *result; /* Pointer value to return */ + +/* 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_frame); + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* If a Title attribute string has been set, invoke the parent method + to obtain a pointer to it. */ + if ( astTestTitle( this ) ) { + result = (*parent_gettitle)( this_frame, status ); + +/* Otherwise, create a suitable default string and return a pointer to + this. */ + } else { + (void) sprintf( gettitle_buff, "%d-d compound coordinate system", + astGetNaxes( this ) ); + if ( astOK ) result = gettitle_buff; + } + +/* Return the result. */ + return result; + +} + +static int GetUseDefs( AstObject *this_object, int *status ) { +/* +* Name: +* GetUseDefs + +* Purpose: +* Get a value for the UseDefs attribute of a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int GetUseDefs( AstCmpFrame *this, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetUseDefs method +* inherited from the Frame class). + +* Description: +* This function returns a value for the UseDefs attribute of a +* CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The UseDefs attribute value. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + int result; /* Result value to return */ + +/* Initialise. */ + result = 1; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_object; + +/* If an UseDefs attribute value has been set, invoke the parent method + to obtain it. */ + if ( astTestUseDefs( this ) ) { + result = (*parent_getusedefs)( this_object, status ); + +/* Otherwise, use the UseDefs value in the first component Frame as the + default. */ + } else { + result = (*parent_getusedefs)( (AstObject *) this->frame1, status ); + } + +/* Return the result. */ + return result; +} + +static int GoodPerm( int ncoord_in, const int inperm[], + int ncoord_out, const int outperm[], int *status ) { +/* +* Name: +* GoodPerm + +* Purpose: +* Test if a PermMap will be non-null. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int GoodPerm( int ncoord_in, const int inperm[], +* int ncoord_out, const int outperm[], int *status ) + +* Class Membership: +* CmpFrame member function. + +* Description: +* This function tests if a pair of permutation arrays will, when +* used to create a PermMap, result in a PermMap which has a +* non-null effect (i.e. one which is not simply equivalent to a +* unit Mapping). + +* Parameters: +* ncoord_in +* The number of input coordinates for the PermMap. +* inperm +* The input permutation array for the PermMap (with "ncoord_in" +* elements). +* ncoord_out +* The number of output coordinates for the PermMap. +* outperm +* The output permutation array for the PermMap (with +* "ncoord_out" elements). +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Zero if the PermMap would be equivalent to a unit Mapping, +* otherwise one. + +* 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 axis; /* Loop counter for axes */ + int result; /* Result value to return */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* First test if the number of input and output coordinates are + different. */ + result = ( ncoord_in != ncoord_out ); + +/* If they are not, examine the contents of the "inperm" array. */ + if ( !result ) { + for ( axis = 0; axis < ncoord_in; axis++ ) { + +/* We have a non-null Mapping if any element of this array selects an + output axis with a different index to the input axis (or selects an + invalid axis or a constant). */ + if ( inperm[ axis ] != axis ) { + result = 1; + break; + } + } + } + +/* If the Mapping still appears to be null, also examine the "outperm" + array in the same way. */ + if ( !result ) { + for ( axis = 0; axis < ncoord_out; axis++ ) { + if ( outperm[ axis ] != axis ) { + result = 1; + break; + } + } + } + +/* Return the result. */ + return result; +} + +void astInitCmpFrameVtab_( AstCmpFrameVtab *vtab, const char *name, int *status ) { +/* +*+ +* Name: +* astInitCmpFrameVtab + +* Purpose: +* Initialise a virtual function table for a CmpFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "cmpframe.h" +* void astInitCmpFrameVtab( AstCmpFrameVtab *vtab, const char *name ) + +* Class Membership: +* CmpFrame vtab initialiser. + +* Description: +* This function initialises the component of a virtual function +* table which is used by the CmpFrame 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. */ + astInitFrameVtab( (AstFrameVtab *) vtab, name ); + +/* Store a unique "magic" value in the virtual function table. This + will be used (by astIsACmpFrame) 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. */ + +/* 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; + 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_getusedefs = object->GetUseDefs; + object->GetUseDefs = GetUseDefs; + +#if defined(THREAD_SAFE) + parent_managelock = object->ManageLock; + object->ManageLock = ManageLock; +#endif + + mapping->RemoveRegions = RemoveRegions; + mapping->Simplify = Simplify; + mapping->Transform = Transform; + + parent_getdomain = frame->GetDomain; + frame->GetDomain = GetDomain; + + parent_gettitle = frame->GetTitle; + frame->GetTitle = GetTitle; + + parent_getepoch = frame->GetEpoch; + frame->GetEpoch = GetEpoch; + + parent_setepoch = frame->SetEpoch; + frame->SetEpoch = SetEpoch; + + parent_clearepoch = frame->ClearEpoch; + frame->ClearEpoch = ClearEpoch; + + parent_getdtai = frame->GetDtai; + frame->GetDtai = GetDtai; + + parent_setdtai = frame->SetDtai; + frame->SetDtai = SetDtai; + + parent_cleardtai = frame->ClearDtai; + frame->ClearDtai = ClearDtai; + + parent_getdut1 = frame->GetDut1; + frame->GetDut1 = GetDut1; + + parent_setdut1 = frame->SetDut1; + frame->SetDut1 = SetDut1; + + parent_cleardut1 = frame->ClearDut1; + frame->ClearDut1 = ClearDut1; + + parent_getobslon = frame->GetObsLon; + frame->GetObsLon = GetObsLon; + + parent_setobslon = frame->SetObsLon; + frame->SetObsLon = SetObsLon; + + parent_clearobslon = frame->ClearObsLon; + frame->ClearObsLon = ClearObsLon; + + parent_getobslat = frame->GetObsLat; + frame->GetObsLat = GetObsLat; + + parent_setobslat = frame->SetObsLat; + frame->SetObsLat = SetObsLat; + + parent_clearobslat = frame->ClearObsLat; + frame->ClearObsLat = ClearObsLat; + + parent_getobsalt = frame->GetObsAlt; + frame->GetObsAlt = GetObsAlt; + + parent_setobsalt = frame->SetObsAlt; + frame->SetObsAlt = SetObsAlt; + + parent_clearobsalt = frame->ClearObsAlt; + frame->ClearObsAlt = ClearObsAlt; + + parent_angle = frame->Angle; + frame->Angle = Angle; + + parent_getsystem = frame->GetSystem; + frame->GetSystem = GetSystem; + + parent_getalignsystem = frame->GetAlignSystem; + frame->GetAlignSystem = GetAlignSystem; + + parent_clearalignsystem = frame->ClearAlignSystem; + frame->ClearAlignSystem = ClearAlignSystem; + + parent_overlay = frame->Overlay; + frame->Overlay = Overlay; + + parent_setactiveunit = frame->SetActiveUnit; + frame->SetActiveUnit = SetActiveUnit; + + parent_getactiveunit = frame->GetActiveUnit; + frame->GetActiveUnit = GetActiveUnit; + + parent_setframeflags = frame->SetFrameFlags; + frame->SetFrameFlags = SetFrameFlags; + + parent_getmaxaxes = frame->GetMaxAxes; + frame->GetMaxAxes = GetMaxAxes; + + parent_getminaxes = frame->GetMinAxes; + frame->GetMinAxes = GetMinAxes; + +/* Store replacement pointers for methods which will be over-ridden by + new member functions implemented here. */ + object->Cast = Cast; + mapping->Decompose = Decompose; + frame->Abbrev = Abbrev; + frame->ClearDirection = ClearDirection; + frame->ClearFormat = ClearFormat; + frame->ClearLabel = ClearLabel; + frame->ClearSymbol = ClearSymbol; + frame->ClearUnit = ClearUnit; + frame->Distance = Distance; + frame->Fields = Fields; + frame->Format = Format; + frame->FrameGrid = FrameGrid; + frame->Centre = Centre; + frame->Gap = Gap; + frame->GetAxis = GetAxis; + frame->GetDirection = GetDirection; + frame->GetFormat = GetFormat; + frame->GetLabel = GetLabel; + frame->GetNaxes = GetNaxes; + frame->GetPerm = GetPerm; + frame->GetSymbol = GetSymbol; + frame->GetUnit = GetUnit; + frame->IsUnitFrame = IsUnitFrame; + frame->Match = Match; + frame->Norm = Norm; + frame->NormBox = NormBox; + frame->Offset = Offset; + frame->PermAxes = PermAxes; + frame->PrimaryFrame = PrimaryFrame; + frame->Resolve = Resolve; + frame->ResolvePoints = ResolvePoints; + frame->SetAxis = SetAxis; + frame->SetDirection = SetDirection; + frame->SetFormat = SetFormat; + frame->SetLabel = SetLabel; + frame->SetSymbol = SetSymbol; + frame->SetUnit = SetUnit; + frame->SubFrame = SubFrame; + frame->TestDirection = TestDirection; + frame->TestFormat = TestFormat; + frame->TestLabel = TestLabel; + frame->TestSymbol = TestSymbol; + frame->TestUnit = TestUnit; + frame->Unformat = Unformat; + frame->ValidateSystem = ValidateSystem; + frame->SystemString = SystemString; + frame->SystemCode = SystemCode; + frame->MatchAxesX = MatchAxesX; + +/* Declare the copy constructor, destructor and class dump + function. */ + astSetCopy( vtab, Copy ); + astSetDelete( vtab, Delete ); + astSetDump( vtab, Dump, "CmpFrame", + "Compound 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 int IsUnitFrame( AstFrame *this_frame, int *status ){ +/* +* Name: +* IsUnitFrame + +* Purpose: +* Is this Frame equivalent to a UnitMap? + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.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. + +*- +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Return the result. */ + return astIsUnitFrame( this->frame1 ) && astIsUnitFrame( this->frame2 ); +} + +#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: +* CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame 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 CmpFrame structure. */ + this = (AstCmpFrame *) 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->frame1, mode, extra, fail ); + if( !result ) result = astManageLock( this->frame2, mode, extra, fail ); + + return result; + +} +#endif + +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 "cmpframe.h" +* int Match( AstFrame *template, AstFrame *target, int matchsub, +* int **template_axes, int **target_axes, +* AstMapping **map, AstFrame **result, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the protected astMatch +* method inherited from the Frame class). + +* Description: +* This function matches a "template" CmpFrame 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" CmpFrame from which they are derived. + +* Parameters: +* template +* Pointer to the template CmpFrame. 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 CmpFrame 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 +* CmpFrame. 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" CmpFrame. However, +* if the PreserveAxes attribute of the template CmpFrame 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: */ + AstCmpFrame *template; /* Pointer to template CmpFrame structure */ + 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 *axes1; /* Pointer to axis selection 1 */ + int *axes2; /* Pointer to axis selection 2 */ + int *used; /* Pointer to flags array */ + int axis2; /* Index for axis selection 2 */ + int axis; /* Index for axis arrays */ + int last_target; /* Last target axis association */ + int last_template; /* Last template axis associateion */ + int match; /* Match obtained (returned result)? */ + int maxax1; /* MaxAxes attribute for component 1 */ + int maxax2; /* MaxAxes attribute for component 2 */ + int maxax; /* Max axes that can be matched by template */ + int minax1; /* MinAxes attribute for component 1 */ + int minax2; /* MinAxes attribute for component 2 */ + int minax; /* Min axes that can be matched by template */ + int naxes1; /* Number of axes assigned to component 1 */ + int naxes2; /* Number of axes assigned to component 2 */ + int naxes; /* Total number of target axes */ + int naxes_max1; /* First estimate of naxes_max */ + int naxes_max2; /* Second estimate of naxes_max */ + int naxes_max; /* Max number of axes to match component 1 */ + int naxes_min1; /* First estimate of naxes_min */ + int naxes_min2; /* Second estimate of naxes_min */ + int naxes_min; /* Min number of axes to match component 1 */ + int permute; /* Permute attribute for template */ + int result_naxes; /* Number of result Frame 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 CmpFrame structure. */ + template = (AstCmpFrame *) template_frame; + +/* Further initialisation to avoid compiler warnings. */ + naxes_min = 0; + naxes_max = 0; + +/* Obtain the maximum number of axes that the template CmpFrame, and each + component Frame of the template CmpFrame, can match. If the MaxAxes + attribute is set for the template, use it and assume that each + component Frame can match any number of axes. */ + if( astTestMaxAxes( template ) ) { + maxax = astGetMaxAxes( template ); + maxax1 = 100000; + maxax2 = 100000; + } else { + maxax1 = astGetMaxAxes( template->frame1 ); + maxax2 = astGetMaxAxes( template->frame2 ); + maxax = maxax1 + maxax2; + } + +/* Do the same for the minimum number of axes that can be matched by the + template CmpFrame. */ + if( astTestMinAxes( template ) ) { + minax = astGetMinAxes( template ); + minax1 = 1; + minax2 = 1; + } else { + minax1 = astGetMinAxes( template->frame1 ); + minax2 = astGetMinAxes( template->frame2 ); + minax = minax1 + minax2; + } + +/* Obtain the number of axes in the target Frame and test to see if it + is possible for the template to match it on the basis of axis + counts. */ + naxes = astGetNaxes( target ); + match = ( naxes >= minax && naxes <= maxax ); + +/* The next requirement is that all the frames have some axes. */ + if( naxes == 0 || maxax1 == 0 || maxax2 == 0 ) match = 0; + +/* The next requirement is that if the template CmpFrame has its + Domain attribute defined, then the target Frame 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 a match still appears possible, determine the minimum number of + target axes that will have to match the first component Frame of + the template CmpFrame. */ + if ( astOK && match ) { + naxes_min1 = minax1; + naxes_min2 = naxes - maxax2; + naxes_min = ( naxes_min1 > naxes_min2 ) ? naxes_min1 : naxes_min2; + +/* Also determine the maximum number of target axes that may match + this component of the template. */ + naxes_max1 = maxax1; + naxes_max2 = naxes - minax2; + naxes_max = ( naxes_max1 < naxes_max2 ) ? naxes_max1 : naxes_max2; + +/* No match possible if the number of axes are inconsistent. */ + if( naxes_min > naxes_max ) match = 0; + } + +/* If a match is still possible, allocate workspace. */ + if( match ) { + axes1 = astMalloc( sizeof( int ) * (size_t) naxes ); + axes2 = astMalloc( sizeof( int ) * (size_t) naxes ); + used = astMalloc( sizeof( int ) * (size_t) naxes ); + +/* Obtain the value of the template's Permute attribute. */ + permute = astGetPermute( template ); + if ( astOK ) { + +/* Loop to consider all possible choices of the number of template + axes that might match the first component Frame of the template, + and derive the corresponding number of axes that must match the + second component at the same time. */ + for ( naxes1 = naxes_max; naxes1 >= naxes_min; naxes1-- ) { + naxes2 = naxes - naxes1; + +/* Initialise the selection of target axes that we will attempt to + match against the first template component (to [0,1,2,...]). */ + for ( axis = 0; axis < naxes1; axis++ ) axes1[ axis ] = axis; + +/* Loop to consider all possible selections with this number of axes, + until a match is found. */ + while ( 1 ) { + +/* Initialise an array of flags to zero for each target axis. Then set + the flag to 1 for each axis which is in the first selection.*/ + for ( axis = 0; axis < naxes; axis++ ) used[ axis ] = 0; + for( axis = 0; axis < naxes1; axis++ ) { + used[ axes1[ axis ] ] = 1; + } + +/* Generate the second selection by including all target axes that are + not in the first selection. */ + axis2 = 0; + for ( axis = 0; axis < naxes; axis++ ) { + if ( !used[ axis ] ) axes2[ axis2++ ] = axis; + } + +/* Attempt to match the target axes partitioned in this way to the two + template components. */ + match = PartMatch( template, target, matchsub, + naxes1, axes1, naxes2, axes2, + template_axes, target_axes, map, result, status ); + +/* If a match was obtained but the template's Permute attribute is zero, + then we must check to see if the match involves permuting the target + axes. */ + if ( astOK && match && !permute ) { + +/* Obtain the number of result Frame axes. */ + result_naxes = astGetNaxes( *result ); + +/* Loop to check the target and template axis associations for all the + result Frame axes. The match will only be accepted if both of these + are monotonically increasing (indicating no axis permutation) after + allowing for any absent associations . */ + last_template = -1; + last_target = -1; + for ( axis = 0; axis < result_naxes; axis++ ) { + +/* Check the template axis association against the previous value, + omitting any axes witout valid associations. */ + if ( ( *template_axes )[ axis ] != -1 ) { + if ( ( *template_axes )[ axis ] <= last_template ) { + match = 0; + break; + +/* Update the previous association value. */ + } else { + last_template = ( *template_axes )[ axis ]; + } + } + +/* Repeat this process for the target axis associations. */ + if ( ( *target_axes )[ axis ] != -1 ) { + if ( ( *target_axes )[ axis ] <= last_target ) { + match = 0; + break; + } else { + last_target = ( *target_axes )[ axis ]; + } + } + } + +/* If the match was rejected because it involves an axis permutation, + then free the allocated memory and annul the Object pointers + associated with the match. */ + if ( !match ) { + *template_axes = astFree( *template_axes ); + *target_axes = astFree( *target_axes ); + *map = astAnnul( *map ); + *result = astAnnul( *result ); + } + } + +/* If an error occurred or a match was found, quit searching, + otherwise generate the next axis selection and try that + instead. Quit if there are no more selections to try. */ + if ( !astOK || match || + !GenAxisSelection( naxes, naxes1, axes1, status ) ) break; + } + +/* Quit the outer loop if an error occurs or a match is found. */ + if ( !astOK || match ) break; + } + } + +/* Free the workspace arrays. */ + axes1 = astFree( axes1 ); + axes2 = astFree( axes2 ); + used = astFree( used ); + } + +/* If the target did not match the supplied template CmpFrame, see if it + will match either of the component Frames. First try matching it against + the first component Frame. */ + if( !match ) match = ComponentMatch( template, target, matchsub, 0, + template_axes, target_axes, map, result, + status ); + +/* If we still dont have a mcth, try matching it against the second + component Frame. */ + if( !match ) match = ComponentMatch( template, target, matchsub, 1, + template_axes, target_axes, map, + result, status ); + +/* If an error occurred, free all allocated memory, annul the result + Object pointers and clear all returned values. */ + if ( !astOK ) { + *template_axes = astFree( *template_axes ); + *target_axes = astFree( *target_axes ); + *map = astAnnul( *map ); + *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 "cmpframe.h" +* void MatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes ) +* int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the protected astMatchAxesX +* 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: +* 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: */ + AstCmpFrame *frm2; + const int *perm; + int *work; + int i; + int nax2; + int nax1; + int nax; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the CmpFrame. */ + frm2 = (AstCmpFrame *) frm2_frame; + +/* Get the number of axes in the two component Frames, and the total + number of axes in the CmpFrame. */ + nax2 = astGetNaxes( frm2->frame1 ); + nax1 = astGetNaxes( frm2->frame2 ); + nax = nax2 + nax1; + +/* Allocate a work array to hold the unpermuted axis indices */ + work = astMalloc( sizeof( int )*nax ); + if( astOK ) { + +/* Use the astMatchAxes method to match axes in the first component Frame + within CmpFrame "frm2". Write the associated axis indices into the first + part of the work array. */ + astMatchAxes( frm1, frm2->frame1, work ); + +/* Use the MatchAxes method to match axes in the second component + Frame. Write the associated axis indices into the work array + following the end of the values already in there. */ + astMatchAxes( frm1, frm2->frame2, work + nax2 ); + +/* Obtain a pointer to the CmpFrame's axis permutation array. The index + into "perm" represents the external axis index, and the value held in + each element of "perm" represents the corresponding internal axis index. */ + perm = astGetPerm( frm2 ); + if( astOK ) { + +/* Copy the frm2 axis indices from the work array into the returned "axes" + array, permuting their order into the external axis order of the + CmpFrame. */ + for( i = 0; i < nax; i++ ) axes[ i ] = work[ perm[ i ] ]; + } + +/* Free resources */ + work = astFree( work ); + } +} + +static void Norm( AstFrame *this_frame, double value[], int *status ) { +/* +* Name: +* Norm + +* Purpose: +* Normalise a set of CmpFrame coordinates. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void Norm( AstAxis *this, double value[], int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astNorm method +* inherited from the Frame class). + +* Description: +* This function converts a set of CmpFrame 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. + +* Parameters: +* this +* Pointer to the CmpFrame. +* value +* An array of double, with one element for each CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + const int *perm; /* Axis permutation array */ + double *v; /* Pointer to permuted coordinates */ + int axis; /* Loop counter for axes */ + int naxes1; /* Number of axes in frame1 */ + int naxes; /* Number of axes in CmpFrame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Obtain a pointer to the CmpFrame's axis permutation array. */ + perm = astGetPerm( this ); + +/* Obtain the number of axes in the CmpFrame and in the first + component Frame. */ + naxes = astGetNaxes( this ); + naxes1 = astGetNaxes( this->frame1 ); + +/* Allocate memory to hold the permuted coordinates. */ + v = astMalloc( sizeof( double ) * (size_t) naxes ); + if ( astOK ) { + +/* Permute the coordinates using the CmpFrame's axis permutation array + to put them into the order required internally (i.e. by the two + component Frames). */ + for ( axis = 0; axis < naxes; axis++ ) v[ perm[ axis ] ] = value[ axis ]; + +/* Invoke the astNorm method of both component Frames, passing the + relevant (permuted) coordinate values for normalisation. */ + astNorm( this->frame1, v ); + astNorm( this->frame2, v + naxes1 ); + +/* Copy the normalised values back into the original coordinate array, + un-permuting them in the process. */ + for ( axis = 0; axis < naxes; axis++ ) value[ axis ] = v[ perm[ axis ] ]; + } + +/* Free the memory used for the permuted coordinates. */ + v = astFree( v ); +} + +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 "cmpframe.h" +* void astNormBox( AstFrame *this, double lbnd[], double ubnd[], +* AstMapping *reg, int *status ) + +* Class Membership: +* CmpFrame 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: */ + AstCmpFrame *this; + AstCmpMap *m1; + AstCmpMap *m2; + AstCmpMap *m3; + AstCmpMap *m4; + AstCmpMap *m5; + AstCmpMap *m6; + AstPermMap *pm1; + AstPermMap *pm2; + AstPermMap *pm3; + const int *perm; + double *vl; + double *vu; + int *inperm; + int axis; + int naxes1; + int naxes; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Obtain a pointer to the CmpFrame's axis permutation array. */ + perm = astGetPerm( this ); + +/* Obtain the number of axes in the CmpFrame and in the first + component Frame. */ + naxes = astGetNaxes( this ); + naxes1 = astGetNaxes( this->frame1 ); + +/* Allocate memory to hold the permuted coordinates. */ + vl = astMalloc( sizeof( double ) * (size_t) naxes ); + vu = astMalloc( sizeof( double ) * (size_t) naxes ); + inperm = astMalloc( sizeof( int ) * (size_t) naxes ); + if( inperm ) { + +/* Permute the coordinates using the CmpFrame's axis permutation array + to put them into the order required internally (i.e. by the two + component Frames). */ + for ( axis = 0; axis < naxes; axis++ ) { + vl[ perm[ axis ] ] = lbnd[ axis ]; + vu[ perm[ axis ] ] = ubnd[ axis ]; + } + +/* Create a PermMap with a forward transformation which reorders a position + which uses internal axis ordering into a position which uses external axis + ordering. */ + pm1 = astPermMap( naxes, NULL, naxes, perm, NULL, "", status ); + +/* Put it in front of the supplied Mapping. The combination transforms an + input internal position into an output external position. */ + m1 = astCmpMap( pm1, reg, 1, "", status ); + +/* Invert it and add it to the end. This combination now transforms an + input internal position into an output internal position. */ + astInvert( pm1 ); + m2 = astCmpMap( m1, pm1, 1, "", status ); + +/* Create a PermMap with a forward transformation which copies the lower + naxes1 inputs to the same outputs, and supplies AST__BAD for the other + outputs. */ + for( axis = 0; axis < naxes1; axis++ ) inperm[ axis ] = axis; + pm2 = astPermMap( naxes1, inperm, naxes, NULL, NULL, "", status ); + +/* Put it in front of the Mapping created above, then invert it and add + it at the end. */ + m3 = astCmpMap( pm2, m2, 1, "", status ); + astInvert( pm2 ); + m4 = astCmpMap( m3, pm2, 1, "", status ); + +/* Invoke the astNormBox method of the first component Frame, passing the + relevant (permuted) coordinate values for normalisation. */ + astNormBox( this->frame1, vl, vu, m4 ); + +/* Create a PermMap with a forward transformation which copies the upper + inputs to the same outputs, and supplied AST__BAD for the other + outputs. */ + for( axis = 0; axis < naxes - naxes1; axis++ ) inperm[ axis ] = naxes1 + axis; + pm3 = astPermMap( naxes1, inperm, naxes, NULL, NULL, "", status ); + +/* Put it in front of the Mapping created above, then invert it and add + it at the end. */ + m5 = astCmpMap( pm3, m2, 1, "", status ); + astInvert( pm3 ); + m6 = astCmpMap( m5, pm3, 1, "", status ); + +/* Invoke the astNormBox method of the seond component Frame, passing the + relevant (permuted) coordinate values for normalisation. */ + astNormBox( this->frame2, vl + naxes1, vu + naxes1, m6 ); + +/* Copy the normalised values back into the original coordinate array, + un-permuting them in the process. */ + for ( axis = 0; axis < naxes; axis++ ) { + lbnd[ axis ] = vl[ perm[ axis ] ]; + ubnd[ axis ] = vu[ perm[ axis ] ]; + } + +/* Free resources. */ + pm1 = astAnnul( pm1 ); + pm2 = astAnnul( pm2 ); + pm3 = astAnnul( pm3 ); + m1 = astAnnul( m1 ); + m2 = astAnnul( m2 ); + m3 = astAnnul( m3 ); + m4 = astAnnul( m4 ); + m5 = astAnnul( m5 ); + m6 = astAnnul( m6 ); + } + inperm = astFree( inperm ); + vl = astFree( vl ); + vu = astFree( vu ); +} + +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 "cmpframe.h" +* void Offset( AstFrame *this, +* const double point1[], const double point2[], +* double offset, double point3[], int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astOffset method +* inherited from the Frame class). + +* Description: +* This function finds the CmpFrame coordinate values of a point +* which is offset a specified distance along the geodesic curve +* between two other points. + +* Parameters: +* this +* Pointer to the CmpFrame. +* point1 +* An array of double, with one element for each CmpFrame 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 CmpFrame 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 CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + const int *perm; /* Pointer to axis permutation array */ + double *p1; /* Permuted coordinates for point1 */ + double *p2; /* Permuted coordinates for point2 */ + double *p3; /* Permuted coordinates for point3 */ + double dist1; /* Distance between input points in frame1 */ + double dist2; /* Distance between input points in frame2 */ + double dist; /* Total distance between input points */ + double offset1; /* Offset distance required in frame1 */ + double offset2; /* Offset distance required in frame2 */ + int axis; /* Loop counter for axes */ + int bad; /* Set bad output coordinates? */ + int naxes1; /* Number of axes in frame1 */ + int naxes; /* Total number of axes in CmpFrame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Obtain the number of axes in the CmpFrame. */ + naxes = astGetNaxes( this ); + +/* Obtain a pointer to the CmpFrame's axis permutation array. */ + perm = astGetPerm( this ); + +/* Allocate workspace. */ + p1 = astMalloc( sizeof( double ) * (size_t) naxes ); + p2 = astMalloc( sizeof( double ) * (size_t) naxes ); + p3 = astMalloc( sizeof( double ) * (size_t) naxes ); + +/* Initialise variables to avoid compiler warnings. */ + dist1 = 0.0; + dist2 = 0.0; + offset1 = 0.0; + offset2 = 0.0; + naxes1 = 0; + +/* Initialise a flag to indicate whether "bad" coordinates should be + returned. */ + bad = 0; + +/* Check that all the coordinates of both input points are OK. If not, + set the "bad" flag and quit checking. */ + if ( astOK ) { + for ( axis = 0; axis < naxes; axis++ ) { + if ( ( point1[ axis ] == AST__BAD ) || + ( point2[ axis ] == AST__BAD ) ) { + bad = 1; + break; + +/* If the coordinates are OK, apply the axis permutation array to + obtain them in the required order. */ + } else { + p1[ perm[ axis ] ] = point1[ axis ]; + p2[ perm[ axis ] ] = point2[ axis ]; + } + } + } + +/* If OK, obtain the number of axes in the first component Frame. */ + if ( astOK && !bad ) { + naxes1 = astGetNaxes( this->frame1 ); + +/* Project the two input points into the two component Frames and + determine the distance between the points in each Frame. */ + dist1 = astDistance( this->frame1, p1, p2 ); + dist2 = astDistance( this->frame2, p1 + naxes1, p2 + naxes1 ); + +/* Check that the returned distances are not bad. */ + if ( astOK ) bad = ( ( dist1 == AST__BAD ) || ( dist2 == AST__BAD ) ); + } + +/* If OK, calculate the total distance between the two points. */ + if ( astOK && !bad ) { + dist = sqrt( dist1 * dist1 + dist2 * dist2 ); + +/* If the points are co-incident, but "offset" is non-zero, then set + the "bad" flag. */ + if ( dist == 0.0 ) { + if ( offset != 0.0 ) { + bad = 1; + +/* Otherwise, set the offset distance required in each Frame to + zero. */ + } else { + offset1 = 0.0; + offset2 = 0.0; + } + +/* If the points are not co-incident, divide the total offset required + between each component Frame in such a way that the path being + followed will pass through the second point. */ + } else { + offset1 = offset * dist1 / dist; + offset2 = offset * dist2 / dist; + } + } + +/* If OK, apply the separate offsets to each component Frame. */ + if ( astOK && !bad ) { + astOffset( this->frame1, p1, p2, offset1, p3 ); + astOffset( this->frame2, p1 + naxes1, p2 + naxes1, offset2, + p3 + naxes1 ); + +/* Copy the resulting coordinates into the output array "point3", + permuting them back into the required order. */ + if ( astOK ) { + for ( axis = 0; axis < naxes; axis++ ) { + point3[ axis ] = p3[ perm[ axis ] ]; + +/* If any of the result coordinates is bad, set the "bad" flag and + quit copying. */ + if ( point3[ axis ] == AST__BAD ) { + bad = 1; + break; + } + } + } + } + +/* Free the workspace arrays. */ + p1 = astFree( p1 ); + p2 = astFree( p2 ); + p3 = astFree( p3 ); + +/* If no error has occurred, but bad coordinates must be returned, + then set these in the output array. */ + if ( astOK && bad ) { + for ( axis = 0; axis < naxes; axis++ ) point3[ axis ] = AST__BAD; + } +} + +static void Overlay( AstFrame *template_frame, const int *template_axes, + AstFrame *result, int *status ) { +/* +* Name: +* Overlay + +* Purpose: +* Overlay the attributes of a template CmpFrame on to another Frame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void Overlay( AstFrame *template, const int *template_axes, +* AstFrame *result, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the protected astOverlay +* method inherited from the Frame class). + +* Description: +* This function overlays attributes from a CmpFrame 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 CmpFrame, 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 CmpFrame 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 +* indices 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: */ + AstCmpFrame *res; /* Pointer to the result CmpFrame structure */ + AstCmpFrame *template; /* Pointer to the template CmpFrame structure */ + AstFrame *sub1; /* Template subframe for 1st result subframe */ + AstFrame *sub2; /* Template subframe for 2nd result subframe */ + const int *perm; /* Template axis permutation array */ + const int *rperm; /* Result axis permutation array */ + int *axes1; /* Axis associations with template frame1 */ + int *axes2; /* Axis associations with template frame2 */ + int done; /* Have attributes been overlayed yet? */ + int i; /* Index of result axis */ + int icmp; /* Internal template axis number */ + int isfirst; /* Res. subframe -> 1st template subframe? */ + int issecond; /* Res. subframe -> 2nd template subframe? */ + int j; /* Index of template axis */ + int nc1; /* Number of axes in template frame1 */ + int nres1; /* Number of axes in first result subframe */ + int nres2; /* Number of axes in second result subframe */ + int nres; /* Number of axes in result Frame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + template = (AstCmpFrame *) template_frame; + +/* Get the axis permutation array for the template CmpFrame. */ + perm = astGetPerm( template ); + +/* Get the number of axes in the first component Frame in the template + CmpFrame. */ + nc1 = astGetNaxes( template->frame1 ); + +/* Indicate we have not yet overlayed any attributes. */ + done = 0; + +/* If the result Frame is a CmpFrame... */ + if( astIsACmpFrame( result ) ) { + +/* Get the number of axes in the two component Frames of the result CmpFrame. */ + res = (AstCmpFrame *) result; + nres1 = astGetNaxes( res->frame1 ); + nres2 = astGetNaxes( res->frame2 ); + +/* Get the total number of axes in the result CmpFrame. */ + nres = nres1 + nres2; + +/* Get the axis permutation array for the result CmpFrame. */ + rperm = astGetPerm( result ); + +/* Allocate memory for two new axes arrays, one for each result sub-frame. */ + axes1 = astMalloc( sizeof(int)*(size_t)nres1 ); + axes2 = astMalloc( sizeof(int)*(size_t)nres2 ); + if( astOK ) { + +/* Assume that there is a 1-to-1 correspondence between axes in the + subframes of the result and template CmpFrame. That is, all the axes + in each result sub-frame are overlayed from the same template sub-frame. */ + done = 1; + +/* Loop round each axis in the first result sub-frame. */ + isfirst = 0; + issecond = 0; + for( i = 0; i < nres1; i++ ) { + +/* Find the external result CmpFrame axis index (j) for internal axis i. */ + for( j = 0; j < nres; j++ ) { + if( rperm[ j ] == i ) break; + } + +/* Get the internal axis number within the template CmpFrame which + provides attribute values for the current result axis. */ + icmp = perm[ template_axes ? template_axes[ j ] : j ]; + +/* If this template axis is in the first template subframe, store the + corresponding internal frame axis index in "axes1" and set a flag + indicating that the first result subframe corresponds to the first + template subframe. If the correspondance has already been established, + but is broken by this axis, then set "done" false and exit the axis + loop. */ + if( icmp < nc1 ) { + if( issecond ) { + done = 0; + break; + } else { + isfirst = 1; + axes1[ i ] = icmp; + } + + } else { + if( isfirst ) { + done = 0; + break; + } else { + issecond = 1; + axes1[ i ] = icmp - nc1; + } + } + } + +/* Save a pointer to the template subframe which is associated with the first + result subframe.*/ + sub1 = isfirst ? template->frame1 :template->frame2; + +/* Now do the same for the axes in the second result sub-frame. */ + isfirst = 0; + issecond = 0; + for( i = 0; i < nres2; i++ ) { + for( j = 0; j < nres; j++ ) { + if( rperm[ j ] == i + nres1 ) break; + } + + icmp = perm[ template_axes ? template_axes[ j ] : j ]; + + if( icmp < nc1 ) { + if( issecond ) { + done = 0; + break; + } else { + isfirst = 1; + axes2[ i ] = icmp; + } + + } else { + if( isfirst ) { + done = 0; + break; + } else { + issecond = 1; + axes2[ i ] = icmp - nc1; + } + } + } + +/* Save a pointer to the template subframe which is associated with the + second result subframe.*/ + sub2 = isfirst ? template->frame1 :template->frame2; + +/* If the two used template subframes are the same, something has gone + wrong. */ + if( sub1 == sub2 ) done = 0; + +/* If all axes within each result subframe are associated with the same + template subframe we continue to use the subframe astOverlay methods. */ + if( done ) { + +/* Overlay the first result subframe. */ + astOverlay( sub1, axes1, res->frame1 ); + astOverlay( sub2, axes2, res->frame2 ); + } + } + +/* Free the axes arrays. */ + axes1 = astFree( axes1 ); + axes2 = astFree( axes2 ); + } + +/* If we have not yet overlayed any attributes... */ + if( !done ) { + +/* Get the number of axes in the result Frame. */ + nres = astGetNaxes( result ); + +/* Allocate memory for two new template_axes arrays. */ + axes1 = astMalloc( sizeof(int)*(size_t)nres ); + axes2 = astMalloc( sizeof(int)*(size_t)nres ); + if( astOK ) { + +/* Set elements to -1 in "axes1" if they do not refer to the first component + Frame in the template CmpFrame. Likewise, set elements to -1 in "axes2" if + they do not refer to the second component Frame in the template CmpFrame. */ + for( i = 0; i < nres; i++ ) { + +/* Get the internal axis number within the template CmpFrame which + provides attribute values for the current results axis. */ + icmp = perm[ template_axes ? template_axes[ i ] : i ]; + +/* If this template axis is in the first component Frame, store the + corresponding internal frame axis index in "axes1" and set "axis2" to + -1. */ + if( icmp < nc1 ) { + axes1[ i ] = icmp; + axes2[ i ] = -1; + +/* If this template axis is in the second component Frame, store the + corresponding internal frame axis index in "axes2" and set "axis1" to + -1. */ + } else { + axes1[ i ] = -1; + axes2[ i ] = icmp - nc1; + } + } + +/* Now use the astOverlay methods of the two component Frames to overlay + attributes onto the appropriate axes of the results Frame. */ + astOverlay( template->frame1, axes1, result ); + astOverlay( template->frame2, axes2, result ); + } + +/* Free the axes arrays. */ + axes1 = astFree( axes1 ); + axes2 = astFree( axes2 ); + } +} + +static void PartitionSelection( int nselect, const int select[], + const int perm[], int naxes1, int naxes2, + int iframe[], int following, int *status ) { +/* +* Name: +* PartitionSelection + +* Purpose: +* Partition a CmpFrame axis selection into two component Frame selections. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void PartitionSelection( int nselect, const int select[], +* const int perm[], int naxes1, int naxes2, +* int iframe[], int following, int *status ) + +* Class Membership: +* CmpFrame member function. + +* Description: +* This function accepts an array containing the indices of axes +* which are to be selected from a CmpFrame, and partitions these +* indices to indicate which must be selected from each of the +* CmpFrame's two component Frames. +* +* This operation is trivial if all the axis indices supplied refer +* to valid CmpFrame axes. However, if some of them do not (these +* should generally be set to -1), this function assigns these +* "extra" axes to one or other of the component Frames by +* associating them with the axes selected immediately before (or +* after). Allowance is made for the possibility that several +* consecutive selected axes may be "extra" ones, or even that they +* may all be. The CmpFrame's axis permutation array is also taken +* into account. + +* Parameters: +* nselect +* The number of axes to be selected. +* select +* An array containing the (zero-based) indices of the CmpFrame +* axes to be selected, or -1 where "extra" axes are required. +* perm +* The CmpFrame's axis permutation array. +* naxes1 +* The number of axes in the CmpFrame's first component Frame. +* naxes2 +* The number of axes in the CmpFrame's second component Frame. +* iframe +* An array with "nselect" elements in which to return a number +* (either 1 or 2) to indicate to which component Frame (frame1 +* or frame2) each selected axis belongs. +* following +* If this is zero, "extra" axes will be associated with the +* preceding normal selected axis which appears in the "select" +* array (if any), otherwise they will be associated with the +* following normal selected axis. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + int end; /* Loop termination value */ + int ifr; /* Choice of Frame for next "extra" axis */ + int inc; /* Loop increment value */ + int iselect; /* Loop counter for axis selections */ + int naxes; /* Total number of CmpFrame axes */ + int start; /* Loop starting value */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain the total number of CmpFrame axes. */ + naxes = naxes1 + naxes2; + +/* Loop through each axis selection and identify those which refer to + valid CmpFrame axes. */ + for ( iselect = 0; iselect < nselect; iselect++ ) { + if ( ( select[ iselect ] >= 0 ) && ( select[ iselect ] < naxes ) ) { + +/* For these selections (only), enter a flag into the "iframe" array + which indicates which component Frame the selected axis resides + in. Permute each axis index before deciding this. */ + iframe[ iselect ] = 1 + ( perm[ select[ iselect ] ] >= naxes1 ); + } + } + +/* Set up a start, end, and increment value for looping through the + array of axis selections forward (if "following" is 0) or backwards + (otherwise). */ + start = following ? nselect - 1 : 0; + end = following ? -1 : nselect; + inc = following ? -1 : 1; + +/* Set the default choice of component Frame. This will be used if + there are no normal axis selections to guide the choice at all. */ + ifr = following ? 2 : 1; + +/* Search for the first normal axis selection so that we can replace + this default, if possible. (Here, "first" actually means "last" if + "following" is set, because we will then be scanning the array of + selections in reverse.) */ + for ( iselect = start; iselect != end; iselect += inc ) { + +/* Identify normal axis selections and obtain the choice of component + Frame for the first one found. The resulting value "ifr" will be + used for initial (or final, if "following" is set) "extra" + selections for which no earlier normal selection exists - see + below. */ + if ( ( select[ iselect ] >= 0 ) && ( select[ iselect ] < naxes ) ) { + ifr = iframe[ iselect ]; + break; + } + } + +/* Loop through the selections again to allocate a choice of Frame to + the "extra" selected axes. */ + for ( iselect = start; iselect != end; iselect += inc ) { + +/* Remember the component Frame used by the most recently encountered + normal axis selection. */ + if ( ( select[ iselect ] >= 0 ) && ( select[ iselect ] < naxes ) ) { + ifr = iframe[ iselect ]; + +/* For "extra" axes, allocate the most recent Frame choice. The + default choice (found above) will apply if no "most recent" choice + has been encountered. */ + } else { + iframe[ iselect ] = ifr; + } + } +} + +static int PartMatch( AstCmpFrame *template, AstFrame *target, + int matchsub, int naxes1, const int axes1[], + int naxes2, const int axes2[], + int **template_axes, int **target_axes, + AstMapping **map, AstFrame **result, int *status ) { +/* +* Name: +* PartMatch + +* Purpose: +* Match a CmpFrame template to partitioned target axes. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int PartMatch( AstCmpFrame *template, AstFrame *target, +* int matchsub, int naxes1, const int axes1[], +* int naxes2, const int axes2[], +* int **template_axes, int **target_axes, +* AstMapping **map, AstFrame **result, int *status ) + +* Class Membership: +* CmpFrame member function. + +* Description: +* This function matches a "template" CmpFrame 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" CmpFrame from which they are derived. +* +* To simplify the matching process for a CmpFrame template, this +* function requires the caller to specify how the axes of the +* target Frame should be partitioned between the two component +* Frames of the template. The function attempts to find a match +* using this axis partitioning only. In general, the way in which +* the target axes must be partitioned is not known in advance, so +* this function must be invoked several times with alternative +* partitioning before a match will be found. + +* Parameters: +* template +* Pointer to the template CmpFrame. 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. +* naxes1 +* The number of target axes to be matched against the first +* component Frame of the template CmpFrame. +* axes1 +* An array with "naxes1" elements containing the (zero-based) +* indices of the target axes to be matched against the first +* component Frame. Order is not significant. +* naxes2 +* The number of target axes to be matched against the second +* component Frame of the template CmpFrame. +* axes2 +* An array with "naxes2" elements containing the (zero-based) +* indices of the target axes to be matched against the second +* component Frame. Order is not significant. +* 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 CmpFrame 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 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 template +* CmpFrame. 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: +* - The "axes1" and "axes2" arrays should not contain any axis +* indices in common and should, taken together, list all the axes +* of the target Frame. +* - By default, the "result" Frame will have its number of axes +* and axis order determined by the "template" CmpFrame. However, +* if the PreserveAxes attribute of the template 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: */ + AstFrame *frame1; /* Pointer to first sub-Frame from target */ + AstFrame *frame2; /* Pointer to second sub-Frame from target */ + AstFrame *result1; /* Result Frame pointer from first match */ + AstFrame *result2; /* Result Frame pointer from second match */ + AstFrame *tmp_frame; /* Temporary Frame pointer */ + AstMapping *junk_map; /* Mapping pointer returned by astSubFrame */ + AstMapping *map1; /* Mapping pointer from first match */ + AstMapping *map2; /* Mapping pointer from second match */ + AstMapping *permmap; /* Pointer to PermMap */ + AstMapping *tmp_map; /* Temporary Mapping pointer */ + const int *perm; /* Template axis permutation array pointer */ + int *inperm; /* Pointer to temporary permutation array */ + int *invperm; /* Inverse axis permutation array pointer */ + int *outperm; /* Pointer to temporary permutation array */ + int *pick; /* Pointer to array of axis selections */ + int *result_order; /* Relative result axis order array pointer */ + int *result_perm; /* Result axis permutation array pointer */ + int *target_assoc; /* Target axis association array pointer */ + int *target_axes1; /* Target axis associations from 1st match */ + int *target_axes2; /* Target axis associations from 2nd match */ + int *template_assoc; /* Template axis association array pointer */ + int *template_axes1; /* Template axis associations, 1st match */ + int *template_axes2; /* Template axis associations, 2nd match */ + int first; /* Axis in 1st component? */ + int full_axis; /* Result Frame axis index, before sub-set */ + int match1; /* First match successful? */ + int match2; /* Second match successful? */ + int match; /* Both matches successful? (result) */ + int match_end1; /* MatchEnd attribute for component 1 */ + int match_end2; /* MatchEnd attribute for component 2 */ + int match_end; /* MatchEnd attribute for template */ + int match_end_set; /* Component MatchEnd attribute set? */ + int output_axis; /* Output axis index */ + int part_result_axis; /* Result Frame component axis index */ + int part_target_axis; /* Target Frame component axis index */ + int part_template_axis; /* Template CmpFrame component axis index */ + int permute_set; /* Component Permute attribute set? */ + int permute_value; /* Component Permute attribute value */ + int preserve_axes; /* Template PreserveAxes attribute value */ + int preserve_axes_set; /* Component PreserveAxes attribute set? */ + int ref_naxes; /* Number of reference Frame axes */ + int result_axis; /* Result Frame axis index */ + int result_naxes1; /* Number of result Frame axes, component 1 */ + int result_naxes2; /* Number of result Frame axes, component 2 */ + int result_naxes; /* Total number of result Frame axes */ + int target_axis; /* Target Frame axis index */ + int target_naxes; /* Number of target Frame axes */ + int template_axis; /* Template CmpFrame axis index */ + int template_naxes1; /* Number of template axes, component 1 */ + int template_naxes; /* Total 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; + +/* Initialise other variables to avoid compiler errors. */ + ref_naxes = 0; + +/* Select the required sub-Frames from the target. */ +/* ----------------------------------------------- */ +/* We first create two sub-Frames (that can be matched against the two + template component Frames) by selecting the two specified sets of + axes from the target. This is done without overlaying any template + attributes. Annul the Mappings produced by this process, as these + are not needed. */ + + frame1 = NULL; + junk_map = NULL; + (void) astSubFrame( target, NULL, naxes1, axes1, NULL, &junk_map, &frame1 ); + if( junk_map ) junk_map = astAnnul( junk_map ); + + frame2 = NULL; + junk_map = NULL; + (void) astSubFrame( target, NULL, naxes2, axes2, NULL, &junk_map, &frame2 ); + if( junk_map ) junk_map = astAnnul( junk_map ); + +/* Match the sub-Frames with the template component Frames. */ +/* -------------------------------------------------------- */ +/* We now have two sub-Frames obtained from the target, and will + attempt to match these with the component Frames contained within + the template CmpFrame. */ + +/* Before using each template component Frame, see whether any of its + attributes that control matching is "un-set". If so, over-ride it + with the attribute value of the template CmpFrame as a whole. */ + match_end_set = astTestMatchEnd( template->frame1 ); + if ( !match_end_set ) { + astSetMatchEnd( template->frame1, astGetMatchEnd( template ) ); + } + preserve_axes_set = astTestPreserveAxes( template->frame1 ); + if ( !preserve_axes_set ) { + astSetPreserveAxes( template->frame1, astGetPreserveAxes( template ) ); + } + +/* We must also temporarily set the Permute attribute to 1 (this is + normally the default, but might have been set otherwise). This is + needed so that permutations of the target axes will be considered. + Without this, the order in which the axes are presented is + significant and we would have to test all the permutations. If the + Permute attribute of the template CmpFrame as a whole is zero, then + the resulting match may still have to be rejected, but this must be + done at a higher level. */ + permute_set = astTestPermute( template->frame1 ); + permute_value = ( permute_set ) ? astGetPermute( template->frame1 ) : 0; + astSetPermute( template->frame1, 1 ); + +/* Test for a match with the first template component Frame. */ + match1 = astMatch( template->frame1, frame1, matchsub, + &template_axes1, &target_axes1, &map1, &result1 ); + +/* Clear the attribute values again afterwards if necessary. */ + if ( !match_end_set ) astClearMatchEnd( template->frame1 ); + if ( !preserve_axes_set ) astClearPreserveAxes( template->frame1 ); + +/* Also restore the original Permute attribute setting. */ + if ( permute_set ) { + astSetPermute( template->frame1, permute_value ); + } else { + astClearPermute( template->frame1 ); + } + +/* Repeat the whole process for the second component Frame. */ + match_end_set = astTestMatchEnd( template->frame2 ); + if ( !match_end_set ) { + astSetMatchEnd( template->frame2, astGetMatchEnd( template ) ); + } + preserve_axes_set = astTestPreserveAxes( template->frame2 ); + if ( !preserve_axes_set ) { + astSetPreserveAxes( template->frame2, astGetPreserveAxes( template ) ); + } + permute_set = astTestPermute( template->frame2 ); + if ( permute_set ) permute_value = astGetPermute( template->frame2 ); + astSetPermute( template->frame2, 1 ); + + match2 = astMatch( template->frame2, frame2, matchsub, + &template_axes2, &target_axes2, &map2, &result2 ); + + if ( !match_end_set ) astClearMatchEnd( template->frame2 ); + if ( !preserve_axes_set ) astClearPreserveAxes( template->frame2 ); + if ( permute_set ) { + astSetPermute( template->frame2, permute_value ); + } else { + astClearPermute( template->frame2 ); + } + +/* See if both matches were successful. */ + if ( astOK && match1 && match2 ) { + match = 1; + +/* Obtain the number of target axes. */ + target_naxes = astGetNaxes( target ); + +/* Obtain the number of axes in each of the result Frames produced by + the matching operation. */ + result_naxes1 = astGetNaxes( result1 ); + result_naxes2 = astGetNaxes( result2 ); + +/* Obtain the number of axes in the first template component Frame and + in the template CmpFrame as a whole. */ + template_naxes1 = astGetNaxes( template->frame1 ); + template_naxes = astGetNaxes( template ); + +/* Obtain the value of the MatchEnd attribute for each of the + template's component Frames and for the template CmpFrame as a + whole. */ + match_end1 = astGetMatchEnd( template->frame1 ); + match_end2 = astGetMatchEnd( template->frame2 ); + match_end = astGetMatchEnd( template ); + +/* Obtain a pointer to the template CmpFrame's axis permutation + array. Allocate space for a further array and fill it with the + inverse of this axis permutation. */ + perm = astGetPerm( template ); + invperm = astMalloc( sizeof( int ) * (size_t) template_naxes ); + if ( astOK ) { + for ( template_axis = 0; template_axis < template_naxes; + template_axis++ ) { + invperm[ perm[ template_axis ] ] = template_axis; + } + } + +/* Generate template and target axis associations. */ +/* ----------------------------------------------- */ +/* We now construct two arrays which identify the axis associations + between the result axes (in the order obtained from the matching + process above) and the axes of the template and target. This + involves tracing back through several steps. */ + +/* First calculate the total number of result axes and allocate memory + for the association arrays. */ + result_naxes = result_naxes1 + result_naxes2; + template_assoc = astMalloc( sizeof( int ) * (size_t) result_naxes ); + target_assoc = astMalloc( sizeof( int ) * (size_t) result_naxes ); + if ( astOK ) { + +/* Produce associations for each result axis in turn. */ + for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) { + +/* Decide whether this result axis is contained in the first (or + second) individual result Frame. */ + first = ( result_axis < result_naxes1 ); + +/* Obtain the index of the axis within the individual result Frame. + This involves adjusting for the axis numbering offset of the second + result Frame if necessary. */ + part_result_axis = first ? result_axis : + result_axis - result_naxes1; + +/* Find the template and target axis associations for this axis by + looking them up in the association arrays returned from the + matching process. This gives axis indices that apply to the + individual template/target Frames supplied as input to the matching + process. */ + part_template_axis = first ? template_axes1[ part_result_axis ] : + template_axes2[ part_result_axis ]; + part_target_axis = first ? target_axes1[ part_result_axis ] : + target_axes2[ part_result_axis ]; + +/* Check that the resulting template association identifies a valid + template axis. */ + if ( part_template_axis != -1 ) { + +/* If so, obtain the template axis index. This involves adjusting for + the axis numbering offset of the second template component Frame + (if necessary) and then applying the inverse template axis + permutation to convert to the external template axis + numbering. Store the result in the template association array. */ + template_assoc[ result_axis ] = + invperm[ first ? part_template_axis : + part_template_axis + template_naxes1 ]; + +/* Indicate if there is no template axis association by storing an + index of -1. */ + } else { + template_assoc[ result_axis ] = -1; + } + +/* Similarly, check that the target association identifies a valid + target axis. */ + if ( part_target_axis != -1 ) { + +/* If so, obtain the target axis index. This simply involves using the + axis selection arrays provided by the caller to look up which + target axes were involved in the matching process. */ + target_assoc[ result_axis ] = + first ? axes1[ part_target_axis ] : + axes2[ part_target_axis ]; + +/* Indicate if there is no target axis association by storing an index + of -1. */ + } else { + target_assoc[ result_axis ] = -1; + } + } + } + +/* Free the inverse axis permutation array. */ + invperm = astFree( invperm ); + +/* Create the output Frame. */ +/* ------------------------ */ +/* Initialise. */ + result_order = NULL; + result_perm = NULL; + +/* Construct the basis of the final result Frame by combining the two + individual result Frames (from the matching process) using a + CmpFrame. */ + if ( astOK ) { + *result = (AstFrame *) astCmpFrame( result1, result2, "", status ); + +/* The next step is to permute the result Frame's axis order so that + it corresponds with the axis order of the "reference Frame". The + reference Frame is either the template or the target, depending on + whether the template's PreserveAxes attribute is non-zero. Obtain + the value of this attribute. */ + preserve_axes = astGetPreserveAxes( template ); + +/* Decide how many axes the reference Frame contains. */ + ref_naxes = preserve_axes ? target_naxes : template_naxes; + +/* Make a copy of the axis association array that refers to the + reference Frame. */ + result_order = astStore( NULL, + preserve_axes ? target_assoc : + template_assoc, + sizeof( int ) * (size_t) result_naxes ); + +/* The intention is to use this axis association array to permute the + result axes into the same order as the reference Frame's axes. It + is not that simple, however, because some of the axis associations + may be null (i.e. result axes may exist that are not associated + with reference axes) and they may also be incomplete (i.e. not + every reference axis may be associated with a result axis). + + This prevents us from permuting the result axis order using this + array directly, essentially because we haven't yet defined where + any "extra" result axes (those with no association) should appear + in the final axis order. */ + +/* To overcome this, we replace all the null (-1) entries in the + "result_order" array with new values which define their position + relative to the other entries. This also involves re-numbering + other entries to avoid clashes. The new numbers assigned depend on + the MatchEnd attribute for each of the template component Frames, + so we handle the associations for each of these components + separately. */ + AddExtraAxes( result_naxes, result_order, + 0, result_naxes1 - 1, match_end1, status ); + AddExtraAxes( result_naxes, result_order, + result_naxes1, result_naxes - 1, match_end2, status ); + +/* There may now be some reference Frame axes which are not referenced + in this array, so we renumber the entries starting at zero (but + preserving their relative order) so that there are no missing + values due to these. */ + RenumberAxes( result_naxes, result_order, status ); + +/* The resulting "result_order" array no longer describes the original + reference Frame axis associations, but is now suitable for + permuting the result axes into the required order. However, we + require the inverse of this permutation, so allocate an array and + fill it with the inverse. */ + result_perm = astMalloc( sizeof( int ) * (size_t) result_naxes ); + if ( astOK ) { + for ( result_axis = 0; result_axis < result_naxes; + result_axis++ ) { + result_perm[ result_order[ result_axis ] ] = result_axis; + } + } + +/* Apply the inverse permutation to the result CmpFrame to put its + axes into the required order. */ + astPermAxes( *result, result_perm ); + +/* Check if the number of result Frame axes differs from the number of + reference axes. This can arise if the PreserveAxes attribute of + either template component Frame is set to a value that differs from + that of the template CmpFrame as a whole. If this is the case, we + must select a sub-set (or super-set) of the result axes, so that we + end up with the same number of axes as the reference Frame. */ + if ( ref_naxes != result_naxes ) { + +/* Allocate an array to hold the indices of the axes required. */ + pick = astMalloc( sizeof( int ) * (size_t) ref_naxes ); + if ( astOK ) { + +/* Generate the axis indices, using the template CmpFrame's MatchEnd + attribute to decide which ones to use. */ + for ( output_axis = 0; output_axis < ref_naxes; + output_axis++ ) { + full_axis = + match_end ? output_axis + ( result_naxes - ref_naxes ) : + output_axis; + +/* If the index is valid (i.e. the required axis is available), store + it. Otherwise, use an index of -1, which requests that new + (default) axes be supplied where needed. */ + if ( ( full_axis >= 0 ) && ( full_axis < result_naxes ) ) { + pick[ output_axis ] = full_axis; + } else { + pick[ output_axis ] = -1; + } + } + } + +/* Pick the required axes from the result Frame and replace it with + the new one. */ + tmp_frame = astPickAxes( *result, ref_naxes, pick, NULL ); + *result = astAnnul( *result ); + *result = tmp_frame; + +/* Free the array of axis indices. */ + pick = astFree( pick ); + } + } + +/* Create output axis association arrays. */ +/* -------------------------------------- */ +/* We now construct the two arrays that are returned to identify which + template and target axes (if any) are associated with each final + result Frame axis. Allocate memory for these arrays. */ + if ( astOK ) { + *target_axes = astMalloc( sizeof( int ) * (size_t) ref_naxes ); + *template_axes = astMalloc( sizeof( int ) * (size_t) ref_naxes ); + if ( astOK ) { + +/* For each output axis, obtain the original result axis index (before + any sub-set or super-set of the output axes was selected). */ + for ( output_axis = 0; output_axis < ref_naxes; output_axis++ ) { + full_axis = + match_end ? output_axis + ( result_naxes - ref_naxes ) : + output_axis; + +/* Derive the result axis index before the axes were permuted into + their final order. */ + if ( ( full_axis >= 0 ) && ( full_axis < result_naxes ) ) { + result_axis = result_perm[ full_axis ]; + +/* Use this axis index and the axis association arrays generated + earlier to obtain the required associations, and store these in the + output arrays. */ + ( *template_axes )[ output_axis ] = + template_assoc[ result_axis ]; + ( *target_axes )[ output_axis ] = + target_assoc[ result_axis ]; + +/* Store a value of -1 if there is no association. */ + } else { + ( *template_axes )[ output_axis ] = -1; + ( *target_axes )[ output_axis ] = -1; + } + } + } + } + +/* Free the original (un-permuted) axis association arrays. */ + template_assoc = astFree( template_assoc ); + target_assoc = astFree( target_assoc ); + +/* Create the output Mapping. */ +/* -------------------------- */ +/* Construct the basis of the final output Mapping by combining the + Mappings produced by the individual matching processes in parallel, + using a CmpMap. */ + *map = (AstMapping *) astCmpMap( map1, map2, 0, "", status ); + +/* It is now necessary to prefix and suffix this CmpMap with two + PermMaps, which correct the input and output axis order to + correspond with the target and result Frame axes. + + At the target end, this reflects the partitioning of the target + axes into two groups, as specified by the caller. At the result + end, it reflects the axis permutation applied (above) to put the + final result Frame axes into the required order, together with the + selection of any sub-set or super-set of these axes. */ + +/* Allocate memory for permutation arrays to describe the prefix + PermMap. */ + inperm = astMalloc( sizeof( int ) * (size_t) target_naxes ); + outperm = astMalloc( sizeof( int ) * (size_t) target_naxes ); + if ( astOK ) { + +/* Consider the target axes in the order that they were supplied to + the matching processes (i.e. the order that corresponds with the + input coordinates of the CmpMap produced above). */ + for ( target_axis = 0; target_axis < target_naxes; target_axis++ ) { + +/* Decide whether each axis belongs to the first (or second) selected + group of target axes. */ + first = ( target_axis < naxes1 ); + +/* Obtain the index of the target axis within the group. This involves + allowing for the numbering offset of the second group if + necessary. */ + part_target_axis = first ? target_axis : + target_axis - naxes1; + +/* Obtain the original target axis index by looking up the axis in the + appropriate axis selection array provided by the caller. */ + outperm[ target_axis ] = first ? axes1[ part_target_axis ] : + axes2[ part_target_axis ]; + +/* Fill the "inperm" array with the inverse of this permutation. */ + inperm[ outperm[ target_axis ] ] = target_axis; + } + } + +/* If the permutation is not null, use these permutation arrays to + construct the required prefix PermMap. */ + if ( GoodPerm( target_naxes, inperm, target_naxes, outperm, status ) ) { + permmap = (AstMapping *) astPermMap( target_naxes, inperm, + target_naxes, outperm, + NULL, "", status ); + +/* Add the PermMap as a prefix to the result Mapping and then annul + the original Mapping pointers. */ + tmp_map = (AstMapping *) astCmpMap( permmap, *map, 1, "", status ); + (void) astAnnul( *map ); + *map = tmp_map; + permmap = astAnnul( permmap ); + } + +/* Free the permutation arrays. */ + inperm = astFree( inperm ); + outperm = astFree( outperm ); + +/* Allocate memory for permutation arrays to describe the suffix + PermMap. */ + inperm = astMalloc( sizeof( int ) * (size_t) result_naxes ); + outperm = astMalloc( sizeof( int ) * (size_t) ref_naxes ); + if ( astOK ) { + +/* Initialise the "inperm" array. */ + for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) { + inperm[ result_axis ] = -1; + } + +/* For each output axis, obtain the index of the corresponding result + axis before any sub-set or super-set was selected. */ + for ( output_axis = 0; output_axis < ref_naxes; output_axis++ ) { + full_axis = + match_end ? output_axis + ( result_naxes - ref_naxes ) : + output_axis; + +/* Store the axis index before the result axes were permuted, and also + construct the inverse permutation. */ + if ( ( full_axis >= 0 ) && ( full_axis < result_naxes ) ) { + outperm[ output_axis ] = result_perm[ full_axis ]; + inperm[ outperm[ output_axis ] ] = output_axis; + +/* Note which output axes do not exist in the result Frame + (e.g. because a super-set was selected). */ + } else { + outperm[ output_axis ] = -1; + } + } + } + +/* If the permutation is not null, use these permutation arrays to + construct the required suffix PermMap. */ + if ( GoodPerm( target_naxes, inperm, target_naxes, outperm, status ) ) { + permmap = (AstMapping *) astPermMap( result_naxes, inperm, + ref_naxes, outperm, + NULL, "", status ); + +/* Add the PermMap as a suffix to the result Mapping and then annul + the original Mapping pointers. */ + tmp_map = (AstMapping *) astCmpMap( *map, permmap, 1, "", status ); + (void) astAnnul( *map ); + *map = tmp_map; + permmap = astAnnul( permmap ); + } + +/* Free the permutation arrays. */ + inperm = astFree( inperm ); + outperm = astFree( outperm ); + +/* Free the result axis permutation arrays. */ + result_order = astFree( result_order ); + result_perm = astFree( result_perm ); + } + +/* If necessary, free the results of the first matching process. */ + if ( match1 ) { + template_axes1 = astFree( template_axes1 ); + target_axes1 = astFree( target_axes1 ); + map1 = astAnnul( map1 ); + result1 = astAnnul( result1 ); + } + +/* If necessary, free the results of the second matching process. */ + if ( match2 ) { + template_axes2 = astFree( template_axes2 ); + target_axes2 = astFree( target_axes2 ); + map2 = astAnnul( map2 ); + result2 = astAnnul( result2 ); + } + +/* Annul the pointers to the sub-Frames selected from the target. */ + frame1 = astAnnul( frame1 ); + frame2 = astAnnul( frame2 ); + +/* If an error occurred, free all allocated memory, annul the result + Object pointers and clear all returned values. */ + if ( !astOK ) { + *template_axes = astFree( *template_axes ); + *target_axes = astFree( *target_axes ); + *map = astAnnul( *map );; + *result = astAnnul( *result ); + match = 0; + } + +/* Return the result. */ + return match; +} + +static void PermAxes( AstFrame *this_frame, const int perm[], int *status ) { +/* +* Name: +* PermAxes + +* Purpose: +* Permute the order of a CmpFrame's axes. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void astPermAxes( AstFrame *this, const int perm[], int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astPermAxes method +* inherited from the Frame class). + +* Description: +* This function permutes the order in which a CmpFrame's axes occur. + +* Parameters: +* this +* Pointer to the CmpFrame. +* perm +* An array of int (with one element for each axis of the +* CmpFrame) 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 a CmpFrame, +* the effects are cumulative. + +* Implementation Notes: +* - This function performs essentially the same operation as the +* Frame member function which it over-rides. However, it operates +* on a "perm" array held in the CmpFrame structure (rather than +* the one in the parent Frame structure). This duplication of the +* array is necessary because the one in the Frame structure is of +* zero length, the number of axes in the Frame structure having +* been set to zero to prevent unnecessary allocation of Axis +* objects which are not needed by the CmpFrame. +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + int *old; /* Pointer to copy of old permutation array */ + int axis; /* Loop counter for CmpFrame axes */ + int naxes; /* Number of CmpFrame axes */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate the permutation array, to check that it describes a + genuine permutation. */ + astCheckPerm( this, perm, "astPermAxes" ); + +/* Obtain the number of CmpFrame axes. */ + naxes = astGetNaxes( this ); + +/* Allocate memory and use it to store a copy of the old permutation + array for the CmpFrame. */ + 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 CmpFrame. */ + 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 void PrimaryFrame( AstFrame *this_frame, int axis1, + AstFrame **frame, int *axis2, int *status ) { +/* +* Name: +* PrimaryFrame + +* Purpose: +* Uniquely identify a primary Frame and one of its axes. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void astPrimaryFrame( AstFrame *this, int axis1, AstFrame **frame, +* int *axis2, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the protected +* astPrimaryFrame method inherited from the Frame class). + +* Description: +* This function returns information about the underlying (primary) +* Frame corresponding to a specified CmpFrame axis. + +* Parameters: +* this +* Pointer to the CmpFrame. +* axis1 +* An axis index (zero-based) identifying the CmpFrame 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). +* status +* Pointer to the inherited status variable. + +* 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. +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + int naxes1; /* Number of axes in frame1 */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis1 = astValidateAxis( this, axis1, 1, "astPrimaryFrame" ); + +/* Obtain the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + if ( astOK ) { + +/* Decide which Frame contains the axis and invoke its astPrimaryFrame + method to obtain the required information. */ + if ( axis1 < naxes1 ) { + astPrimaryFrame( this->frame1, axis1, frame, axis2 ); + } else { + astPrimaryFrame( this->frame2, axis1 - naxes1, frame, axis2 ); + } + } +} + +static int QsortCmpAxes( const void *a, const void *b ) { +/* +* Name: +* QsortCmpAxes + +* Purpose: +* Compare two axis indices for "qsort". + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int QsortCmpAxes( const void *a, const void *b ) + +* Class Membership: +* CmpFrame member function. + +* Description: +* This is a service function for the C RTL routine "qsort". It +* takes the two values supplied and interprets them as integer +* indices into the static "qsort_axes" array. It compares the +* values of these two array elements and returns the result +* required by "qsort". +* +* This function is used when sorting an array of indices so that +* they access the "qsort_axes" array in ascending order. + +* Parameters: +* As required by "qsort". + +* Returned Value: +* As required by "qsort". +*/ + +/* Local Variables. */ + astDECLARE_GLOBALS /* Declare the thread specific global data */ + int result; /* Result value to return */ + int val_a; /* First axis index */ + int val_b; /* Second axis index */ + +/* Get a pointer to the structure holding thread-specific global data. */ + astGET_GLOBALS(NULL); + +/* Convert the values passed by "qsort" into integer array indices and + use these to access the "qsort_axes" array (this pointer to the + array being assigned by the caller of "qsort"). Extract the two + values being compared. */ + val_a = qsort_axes[ *( (const int *) a ) ]; + val_b = qsort_axes[ *( (const int *) b ) ]; + +/* Compare the two values as required by "qsort". */ + if ( val_a < val_b ) { + result = -1; + } else if ( val_a == val_b ) { + result = 0; + } else { + result = 1; + } + +/* 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 "cmpframe.h" +* AstMapping *RemoveRegions( AstMapping *this, int *status ) + +* Class Membership: +* CmpFrame 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 CmpFrame class invokes the +* astRemoveRegions method on the two component Frames, and joins +* the results together into a new CmpFrame. This replaces any Regions +* with their equivalent Frames. + +* 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: */ + AstCmpFrame *new; /* Pointer to new CmpFrame */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstFrame *newfrm1; /* New first component Frame */ + AstFrame *newfrm2; /* New second component Frame */ + AstMapping *result; /* Result pointer to return */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Get a pointer to the CmpFrame. */ + this = (AstCmpFrame *) this_mapping; + +/* Invoke the astRemoveRegions method on the two component Frames. */ + newfrm1 = astRemoveRegions( this->frame1 ); + newfrm2 = astRemoveRegions( this->frame2 ); + +/* If neither component was modified, just return a clone of the supplied + pointer. */ + if( this->frame1 == newfrm1 && this->frame2 == newfrm2 ) { + result = astClone( this ); + +/* Annul new new Frame pointers. */ + newfrm1 = astAnnul( newfrm1 ); + newfrm2 = astAnnul( newfrm2 ); + +/* Otherwise, we need to create a new CmpFrame to return. */ + } else { + +/* Make a copy of the supplied CmpFrame so that the new CmpFrame retains + any attribute settings of the supplied CmpFrame. */ + new = astCopy( this ); + result = (AstMapping *) new; + +/* Replace the two component Frames with the simplified Frames. */ + (void) astAnnul( new->frame1 ); + (void) astAnnul( new->frame2 ); + new->frame1 = (AstFrame *) newfrm1; + new->frame2 = (AstFrame *) newfrm2; + } + +/* Annul the returned Mapping if an error has occurred. */ + if( !astOK ) result = astAnnul( result ); + +/* Return the result. */ + return result; +} + +static void RenumberAxes( int naxes, int axes[], int *status ) { +/* +* Name: +* RenumberAxes + +* Purpose: +* Renumber axis indices to eliminate missing ones. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void RenumberAxes( int naxes, int axes[], int *status ) + +* Class Membership: +* CmpFrame member function. + +* Description: +* This function takes an array containing a list of (zero-based) +* axis indices referring to the axes of a Frame, some of whose +* axes may not be referenced. It renumbers the axis indices, to +* eliminate any which are missing (i.e. not referenced), while +* preserving the original order. It does this by replacing each +* axis index by its rank (starting at zero) when the indices are +* sorted into ascending order. + +* Parameters: +* naxes +* The number of axis indices present. +* axes +* An array, with "naxes" elements, containing the indices. This +* is modified by this function to contain the new indices. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Declare the thread specific global data */ + int *work; /* Pointer to workspace array */ + int i; /* Loop counter */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Get a pointer to the structure holding thread-specific global data. */ + astGET_GLOBALS(NULL); + +/* Allocate workspace. */ + work = astMalloc( sizeof( int ) * (size_t) naxes ); + if ( astOK ) { + +/* Fill the workspace with indices which address the axis index values + in their natural order. */ + for ( i = 0; i < naxes; i++ ) work[ i ] = i; + +/* Make the "axes" values available to the C RTL function "qsort" via + the static "qsort_axes" pointer. Then use "qsort" to permute the + contents of "work" so that it addresses the axis indices in + ascending order. */ + qsort_axes = axes; + qsort( work, (size_t) naxes, sizeof( int ), QsortCmpAxes ); + +/* Use the result to replace each axis index by its rank when sorted + into ascending order (starting with zero). */ + for ( i = 0; i < naxes; i++ ) axes[ work[ i ] ] = i; + } + +/* Free the workspace array. */ + work = astFree( work ); +} + +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 "cmpframe.h" +* void Resolve( AstFrame *this, const double point1[], +* const double point2[], const double point3[], +* double point4[], double *d1, double *d2, int *status ); + +* Class Membership: +* CmpFrame member function (over-rides the astOffset 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 returned 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + const int *perm; /* Pointer to axis permutation array */ + double *p1; /* Permuted coordinates for point1 */ + double *p2; /* Permuted coordinates for point2 */ + double *p3; /* Permuted coordinates for point3 */ + double *p4; /* Permuted coordinates for point4 */ + double d1a; /* Parallel distance in frame1 */ + double d1b; /* Parallel distance in frame2 */ + double d2a; /* Perpendicular distance in frame1 */ + double d2b; /* Perpendicular distance in frame2 */ + double d; /* Total length of basis vector */ + double da; /* Length of basis vector in frame1 */ + double db; /* Length of basis vector in frame2 */ + int axis; /* Loop counter for axes */ + int bad; /* Set bad output coordinates? */ + int naxes1; /* Number of axes in frame1 */ + int naxes; /* Total number of axes in CmpFrame */ + +/* Check the global error status. */ + *d1 = AST__BAD; + *d2 = AST__BAD; + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Obtain the number of axes in the CmpFrame. */ + naxes = astGetNaxes( this ); + +/* Obtain a pointer to the CmpFrame's axis permutation array. */ + perm = astGetPerm( this ); + +/* Allocate workspace. */ + p1 = astMalloc( sizeof( double ) * (size_t) naxes ); + p2 = astMalloc( sizeof( double ) * (size_t) naxes ); + p3 = astMalloc( sizeof( double ) * (size_t) naxes ); + p4 = astMalloc( sizeof( double ) * (size_t) naxes ); + +/* Initialise a flag to indicate whether "bad" coordinates should be + returned. */ + bad = 0; + +/* Initialise ther variables to avoid compiler warnings. */ + da = 0.0; + db = 0.0; + +/* Check that all the coordinates of both input points are OK. If not, + set the "bad" flag and quit checking. */ + if ( astOK ) { + for ( axis = 0; axis < naxes; axis++ ) { + if ( ( point1[ axis ] == AST__BAD ) || + ( point2[ axis ] == AST__BAD ) || + ( point3[ axis ] == AST__BAD ) ) { + bad = 1; + break; + +/* If the coordinates are OK, apply the axis permutation array to + obtain them in the required order. */ + } else { + p1[ perm[ axis ] ] = point1[ axis ]; + p2[ perm[ axis ] ] = point2[ axis ]; + p3[ perm[ axis ] ] = point3[ axis ]; + } + } + } + +/* If OK, obtain the number of axes in the first component Frame. */ + if ( astOK && !bad ) { + naxes1 = astGetNaxes( this->frame1 ); + +/* Find the projection of the required parallel distance into each of the + two Frames. */ + astResolve( this->frame1, p1, p2, p3, p4, &d1a, &d2a ); + astResolve( this->frame2, p1 + naxes1, p2 + naxes1, p3 + naxes1, + p4 + naxes1, &d1b, &d2b ); + +/* Project the first two input points into the two component Frames and + determine the length of the basis vector in each Frame. */ + da = astDistance( this->frame1, p1, p2 ); + db = astDistance( this->frame2, p1 + naxes1, p2 + naxes1 ); + +/* Check that the returned distances are not bad. */ + if ( astOK ) bad = ( bad || ( da == AST__BAD ) || ( db == AST__BAD ) ); + +/* We can tolerate a bad parallel distance within a sub-Frame if the + basis vector has zero length in the sub-Frame, because the bad + parallel distance will have zero weight in the calculation. Set such + bad parallel distanced arbitrarily to zero. */ + if( d1a == AST__BAD && da == 0.0 ) d1a = 0.0; + if( d1b == AST__BAD && db == 0.0 ) d1b = 0.0; + +/* Check that the final parallel distances are not bad. */ + if ( astOK ) bad = ( bad || ( d1a == AST__BAD ) || ( d1b == AST__BAD ) ); + + } + +/* If OK, calculate the total distance between the two points. */ + if ( astOK && !bad ) { + d = sqrt( da * da + db * db ); + +/* If the points are co-incident, then set the "bad" flag. */ + if ( d == 0.0 ) { + bad = 1; + +/* If the points are not co-incident, combine the parallel distances for + the individual Frames into a single parallel distance for the entire + CmpFrame. */ + } else { + *d1 = ( da*d1a + db*d1b )/d; + +/* Offset this distance away from point 1 towards point 2 to get point 4. */ + astOffset( this, point1, point2, *d1, point4 ); + +/* Now find the perpendicular distance (the distance between point4 and + point3). */ + *d2 = astDistance( this, point4, point3 ); + + } + } + +/* Free the workspace arrays. */ + p1 = astFree( p1 ); + p2 = astFree( p2 ); + p3 = astFree( p3 ); + p4 = astFree( p4 ); + +/* If no error has occurred, but bad coordinates must be returned, + then set these in the output array. */ + if ( astOK && bad ) { + *d1 = AST__BAD; + *d2 = AST__BAD; + for ( axis = 0; axis < naxes; axis++ ) point4[ axis ] = AST__BAD; + } + +} + +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 "cmpframe.h" +* AstPointSet *ResolvePoints( AstFrame *this, const double point1[], +* const double point2[], AstPointSet *in, +* AstPointSet *out ) + +* Class Membership: +* CmpFrame member function (over-rides the astResolvePoints method +* inherited from the Frame class). + +* Description: +* This function takes a CmpFrame 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 CmpFrame. +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + AstPointSet *in1; /* Pointer to input PointSet for frame1 */ + AstPointSet *in2; /* Pointer to input PointSet for frame2 */ + AstPointSet *out1; /* Pointer to output PointSet for frame1 */ + AstPointSet *out2; /* Pointer to output PointSet for frame2 */ + AstPointSet *result; /* Pointer to output PointSet */ + const int *perm; /* Pointer to axis permutation array */ + double **ptr_in; /* Pointers to input axis values */ + double **ptr_out1; /* Pointers to frame1 component lengths */ + double **ptr_out2; /* Pointers to frame2 component lengths */ + double **ptr_out; /* Pointers to returned component lengths */ + double *d1; /* Pointer to next parallel component value */ + double *d1_1; /* arallel distance in frame1 */ + double *d1_2; /* Parallel distance in frame2 */ + double *d2; /* Pointer to next perpendicular component value */ + double *d2_1; /* Perpendicular distance in frame1 */ + double *d2_2; /* Perpendicular distance in frame2 */ + double *p1; /* Permuted coordinates for point1 */ + double *p2; /* Permuted coordinates for point2 */ + double *p3; /* Supplied vector */ + double *p4; /* Closest approach to supplied vector */ + double b1; /* Length of basis vector in frame1 */ + double b2; /* Length of basis vector in frame2 */ + double b; /* Length of basis vector */ + int axis; /* Loop counter for axes */ + int ipoint; /* Index of next point */ + int nax; /* Number of Frame axes */ + int naxes1; /* Number of axes in frame1 */ + int naxes2; /* Number of axes in frame2 */ + 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 */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Further initialise to prevent compiler "uninitialised use" messages. */ + d1 = NULL; + d2 = NULL; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Obtain the number of axes in the two component Frames */ + naxes1 = astGetNaxes( this->frame1 ); + naxes2 = astGetNaxes( this->frame2 ); + +/* For the total number of axes. */ + nax = naxes1 + naxes2; + +/* 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; + } + } + +/* Store points to the first two axis arrays in the returned PointSet. */ + ptr_out = astGetPoints( result ); + if( astOK ) { + d1 = ptr_out[ 0 ]; + d2 = ptr_out[ 1 ]; + } + +/* Obtain a pointer to the CmpFrame's axis permutation array. This array + holds the original axis index for each current Frame axis index. */ + perm = astGetPerm( this ); + +/* Temporarily permute the coordinates within the supplied PointSet back + in to the axis order which existed when the CmpFrame was created. */ + astPermPoints( in, 0, perm ); + +/* Extract the axis values relevant to each of the two sub-Frames from the + point1 and point2 arrays, at the same time undoing any axis permutation + applied to the CmpFrame as a whole. */ + p1 = astMalloc( sizeof( double )*( size_t )nax ); + p2 = astMalloc( sizeof( double )*( size_t )nax ); + if( astOK ) { + for( axis = 0; axis < nax; axis++ ) { + p1[ perm[ axis ] ] = point1[ axis ]; + p2[ perm[ axis ] ] = point2[ axis ]; + } + } + +/* Project the first two input points into the two component Frames and + determine the length of the basis vector in each Frame. */ + b1 = astDistance( this->frame1, p1, p2 ); + b2 = astDistance( this->frame2, p1 + naxes1, p2 + naxes1 ); + +/* If either of these distances is bad or if both are zero, then fill the + returned PointSet with bad values. */ + if( b1 == AST__BAD || b2 == AST__BAD || ( b1 == 0.0 && b2 == 0.0 ) ) { + for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) { + *d1 = AST__BAD; + *d2 = AST__BAD; + } + +/* Otherwise we continue to calculate the resolved components */ + } else if( astOK ){ + +/* Calculate the total distance between the two points. */ + b = sqrt( b1*b1 + b2*b2 ); + +/* Create PointSets holding the input values which refer to each of the + two component Frames. */ + in1 = astPointSet( npoint, naxes1, "", status ); + in2 = astPointSet( npoint, naxes2, "", status ); + +/* Associated the appropriate subset of the data in the supplied input + PointSet with each of these two PointSets. */ + astSetSubPoints( in, 0, 0, in1 ); + astSetSubPoints( in, 0, naxes1, in2 ); + +/* Invoke the astResolvePoints method on each of the sub-Frames. These + invocations create two new PointSets containing the output values. */ + out1 = astResolvePoints( this->frame1, p1, p2, in1, NULL ); + out2 = astResolvePoints( this->frame2, p1 + naxes1, p2 + naxes1, in2, NULL ); + +/* Get pointers to the axis values in these pointsets. */ + ptr_out1 = astGetPoints( out1 ); + ptr_out2 = astGetPoints( out2 ); + +/* More work space */ + p3 = astMalloc( sizeof( double )*( size_t )nax ); + p4 = astMalloc( sizeof( double )*( size_t )nax ); + +/* Get pointers to the input axis values (these are still permuted to + undo any axis permutation applied to the CmpFrame). */ + ptr_in = astGetPoints( in ); + +/* Check pointers can be used safely. */ + if( astOK ) { + +/* Get pointers to the parallel (d1) and perpendiclar (d2) components + within the two sub-Frames (_1 and _2). */ + d1_1 = ptr_out1[ 0 ]; + d2_1 = ptr_out1[ 1 ]; + d1_2 = ptr_out2[ 0 ]; + d2_2 = ptr_out2[ 1 ]; + +/* Loop round each supplied vector. */ + for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++, + d1_1++, d2_1++, + d1_2++, d2_2++ ) { + +/* We can tolerate a bad parallel distance within a sub-Frame if the + basis vector has zero length in the sub-Frame, because the bad + parallel distance will have zero weight in the calculation. Set such + bad parallel distanced arbitrarily to zero. */ + if( *d1_1 == AST__BAD && b1 == 0.0 ) *d1_1 = 0.0; + if( *d1_2 == AST__BAD && b2 == 0.0 ) *d1_2 = 0.0; + +/* Combine the parallel distances for the individual Frames into a single + parallel distance for the entire CmpFrame. */ + if( *d1_1 != AST__BAD && *d1_2 != AST__BAD ) { + *d1 = ( b1*(*d1_1) + b2*(*d1_2) )/b; + +/* Offset this distance away from point 1 towards point 2 to get point 4. */ + astOffset( this, p1, p2, *d1, p4 ); + +/* Now find the perpendicular distance (the distance between point4 and + point3). */ + for( axis = 0; axis < nax; axis++ ) p3[ axis ] = ptr_in[ axis ][ ipoint ]; + *d2 = astDistance( this, p4, p3 ); + + } else { + *d1 = AST__BAD; + *d2 = AST__BAD; + } + } + } + +/* Free resources */ + in1 = astAnnul( in1 ); + in2 = astAnnul( in2 ); + out1 = astAnnul( out1 ); + out2 = astAnnul( out2 ); + p3 = astFree( p3 ); + p4 = astFree( p4 ); + } + +/* Free resources */ + p1 = astFree( p1 ); + p2 = astFree( p2 ); + +/* Re-instate the original ordering of the coordinates within the + supplied PointSet. */ + astPermPoints( in, 1, perm ); + +/* 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_frame, int value, int *status ){ +/* +* Name: +* SetActiveUnit + +* Purpose: +* Specify how the Unit attribute should be used. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetActiveUnit( AstFrame *this, int value, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSetActiveUnit method +* inherited from the Frame class). + +* Description: +* This function sets the current value of the ActiveUnit flag for a +* CmpFrame, which controls how the Frame behaves when it is used (by +* astFindFrame) as a template to match another (target) Frame, or is +* used as the "to" Frame by astConvert. It determines if the Mapping +* between the template and target Frames should take differences in +* axis units into account. + +* Parameters: +* this +* Pointer to the CmpFrame. +* value +* The new value to use. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Invoke the parent method to set the ActiveUnitFlag for the CmpFrame, + then set the same value for the component Frames. */ + (*parent_setactiveunit)( this_frame, value, status ); + astSetActiveUnit( ((AstCmpFrame *)this_frame)->frame1, value ); + astSetActiveUnit( ((AstCmpFrame *)this_frame)->frame2, value ); +} + +static void SetFrameFlags( AstFrame *this_frame, int value, int *status ){ +/* +* Name: +* SetFrameFlags + +* Purpose: +* Set flags that control current Frame behaviour. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetFrameFlags( AstFrame *this, int value, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSetFrameFlags method +* inherited from the Frame class). + +* Description: +* This function sets values for the bit mask of flags that control +* how the CmpFrame behaves. It ensures that both component Frames use +* the the same bitmask as the parent CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* value +* The new value to use. +* status +* Pointer to the inherited status variable. +*/ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Invoke the parent method to set the FrameFlags for the CmpFrame, + then set the same value for the component Frames. */ + (*parent_setframeflags)( this_frame, value, status ); + astSetFrameFlags( ((AstCmpFrame *)this_frame)->frame1, value ); + astSetFrameFlags( ((AstCmpFrame *)this_frame)->frame2, value ); +} + +static int GetActiveUnit( AstFrame *this_frame, int *status ){ +/* +* Name: +* GetActiveUnit + +* Purpose: +* Determines how the Unit attribute will be used. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int GetActiveUnit( AstFrame *this_frame, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astGetActiveUnit method +* inherited from the Frame class). + +* Description: +* This function returns the current value of the ActiveUnit flag for a +* CmpFrame. See the description of the astSetActiveUnit function +* for a description of the ActiveUnit flag. + +* Parameters: +* this +* Pointer to the CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The current value of the ActiveUnit flag. + +*/ + +/* Local Variables; */ + int result; /* The ActiveUnit flag for the CmpFrame */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* If the ActiveUnit value has been set for the CmpFrame use the parent + implementation to get its value. */ + if( astTestActiveUnit( this_frame ) ) { + result = (*parent_getactiveunit)( this_frame, status ); + +/* Otherwise, the default is determined by the component Frames. If both + components have active units, the default for the CmpFrame is "on" */ + } else { + result = astGetActiveUnit( ((AstCmpFrame *)this_frame)->frame1 ) || + astGetActiveUnit( ((AstCmpFrame *)this_frame)->frame2 ); + } + +/* 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 CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetAttrib( AstObject *this, const char *setting, int *status ) + +* Class Membership: +* CmpFrame member function (extends the astSetAttrib method inherited from +* the Mapping class). + +* Description: +* This function assigns an attribute value for a CmpFrame, 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 CmpFrame. +* 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. +*/ + +#define BUF_LEN 1024 + +/* Local Vaiables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + AstFrame *pfrm; /* Pointer to primary Frame containing axis */ + char buf1[BUF_LEN]; /* For for un-indexed attribute name */ + char buf2[BUF_LEN]; /* For for indexed attribute name */ + int axis; /* Supplied (1-base) axis index */ + int len; /* Length of setting string */ + int nc; /* Number of characters read by astSscanf */ + int oldrep; /* Original error reporting state */ + int paxis; /* Index of primary Frame axis */ + int ok; /* Have we accessed the attribute succesfully? */ + int value; /* Offset to start fo value string */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_object; + +/* Obtain the length of the setting string. */ + len = strlen( setting ); + +/* Indicate we have not yet acessed the attribute succesfully. */ + ok = 0; + +/* First check the supplied attribute name against each of the attribute + names defined by this class. In fact there is nothing to do here + since the CmpFrame class currently defines no extra attributes, but + this may change in the future. */ + if( 0 ) { + + + +/* If the attribute is not a CmpFrame specific attribute... */ + } else if( astOK ) { + +/* We want to allow easy access to the attributes of the component Frames. + That is, we do not want it to be necessary to extract a Frame from + its parent CmpFrame in order to access its attributes. For this reason + we first temporarily switch off error reporting so that if an attempt + to access the attribute fails, we can try a different approach. */ + oldrep = astReporting( 0 ); + +/* Our first attempt is to see if the attribute is recognised by the parent + class (Frame). */ + (*parent_setattrib)( this_object, setting, status ); + +/* Indicate success. */ + if( astOK ) { + ok = 1; + +/* Otherwise, clear the error condition so that we can try a different + approach. */ + } else { + astClearStatus; + +/* If the attribute is qualified by an axis index, try accessing it as an + attribute of the primary Frame containing the specified index. */ + if ( nc = 0, + ( 2 == astSscanf( setting, "%[^(=](%d)= %n%*s %n", buf1, &axis, + &value, &nc ) ) && ( nc >= len ) ) { + +/* Find the primary Frame containing the specified axis. */ + astPrimaryFrame( this, axis - 1, &pfrm, &paxis ); + if( astOK ) { + +/* 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" ); + +/* Create a new setting with the same name but with the axis index + appropriate to the primary Frame. */ + nc = sprintf( buf2, "%s(%d)=%s", buf1, paxis + 1, + setting+value ); + if( nc < BUF_LEN ) { + +/* Attempt to access the attribute. */ + astSetAttrib( pfrm, buf2 ); + +/* Indicate success. */ + if( astOK ) { + ok = 1; + +/* Otherwise clear the status value, and try again without any axis index. */ + } else { + astClearStatus; + sprintf( buf2, "%s=%s", buf1, setting+value ); + astSetAttrib( pfrm, buf2 ); + +/* Indicate success, or clear the status value. */ + if( astOK ) { + ok = 1; + } else { + astClearStatus; + } + } + +/* Buffer overflow */ + } else if( astOK ) { + astError( AST__INTER, "SetAttrib(CmpFrame): Buffer " + "over-flow (internal AST programming error).", + status ); + } + +/* Free the primary frame pointer. */ + pfrm = astAnnul( pfrm ); + } + +/* If the attribute is not qualified by an axis index, try accessing it + using the primary Frame of each axis in turn. */ + } else { + +/* Loop round all axes attribute. */ + for( axis = 0; axis < astGetNaxes( this ); axis++ ) { + +/* Get the primary Frame containing this axis. */ + astPrimaryFrame( this, axis, &pfrm, &paxis ); + +/* Attempt to access the attribute as an attribute of the primary Frame. */ + astSetAttrib( pfrm, setting ); + +/* Free the primary Frame pointer. */ + pfrm = astAnnul( pfrm ); + +/* Indicate success, or clear the status value. */ + if( astOK ) { + ok = 1; + } else { + astClearStatus; + } + } + } + } + +/* Re-instate the original error reporting state. */ + astReporting( oldrep ); + + } + +/* Report an error if the attribute could not be accessed. */ + if( !ok && astOK ) { + astError( AST__BADAT, "astSet: The attribute setting \"%s\" is invalid " + "for the given %s.", status, setting, astGetClass( this ) ); + } + +#undef BUF_LEN +} + +static void SetAxis( AstFrame *this_frame, int axis, AstAxis *newaxis, int *status ) { +/* +* Name: +* SetAxis + +* Purpose: +* Set a new Axis for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void astSetAxis( AstFrame *this, int axis, AstAxis *newaxis, int *status ) + +* Class Membership: +* CmpFrame 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 a CmpFrame, replacing the previous one. Each Axis +* object contains a description of the quantity represented along +* one of the CmpFrame's axes, so this function allows this +* description to be exchanged for another one. + +* Parameters: +* this +* Pointer to the CmpFrame. +* axis +* The index (zero-based) of the CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + int naxes1; /* Number of axes in frame1 */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis = astValidateAxis( this, axis, 1, "astSetAxis" ); + +/* Determine the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + if ( astOK ) { + +/* Decide which Frame contains the axis and invoke its astSetAxis + method to set the new Axis. */ + if ( axis < naxes1 ) { + astSetAxis( this->frame1, axis, newaxis ); + } else { + astSetAxis( this->frame2, axis - naxes1, newaxis ); + } + } +} + +static void SetDtai( AstFrame *this_frame, double val, int *status ) { +/* +* Name: +* SetDtai + +* Purpose: +* Set the value of the Dtai attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetDtai( AstFrame *this, double val, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSetDtai method +* inherited from the Frame class). + +* Description: +* This function sets the Dtai value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* val +* New Dtai value. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to set the CmpFrame Dtai value. */ + (*parent_setdtai)( this_frame, val, status ); + +/* Now set the Dtai attribute in the two component Frames. */ + astSetDtai( this->frame1, val ); + astSetDtai( this->frame2, val ); +} + +static void SetDut1( AstFrame *this_frame, double val, int *status ) { +/* +* Name: +* SetDut1 + +* Purpose: +* Set the value of the Dut1 attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetDut1( AstFrame *this, double val, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSetDut1 method +* inherited from the Frame class). + +* Description: +* This function sets the Dut1 value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* val +* New Dut1 value. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to set the CmpFrame Dut1 value. */ + (*parent_setdut1)( this_frame, val, status ); + +/* Now set the Dut1 attribute in the two component Frames. */ + astSetDut1( this->frame1, val ); + astSetDut1( this->frame2, val ); +} + +static void SetEpoch( AstFrame *this_frame, double val, int *status ) { +/* +* Name: +* SetEpoch + +* Purpose: +* Set the value of the Epoch attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetEpoch( AstFrame *this, double val, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSetEpoch method +* inherited from the Frame class). + +* Description: +* This function sets the Epoch value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* val +* New Epoch value. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to set the CmpFrame epoch. */ + (*parent_setepoch)( this_frame, val, status ); + +/* Now set the Epoch attribute in the two component Frames. */ + astSetEpoch( this->frame1, val ); + astSetEpoch( this->frame2, val ); +} + +static void SetObsAlt( AstFrame *this_frame, double val, int *status ) { +/* +* Name: +* SetObsAlt + +* Purpose: +* Set the value of the ObsAlt attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetObsAlt( AstFrame *this, double val, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSetObsAlt method +* inherited from the Frame class). + +* Description: +* This function sets the ObsAlt value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* val +* New ObsAlt value. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to set the CmpFrame ObsAlt. */ + (*parent_setobsalt)( this_frame, val, status ); + +/* Now set the ObsAlt attribute in the two component Frames. */ + astSetObsAlt( this->frame1, val ); + astSetObsAlt( this->frame2, val ); +} + +static void SetObsLat( AstFrame *this_frame, double val, int *status ) { +/* +* Name: +* SetObsLat + +* Purpose: +* Set the value of the ObsLat attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetObsLat( AstFrame *this, double val, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSetObsLat method +* inherited from the Frame class). + +* Description: +* This function sets the ObsLat value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* val +* New ObsLat value. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to set the CmpFrame ObsLat. */ + (*parent_setobslat)( this_frame, val, status ); + +/* Now set the ObsLat attribute in the two component Frames. */ + astSetObsLat( this->frame1, val ); + astSetObsLat( this->frame2, val ); +} + +static void SetObsLon( AstFrame *this_frame, double val, int *status ) { +/* +* Name: +* SetObsLon + +* Purpose: +* Set the value of the ObsLon attribute for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* void SetObsLon( AstFrame *this, double val, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSetObsLon method +* inherited from the Frame class). + +* Description: +* This function sets the ObsLon value in the component Frames as +* well as this CmpFrame. + +* Parameters: +* this +* Pointer to the CmpFrame. +* val +* New ObsLon value. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Invoke the parent method to set the CmpFrame ObsLon. */ + (*parent_setobslon)( this_frame, val, status ); + +/* Now set the ObsLon attribute in the two component Frames. */ + astSetObsLon( this->frame1, val ); + astSetObsLon( this->frame2, val ); +} + +static AstMapping *Simplify( AstMapping *this_mapping, int *status ) { +/* +* Name: +* Simplify + +* Purpose: +* Simplify the Mapping represented by a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* AstMapping *Simplify( AstMapping *this, int *status ) + +* Class Membership: +* CmpFrame method (over-rides the astSimplify method inherited +* from the Frame class). + +* Description: +* This function simplifies the Mapping represented by a CmpFrame, +* by using the astSimplify method on each of the component Frames and +* combining the resulting Mappings together. + +* Parameters: +* this +* Pointer to the original CmpFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A new pointer to the simplified CmpFrame. + +* 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: */ + AstCmpFrame *new; /* Pointer to new CmpFrame structure */ + AstCmpFrame *this; /* Pointer to original CmpFrame structure */ + AstMapping *map1; /* Intermediate Mapping */ + AstMapping *map2; /* Intermediate Mapping */ + AstMapping *result; /* Result pointer to return */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_mapping; + +/* Simplify each of the component Frames. */ + map1 = astSimplify( this->frame1 ); + map2 = astSimplify( this->frame2 ); + +/* Did any usable simplification occur? */ + if( astIsAFrame( map1 ) && astIsAFrame( map2 ) && + ( map1 != (AstMapping *) this->frame1 || + map2 != (AstMapping *) this->frame2 ) ) { + +/* Make a copy of the supplied CmpFrame. */ + new = astCopy( this ); + result = (AstMapping *) new; + +/* Replace the two component Frames with the simplified Frames. */ + (void) astAnnul( new->frame1 ); + (void) astAnnul( new->frame2 ); + new->frame1 = (AstFrame *) map1; + new->frame2 = (AstFrame *) map2; + +/* If no simplication took place, annul the Mapping pointers and return a + clone of the supplied pointer. */ + } else { + map1 = astAnnul( map1 ); + map2 = astAnnul( map2 ); + result= astClone( this ); + } + +/* If an error occurred, annul the returned pointer. */ + if ( !astOK ) result = astAnnul( result ); + +/* Return the result. */ + return result; +} + +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 "cmpframe.h" +* AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) + +* Class Membership: +* CmpFrame 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 CmpFrame +* 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 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 */ + +/* 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 CmpFrame class only supports a single system "Compound". */ + if ( astChrMatch( "Compound", system ) ) { + result = AST__COMP; + } + +/* 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 "cmpframe.h" +* const char *SystemString( AstFrame *this, AstSystemType system, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astSystemString method +* inherited from the Frame class). + +* Description: +* This function converts a CmpFrame 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 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 + CmpFrame only allows a single System value, "Compound". */ + switch ( system ) { + case AST__COMP: + result = "Compound"; + 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 CmpFrame and convert to the new coordinate system. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.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: +* CmpFrame 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" CmpFrame 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 CmpFrame, 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 CmpFrame. 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 CmpFrame 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: */ + AstCmpFrame *target; /* Pointer to target CmpFrame structure */ + AstFrame *sub_result1; /* Pointer to result Frame for frame1 */ + AstFrame *sub_result2; /* Pointer to result Frame for frame2 */ + AstMapping *permmap_pref; /* Pointer to PermMap used as a prefix */ + AstMapping *permmap_suff; /* Pointer to PermMap used as a suffix */ + AstMapping *sub_map1; /* Pointer to Mapping from frame1 */ + AstMapping *sub_map2; /* Pointer to Mapping from frame2 */ + AstMapping *sub_map; /* Pointer to combined component Mappings */ + AstMapping *tmp_map; /* Temporary Mapping pointer */ + const int *perm; /* Pointer to axis permutation array */ + int *frame_choice; /* Pointer to flag array for partitioning */ + int *inperm_pref; /* Pointer to prefix permutation array */ + int *inperm_suff; /* Pointer to suffix permutation array */ + int *outperm_pref; /* Pointer to prefix permutation array */ + int *outperm_suff; /* Pointer to suffix permutation array */ + int *target_axes1; /* Pointer to frame1 axis selection array */ + int *target_axes2; /* Pointer to frame2 axis selection array */ + int *template_axes1; /* Pointer to frame1 template axis array */ + int *template_axes2; /* Pointer to frame2 template axis array */ + int axis_p; /* Permuted axis index */ + int following; /* Associate extra axis and following axis? */ + int i1; /* Count of axes obtained from frame1 */ + int i2; /* Count of axes obtained from frame2 */ + int match; /* Result value to return */ + int n1; /* Number of axes obtained from frame1 */ + int n2; /* Number of axes obtained from frame2 */ + int naxes1; /* Number of axes in frame1 */ + int naxes2; /* Number of axes in frame2 */ + int naxes; /* Number of axes in target */ + int result_axis; /* Result axis index */ + int target_axis; /* Target axis index */ + +/* 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 CmpFrame structure. */ + target = (AstCmpFrame *) target_frame; + +/* Obtain the number of axes in the target CmpFrame and in each of its + component Frames. */ + naxes = astGetNaxes( target ); + naxes1 = astGetNaxes( target->frame1 ); + naxes2 = astGetNaxes( target->frame2 ); + +/* Iinitialise variables to avoid compiler warnings. */ + template_axes1 = NULL; + template_axes2 = NULL; + n1 = 0; + n2 = 0; + +/* Obtain the axis permutation array for the target CmpFrame. */ + perm = astGetPerm( target ); + +/* Determine how any "extra" axes should be associated with existing + axes (i.e. whether to associate with the preceding or following + axis). */ + following = astGetMatchEnd( target ); + +/* Split selected axes into two groups. */ +/* ------------------------------------ */ +/* Allocate a workspace array to hold the choice of component Frame + for each selected target axis. */ + frame_choice = astMalloc( sizeof( int ) * (size_t) result_naxes ); + +/* Obtain an array of flags indicating whether each selected target + axis should be obtained from the first or second component + Frame. */ + PartitionSelection( result_naxes, target_axes, perm, naxes1, naxes2, + frame_choice, following, status ); + +/* Allocate two arrays to hold the axis indices that refer to each of + the component Frames. The maximum number of indices is given by + "result_naxes" (if all the selected axes come from one component + Frame alone). */ + target_axes1 = astMalloc( sizeof( int ) * (size_t) result_naxes ); + target_axes2 = astMalloc( sizeof( int ) * (size_t) result_naxes ); + +/* If a template Frame has been provided, allocate similar arrays to + hold the indices of the two groups of template axes. */ + if ( template ) { + template_axes1 = astMalloc( sizeof( int ) * (size_t) result_naxes ); + template_axes2 = astMalloc( sizeof( int ) * (size_t) result_naxes ); + } + +/* Initialise the count of axes selected from each component Frame. */ + if ( astOK ) { + n1 = n2 = 0; + +/* Loop through each axis index to be selected from the CmpFrame. */ + for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) { + target_axis = target_axes[ result_axis ]; + +/* Determine if the index refers to a valid CmpFrame axis. If it does, + then permute the index, otherwise set it to -1. */ + if ( ( target_axis >= 0 ) && ( target_axis < naxes ) ) { + axis_p = perm[ target_axis ]; + } else { + axis_p = -1; + } + +/* If the axis is to be selected from the first component Frame, store + the index of the axis to be selected. Also store the associated + template axis index (if any). */ + if ( frame_choice[ result_axis ] == 1 ) { + target_axes1[ n1 ] = axis_p; + if ( template ) { + template_axes1[ n1 ] = template_axes[ result_axis ]; + } + +/* Count the axes selected from the first component Frame. */ + n1++; + +/* If the axis is to be selected from the second component Frame, + store the index of the index to be selected (adjusting for the + offset in axis numbering). Also store the associated template axis + index (if any) and count the axes selected. */ + } else { + target_axes2[ n2 ] = ( axis_p == -1 ) ? -1 : axis_p - naxes1; + if ( template ) { + template_axes2[ n2 ] = template_axes[ result_axis ]; + } + n2++; + } + } + } + +/* Select from first component Frame only. */ +/* --------------------------------------- */ +/* If all the selected axes come from the first component Frame, use + that Frame's astSubFrame method to select them (and overlay the + template attributes if required). */ + if ( astOK ) { + if ( n1 && !n2 ) { + sub_map1 = NULL; + match = astSubFrame( target->frame1, template, n1, target_axes1, + template_axes1, &sub_map1, result ); + +/* If this is successful, the "result" Frame will be ready to return + and "sub_map1" will point at a Mapping that converts from the first + component Frame to the "result" Frame. We must now modify this + mapping to account for the CmpFrame's axis permutation array + (i.e. make it refer back to the CmpFrame's original axis order). */ + if ( astOK && match ) { + +/* To do this we must prefix the Mapping with a PermMap which converts + between the target CmpFrame axes and those of the first component + Frame. Allocate space for the permutation arrays required. */ + inperm_pref = astMalloc( sizeof( int ) * (size_t) naxes ); + outperm_pref = astMalloc( sizeof( int ) * (size_t) naxes1 ); + if ( astOK ) { + +/* Permute each target axis index. */ + for ( target_axis = 0; target_axis < naxes; target_axis++ ) { + axis_p = perm[ target_axis ]; + +/* Set up arrays that describe this permutation and its inverse. */ + if ( axis_p < naxes1 ) { + inperm_pref[ target_axis ] = axis_p; + outperm_pref[ axis_p ] = target_axis; + +/* Note which target axes do not correspond with axes in the first + component Frame and assign -1 (so the PermMap will assign "bad" + coordinate values to these axes). */ + } else { + inperm_pref[ target_axis ] = -1; + } + } + +/* Use these permutation arrays to construct the PermMap. Prefix this + to the Mapping obtained earlier to give the final Mapping to be + returned. */ + permmap_pref = + (AstMapping *) astPermMap( naxes, inperm_pref, + naxes1, outperm_pref, NULL, "", status ); + *map = (AstMapping *) astCmpMap( permmap_pref, sub_map1, 1, "", status ); + +/* Annul the PermMap pointer. */ + permmap_pref = astAnnul( permmap_pref ); + } + +/* Free the permutation arrays and annul the original Mapping pointer. */ + inperm_pref = astFree( inperm_pref ); + outperm_pref = astFree( outperm_pref ); + sub_map1 = astAnnul( sub_map1 ); + } + +/* Select from second component Frame only. */ +/* ---------------------------------------- */ +/* If all the selected axes come from the second component Frame, use + that Frame's astSubFrame method to select them (and overlay the + template attributes if required). */ + } else if ( n2 && !n1 ) { + sub_map2 = NULL; + match = astSubFrame( target->frame2, template, n2, target_axes2, + template_axes2, &sub_map2, result ); + +/* If this is successful, the "result" Frame will be ready to return + and "sub_map2" will point at a Mapping that converts from the second + component Frame to the "result" Frame. We must now modify this + mapping to account for the CmpFrame's axis permutation array + (i.e. make it refer back to the CmpFrame's original axis order). */ + if ( astOK && match ) { + +/* To do this we must prefix the Mapping with a PermMap which converts + between the target CmpFrame axes and those of the second component + Frame. Allocate space for the permutation arrays required. */ + inperm_pref = astMalloc( sizeof( int ) * (size_t) naxes ); + outperm_pref = astMalloc( sizeof( int ) * (size_t) naxes2 ); + if ( astOK ) { + +/* Permute each target axis index. */ + for ( target_axis = 0; target_axis < naxes; target_axis++ ) { + axis_p = perm[ target_axis ]; + +/* Set up arrays that describe this permutation and its inverse, + allowing for the shift in axis numbering for the second component + Frame. */ + if ( axis_p >= naxes1 ) { + inperm_pref[ target_axis ] = axis_p - naxes1; + outperm_pref[ axis_p - naxes1 ] = target_axis; + +/* Note which target axes do not correspond with axes in the second + component Frame and assign -1 (so the PermMap will assign "bad" + coordinate values to these axes). */ + } else { + inperm_pref[ target_axis ] = -1; + } + } + +/* Use these permutation arrays to construct the PermMap. Prefix this + to the Mapping obtained earlier to give the final Mapping to be + returned. */ + permmap_pref = + (AstMapping *) astPermMap( naxes, inperm_pref, + naxes2, outperm_pref, NULL, "", status ); + + *map = (AstMapping *) astCmpMap( permmap_pref, sub_map2, 1, "", status ); + +/* Annul the PermMap pointer. */ + permmap_pref = astAnnul( permmap_pref ); + } + +/* Free the permutation arrays and annul the original Mapping pointer. */ + inperm_pref = astFree( inperm_pref ); + outperm_pref = astFree( outperm_pref ); + sub_map2 = astAnnul( sub_map2 ); + } + +/* Select from both component Frames. */ +/* ---------------------------------- */ +/* If the selected axes come from both component Frames, then use both + Frames' astSubFrame methods to select the required axes from each + of them (and overlay the template attributes if required). */ + } else { + sub_map1 = NULL; + sub_map2 = NULL; + sub_result1 = NULL; + sub_result2 = NULL; + match = astSubFrame( target->frame1, template, n1, target_axes1, + template_axes1, &sub_map1, &sub_result1 ); + if ( match ) { + match = astSubFrame( target->frame2, template, n2, target_axes2, + template_axes2, &sub_map2, &sub_result2 ); + } + +/* If this is successful, the two "result" Frames will need to be + combined together (in a CmpFrame) in order to produce the required + result, and the two accompanying Mappings will also need to be + applied in parallel (in a CmpMap). However, the axis order + resulting from this will still not match that required. + + On the target side, this is because of the target's axis + permutation array. On the result side, it is because the result + axes cannot be inter-mingled (as may be required) simply by joining + the Frames and Mappings in parallel. The resulting CmpFrame axes + will therefore need permuting into the required final order. */ + if ( astOK && match ) { + +/* In addition, the Mappings will need to be both prefixed and + suffixed with suitable PermMaps which re-order the axes. Allocate + space for the permutation arrays required. */ + inperm_pref = astMalloc( sizeof( int ) * (size_t) naxes ); + outperm_pref = astMalloc( sizeof( int ) * (size_t) naxes ); + inperm_suff = astMalloc( sizeof( int ) * (size_t) result_naxes ); + outperm_suff = astMalloc( sizeof( int ) * (size_t) result_naxes ); + if ( astOK ) { + +/* Set up permutation arrays to construct the prefix PermMap. This + simply represents the target CmpFrame's axis permutation array and + its inverse. */ + for ( target_axis = 0; target_axis < naxes; target_axis++ ) { + axis_p = perm[ target_axis ]; + inperm_pref[ target_axis ] = axis_p; + outperm_pref[ axis_p ] = target_axis; + } + +/* Set up permutation arrays to construct the suffix PermMap. This + represents the way the original axis selections were partitioned + between the two component frames. */ + i1 = i2 = 0; + for ( result_axis = 0; result_axis < result_naxes; + result_axis++ ) { + +/* For each result axis derived from the first component Frame, set up + permutation array elements to link the output axis with the next + component Frame axis. Count the number of component Frame axes + used. */ + if ( frame_choice[ result_axis ] == 1 ) { + inperm_suff[ i1 ] = result_axis; + outperm_suff[ result_axis ] = i1; + i1++; + +/* Similarly link the axes derived from the second component Frame + with the appropriate axes of that Frame. */ + } else { + inperm_suff[ n1 + i2 ] = result_axis; + outperm_suff[ result_axis ] = n1 + i2; + i2++; + } + } + +/* Combine the Mappings supplied by the two component Frames in + parallel. */ + sub_map = (AstMapping *) astCmpMap( sub_map1, sub_map2, 0, "", status ); + +/* Create the PermMaps which are to be used as a prefix and a suffix. */ + permmap_pref = + (AstMapping *) astPermMap( naxes, inperm_pref, + naxes, outperm_pref, NULL, "", status ); + permmap_suff = + (AstMapping *) astPermMap( result_naxes, inperm_suff, + result_naxes, outperm_suff, + NULL, "", status ); + +/* Add the prefix and suffix PermMaps. */ + tmp_map = (AstMapping *) astCmpMap( permmap_pref, sub_map, + 1, "", status ); + *map = (AstMapping *) astCmpMap( tmp_map, permmap_suff, 1, "", status ); + +/* Annul the Mapping pointers that are no longer required. */ + sub_map = astAnnul( sub_map ); + permmap_pref = astAnnul( permmap_pref ); + permmap_suff = astAnnul( permmap_suff ); + tmp_map = astAnnul( tmp_map ); + +/* Create the result CmpFrame by combining the two component result + Frames and permuting the resulting axes into the required order. */ + *result = (AstFrame *) astCmpFrame( sub_result1, sub_result2, + "", status ); + astPermAxes( *result, outperm_suff ); + +/* ADDED BY DSB (5-FEB-2001). Without this, properties of the target frame + (most importantly, Domain) are not transferred to the result frame. + This results in Frames not matching which should match. + =================================================================== */ + +/* If the result CmpFrame includes all the axes of the target CmpFrame, + then it should inherit any Domain and Title attributes set in the target + CmpFrame. */ + if( result_naxes == naxes ) { + + if( astTestDomain( target ) ) { + astSetDomain( *result, astGetDomain( target ) ); + } + + if( astTestTitle( target ) ) { + astSetTitle( *result, astGetTitle( target ) ); + } + } + +/* End of DSB insertion (5/2/01). + =================================================================== */ + } + +/* Free the temporary permutation arrays. */ + inperm_pref = astFree( inperm_pref ); + inperm_suff = astFree( inperm_suff ); + outperm_pref = astFree( outperm_pref ); + outperm_suff = astFree( outperm_suff ); + } + +/* Annul the Mapping and Frame pointers obtained from each component + Frame. */ + if( sub_map1 ) sub_map1 = astAnnul( sub_map1 ); + if( sub_map2 ) sub_map2 = astAnnul( sub_map2 ); + if( sub_result1 ) sub_result1 = astAnnul( sub_result1 ); + if( sub_result2 ) sub_result2 = astAnnul( sub_result2 ); + } + } + +/* Free the workspace used to store the choice of component Frame and the + axis indices for each component Frame. */ + frame_choice = astFree( frame_choice ); + target_axes1 = astFree( target_axes1 ); + target_axes2 = astFree( target_axes2 ); + +/* If necessary, also free the memory used for the template axis + indices. */ + if ( template ) { + template_axes1 = astFree( template_axes1 ); + template_axes2 = astFree( template_axes2 ); + } + +/* 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; +} + +static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* TestAttrib + +* Purpose: +* Test if a specified attribute value is set for a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int TestAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* CmpFrame 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 CmpFrame's attributes. + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + AstFrame *pfrm; /* Pointer to primary Frame containing axis */ + char buf1[80]; /* For for un-indexed attribute name */ + char buf2[80]; /* For for indexed attribute name */ + int axis; /* Supplied (1-base) axis index */ + int len; /* Length of attrib string */ + int nc; /* Length of string used so far */ + int oldrep; /* Original error reporting state */ + int paxis; /* Index of primary Frame axis */ + int result; /* Result value to return */ + int ok; /* Has the attribute been accessed succesfully? */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_object; + +/* Obtain the length of the attrib string. */ + len = strlen( attrib ); + +/* Indicate we have not yet acessed the attribute succesfully. */ + ok = 0; + +/* First check the supplied attribute name against each of the attribute + names defined by this class. In fact there is nothing to do here + since the CmpFrame class currently defines no extra attributes, but + this may change in the future. */ + if( 0 ) { + + + +/* If the attribute is not a CmpFrame specific attribute... */ + } else if( astOK ) { + +/* We want to allow easy access to the attributes of the component Frames. + That is, we do not want it to be necessary to extract a Frame from + its parent CmpFrame in order to access its attributes. For this reason + we first temporarily switch off error reporting so that if an attempt + to access the attribute fails, we can try a different approach. */ + oldrep = astReporting( 0 ); + +/* Our first attempt is to see if the attribute is recognised by the parent + class (Frame). */ + result = (*parent_testattrib)( this_object, attrib, status ); + +/* Indicate success. */ + if( astOK ) { + ok = 1; + +/* Otherwise, clear the error condition so that we can try a different + approach. */ + } else { + astClearStatus; + +/* If the attribute is qualified by an axis index, try accessing it as an + attribute of the primary Frame containing the specified index. */ + if ( nc = 0, + ( 2 == astSscanf( attrib, "%[^(](%d)%n", buf1, &axis, &nc ) ) + && ( nc >= len ) ) { + +/* Find the primary Frame containing the specified axis. */ + astPrimaryFrame( this, axis - 1, &pfrm, &paxis ); + if( astOK ) { + +/* 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" ); + +/* Create a new attribute with the same name but with the axis index + appropriate to the primary Frame. */ + sprintf( buf2, "%s(%d)", buf1, paxis + 1 ); + +/* Attempt to access the attribute. */ + result = astTestAttrib( pfrm, buf2 ); + +/* Indicate success. */ + if( astOK ) { + ok = 1; + +/* Otherwise clear the status value, and try again without any axis index. */ + } else { + astClearStatus; + result = astTestAttrib( pfrm, buf1 ); + +/* Indicate success, or clear the status value. */ + if( astOK ) { + ok = 1; + } else { + astClearStatus; + } + } + +/* Free the primary frame pointer. */ + pfrm = astAnnul( pfrm ); + } + +/* If the attribute is not qualified by an axis index, try accessing it + using the primary Frame of each axis in turn. */ + } else { + +/* Loop round all axes, until one is found which defines the specified + attribute. */ + for( axis = 0; axis < astGetNaxes( this ) && !ok; axis++ ) { + +/* Get the primary Frame containing this axis. */ + astPrimaryFrame( this, axis, &pfrm, &paxis ); + +/* Attempt to access the attribute as an attribute of the primary Frame. */ + result = astTestAttrib( pfrm, attrib ); + +/* Indicate success, or clear the status value. */ + if( astOK ) { + ok = 1; + } else { + astClearStatus; + } + +/* Free the primary Frame pointer. */ + pfrm = astAnnul( pfrm ); + + } + } + } + +/* Re-instate the original error reporting state. */ + astReporting( oldrep ); + + } + +/* Report an error if the attribute could not be accessed. */ + if( !ok && astOK ) { + astError( AST__BADAT, "astTest: The %s given does not have an attribute " + "called \"%s\".", status, astGetClass( this ), attrib ); + } + +/* Return the result. */ + return result; + +} + +static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in, + int forward, AstPointSet *out, int *status ) { +/* +* Name: +* Transform + +* Purpose: +* Transform a set of points. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* AstPointSet *Transform( AstMapping *this, AstPointSet *in, +* int forward, AstPointSet *out, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the astTransform method +* inherited from the Frame class). + +* Description: +* This function takes a CmpFrame and a set of points encapsulated +* in a PointSet, and applies the coordinate transformation equivalent +* to the CmpFrame (this will normally be a UnitMap but may not be if +* the CmpFrame contains any Regions). + +* Parameters: +* this +* Pointer to the CmpFrame. +* 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 number of coordinate values per point in the input +* PointSet must match the number of axes in the CmpFrame. +* - 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 CmpFrame axes). 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: */ + AstCmpFrame *this; /* Pointer to original CmpFrame structure */ + AstCmpMap *map2; /* Intermediate Mapping */ + AstCmpMap *map; /* Equivalent Mapping */ + AstPermMap *pmap; /* Intermediate PermMap */ + AstPointSet *result; /* Pointer value to return */ + const int *inperm; /* Pointer to axis permutation array */ + int *outperm; /* Pointer to inverse axis permutation array */ + int i; /* External axis index */ + int naxes; /* Number of axes in CmpFrame */ + int perm; /* Is there an axis permutation to undo? */ + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_mapping; + +/* Form a parallel CmpMap from the two component Frames. */ + map = astCmpMap( this->frame1, this->frame2, 0, "", status ); + +/* The above CmpMap does not take into account any axis permutation + which has been applied to the CmpFrame as a whole (as opposed to axis + permutations applied to the individual component Frames, which are taken + care of by the Transform methods of the individual Frames). Therefore + we need to modify the Mapping by adding a PermMap at the start which + converts from external axis numbering to internal axis numbering, and a + corresponding PermMap at the end which converts from internal to external + axis numbering. Obtain the number of axes in the CmpFrame */ + naxes = astGetNaxes( this ); + +/* Obtain a pointer to the CmpFrame's axis permutation array. This + contains internal axis numbers and is indexed by external axis number. */ + inperm = astGetPerm( this ); + +/* Check if there is any axis permutation to be performed. */ + perm = 0; + for( i = 0; i < naxes; i++ ) { + if( inperm[ i ] != i ) { + perm = 1; + break; + } + } + +/* If so, create an array holding the inverse permutation - one which + contains external axis numbers and is indexed by internal axis number. */ + if( perm ) { + outperm = astMalloc( sizeof( int )*(size_t) naxes ); + if( astOK ) for( i = 0; i < naxes; i++ ) outperm[ inperm[ i ] ] = i; + +/* Create a PermMap from these permutation arrays. The forward + transformation maps from external axis indices to internal axis + indices. */ + pmap = astPermMap( naxes, inperm, naxes, outperm, NULL, "", status ); + outperm = astFree( outperm ); + +/* Combine this PermMap with the CmpMap created above, adding it in the + forward direction at the start and in the inverse direction at the end. */ + map2 = astCmpMap( pmap, map, 1, "", status ); + map = astAnnul( map ); + astInvert( pmap ); + map = astCmpMap( map2, pmap, 1, "", status ); + map2 = astAnnul( map2 ); + pmap = astAnnul( pmap ); + + } + +/* Apply the Mapping to the input PointSet. */ + result = astTransform( map, in, forward, out ); + +/* Annul the Mapping pointer. */ + map = astAnnul( map ); + +/* 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; +} + +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 CmpFrame axis. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* int Unformat( AstFrame *this, int axis, const char *string, +* double *value, int *status ) + +* Class Membership: +* CmpFrame member function (over-rides the public astUnformat +* method inherited from the Frame class). + +* Description: +* This function reads a formatted coordinate value for a CmpFrame +* 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 CmpFrame. +* axis +* The number of the CmpFrame 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 "<bad>" 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + AstFrame *frame; /* Pointer to Frame containing axis */ + double coord; /* Coordinate value read */ + int naxes1; /* Number of axes in frame1 */ + int nc; /* Number of characters read */ + int set; /* Digits attribute set? */ + +/* Initialise. */ + nc = 0; + +/* Check the global error status. */ + if ( !astOK ) return nc; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_frame; + +/* Validate and permute the axis index supplied. */ + axis = astValidateAxis( this, axis, 1, "astUnformat" ); + +/* Determine the number of axes in the first component Frame. */ + naxes1 = astGetNaxes( this->frame1 ); + if ( astOK ) { + +/* Decide which component Frame contains the axis and adjust the axis + index if necessary. */ + frame = ( axis < naxes1 ) ? this->frame1 : this->frame2; + axis = ( axis < naxes1 ) ? axis : axis - naxes1; + +/* Since the component Frame is "managed" by the enclosing CmpFrame, + we next test if any Frame 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 + CmpFrame. Only the Digits attribute is potentially relevant + here. */ + set = astTestDigits( frame ); + if ( !set ) astSetDigits( frame, astGetDigits( this ) ); + +/* Invoke the Frame's astUnformat method to read the coordinate value. */ + nc = astUnformat( frame, axis, string, &coord ); + +/* Clear Frame attributes which were temporarily over-ridden. */ + if ( !set ) astClearDigits( frame ); + } + +/* 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 chracters read. */ + return nc; +} + +static int ValidateSystem( AstFrame *this, AstSystemType system, const char *method, int *status ) { +/* +* +* Name: +* ValidateSystem + +* Purpose: +* Validate a value for a CmpFrame's System attribute. + +* Type: +* Protected virtual function. + +* Synopsis: +* #include "cmpframe.h" +* int ValidateSystem( AstFrame *this, AstSystemType system, +* const char *method, int *status ) + +* Class Membership: +* CmpFrame 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; +} + +/* Functions which access class attributes. */ +/* ---------------------------------------- */ +/* Implement member functions to access the attributes associated with + the axes of a CmpFrame using the private macros defined for this + purpose at the start of this file. */ + +/* Direction(axis). */ +/* ---------------- */ +MAKE_CLEAR(Direction) +MAKE_GET(Direction,int,0,0,0) +MAKE_SET(Direction,int) +MAKE_TEST(Direction) + +/* Format(axis). */ +/* ------------- */ +MAKE_CLEAR(Format) +MAKE_GET(Format,const char *,NULL,0,NULL) +MAKE_SET(Format,const char *) +MAKE_TEST(Format) + +/* Label(axis). */ +/* ------------ */ +MAKE_CLEAR(Label) + +/* Over-ride the default axis labels produced by Frame class objects + and substitute the axis numbering of the enclosing CmpFrame + instead. */ +static const char *label_class; +MAKE_GET(Label,const char *,NULL,( label_class = astGetClass( frame ), + ( astOK && !strcmp( label_class, + "Frame" ) ) ), + ( (void) sprintf( label_buff, "Axis %d", axis + 1 ), label_buff )) +MAKE_SET(Label,const char *) +MAKE_TEST(Label) + +/* Symbol(axis). */ +/* ------------- */ +MAKE_CLEAR(Symbol) + +/* Over-ride the default axis symbols produced by Frame class objects + and substitute the axis numbering of the enclosing CmpFrame + instead. */ +static const char *symbol_class; +MAKE_GET(Symbol,const char *,NULL,( symbol_class = astGetClass( frame ), + ( astOK && !strcmp( symbol_class, + "Frame" ) ) ), + ( (void) sprintf( symbol_buff, "x%d", axis + 1 ), symbol_buff )) +MAKE_SET(Symbol,const char *) +MAKE_TEST(Symbol) + +/* Unit(axis). */ +/* ----------- */ +MAKE_CLEAR(Unit) +MAKE_GET(Unit,const char *,NULL,0,NULL) +MAKE_SET(Unit,const char *) +MAKE_TEST(Unit) + +/* Copy constructor. */ +/* ----------------- */ +static void Copy( const AstObject *objin, AstObject *objout, int *status ) { +/* +* Name: +* Copy + +* Purpose: +* Copy constructor for CmpFrame objects. + +* Type: +* Private function. + +* Synopsis: +* void Copy( const AstObject *objin, AstObject *objout, int *status ) + +* Description: +* This function implements the copy constructor for CmpFrame 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: */ + AstCmpFrame *in; /* Pointer to input CmpFrame */ + AstCmpFrame *out; /* Pointer to output CmpFrame */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain pointers to the input and output CmpFrames. */ + in = (AstCmpFrame *) objin; + out = (AstCmpFrame *) objout; + +/* Copy the two component Frames. */ + out->frame1 = astCopy( in->frame1 ); + out->frame2 = astCopy( in->frame2 ); + +/* Determine the number of axes and copy the axis permutation + array. */ + out->perm = astStore( NULL, in->perm, sizeof( int ) * + (size_t) GetNaxes( (AstFrame *) in, status ) ); +} + +/* Destructor. */ +/* ----------- */ +static void Delete( AstObject *obj, int *status ) { +/* +* Name: +* Delete + +* Purpose: +* Destructor for CmpFrame objects. + +* Type: +* Private function. + +* Synopsis: +* void Delete( AstObject *obj, int *status ) + +* Description: +* This function implements the destructor for CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to CmpFrame structure */ + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) obj; + +/* Annul the two component Frame pointers. */ + if ( this->frame1 ) this->frame1 = astAnnul( this->frame1 ); + if ( this->frame2 ) this->frame2 = astAnnul( this->frame2 ); + +/* Free the axis permutation array. */ + if ( this->perm ) this->perm = astFree( this->perm ); +} + +/* Dump function. */ +/* -------------- */ +static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { +/* +* Name: +* Dump + +* Purpose: +* Dump function for CmpFrame 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 CmpFrame class to an output Channel. + +* Parameters: +* this +* Pointer to the CmpFrame 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: */ + AstCmpFrame *this; /* Pointer to the CmpFrame structure */ + char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment strings */ + char key[ KEY_LEN + 1 ]; /* Buffer for keywords */ + int axis; /* Loop counter for CmpFrame axes */ + int full; /* Full attribute value */ + int full_set; /* Full attribute set? */ + int ival; /* Integer value */ + int naxes; /* Number of CmpFrame axes */ + int set; /* Attribute value set? */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the CmpFrame structure. */ + this = (AstCmpFrame *) this_object; + +/* Write out values representing the instance variables for the + CmpFrame 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. */ + +/* Axis permutation array. */ +/* ----------------------- */ +/* Obtain the number of CmpFrame axes. */ + naxes = GetNaxes( (AstFrame *) this, status ); + +/* Write out the CmpFrame axis permutation array value for each axis, + converting to 1-based axis numbering. */ + for ( axis = 0; axis < naxes; axis++ ) { + set = ( this->perm[ axis ] != axis ); + ival = this->perm[ axis ] + 1; + +/* Create a keyword and comment appropriate to the axis. */ + (void) sprintf( key, "Axp%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 ); + } + +/* Component Frames. */ +/* ----------------- */ +/* 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" Frame values being output that would otherwise + simply duplicate the CmpFrame's attributes which have already been + written. "Set" Frame 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 ); + +/* Write out Object descriptions for the two component Frames. */ + astWriteObject( channel, "FrameA", 1, 1, this->frame1, + "First component Frame" ); + astWriteObject( channel, "FrameB", 1, 1, this->frame2, + "Second component Frame" ); + +/* Restore the Channel's original Full attribute setting. */ + if ( full_set ) { + astSetFull( channel, full ); + } else { + astClearFull( channel ); + } + +/* Undefine macros local to this function. */ +#undef COMMENT_LEN +#undef KEY_LEN +} + +/* Standard class functions. */ +/* ========================= */ +/* Implement the astIsACmpFrame and astCheckCmpFrame functions using the macros + defined for this purpose in the "object.h" header file. */ +astMAKE_ISA(CmpFrame,Frame) +astMAKE_CHECK(CmpFrame) + +AstCmpFrame *astCmpFrame_( void *frame1_void, void *frame2_void, + const char *options, int *status, ...) { +/* +*++ +* Name: +c astCmpFrame +f AST_CMPFRAME + +* Purpose: +* Create a CmpFrame. + +* Type: +* Public function. + +* Synopsis: +c #include "cmpframe.h" +c AstCmpFrame *astCmpFrame( AstFrame *frame1, AstFrame *frame2, +c const char *options, ... ) +f RESULT = AST_CMPFRAME( FRAME1, FRAME2, OPTIONS, STATUS ) + +* Class Membership: +* CmpFrame constructor. + +* Description: +* This function creates a new CmpFrame and optionally initialises +* its attributes. +* +* A CmpFrame is a compound Frame which allows two component Frames +* (of any class) to be merged together to form a more complex +* Frame. The axes of the two component Frames then appear together +* in the resulting CmpFrame (those of the first Frame, followed by +* those of the second Frame). +* +* Since a CmpFrame is itself a Frame, it can be used as a +* component in forming further CmpFrames. Frames of arbitrary +* complexity may be built from simple individual Frames in this +* way. +* +* Also since a Frame is a Mapping, a CmpFrame can also be used as a +* Mapping. Normally, a CmpFrame is simply equivalent to a UnitMap, +* but if either of the component Frames within a CmpFrame is a Region +* (a sub-class of Frame), then the CmpFrame will use the Region as a +* Mapping when transforming values for axes described by the Region. +* Thus input axis values corresponding to positions which are outside the +* Region will result in bad output axis values. + +* Parameters: +c frame1 +f FRAME1 = INTEGER (Given) +* Pointer to the first component Frame. +c frame2 +f FRAME2 = INTEGER (Given) +* Pointer to the second component Frame. +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 CmpFrame. 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 CmpFrame. 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 astCmpFrame() +f AST_CMPFRAME = INTEGER +* A pointer to the new CmpFrame. + +* 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". + +*-- + +* Implementation Notes: +* - This function implements the basic CmpFrame constructor which +* is available via the protected interface to the CmpFrame class. +* A public interface is provided by the astCmpFrameId_ 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 */ + AstCmpFrame *new; /* Pointer to new CmpFrame */ + AstFrame *frame1; /* Pointer to first Frame structure */ + AstFrame *frame2; /* Pointer to second Frame 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 = astCheckFrame( frame1_void ); + frame2 = astCheckFrame( frame2_void ); + if ( astOK ) { + +/* Initialise the CmpFrame, allocating memory and initialising the + virtual function table as well if necessary. */ + new = astInitCmpFrame( NULL, sizeof( AstCmpFrame ), !class_init, + &class_vtab, "CmpFrame", 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 + CmpFrame'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 CmpFrame. */ + return new; +} + +AstCmpFrame *astCmpFrameId_( void *frame1_void, void *frame2_void, + const char *options, ... ) { +/* +* Name: +* astCmpFrameId_ + +* Purpose: +* Create a CmpFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "cmpframe.h" +* AstCmpFrame *astCmpFrameId_( void *frame1_void, void *frame2_void, +* const char *options, ... ) + +* Class Membership: +* CmpFrame constructor. + +* Description: +* This function implements the external (public) interface to the +* astCmpFrame constructor function. It returns an ID value +* (instead of a true C pointer) to external users, and must be +* provided because astCmpFrame_ 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 astCmpFrame_ 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 astCmpFrame_. + +* Returned Value: +* The ID value associated with the new CmpFrame. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstCmpFrame *new; /* Pointer to new CmpFrame */ + AstFrame *frame1; /* Pointer to first Frame structure */ + AstFrame *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 = astVerifyFrame( astMakePointer( frame1_void ) ); + frame2 = astVerifyFrame( astMakePointer( frame2_void ) ); + if ( astOK ) { + +/* Initialise the CmpFrame, allocating memory and initialising the + virtual function table as well if necessary. */ + new = astInitCmpFrame( NULL, sizeof( AstCmpFrame ), !class_init, + &class_vtab, "CmpFrame", 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 + CmpFrame'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 CmpFrame. */ + return astMakeId( new ); +} + +AstCmpFrame *astInitCmpFrame_( void *mem, size_t size, int init, + AstCmpFrameVtab *vtab, const char *name, + AstFrame *frame1, AstFrame *frame2, int *status ) { +/* +*+ +* Name: +* astInitCmpFrame + +* Purpose: +* Initialise a CmpFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "cmpframe.h" +* AstCmpFrame *astInitCmpFrame( void *mem, size_t size, int init, +* AstCmpFrameVtab *vtab, const char *name, +* AstFrame *frame1, AstFrame *frame2 ) + +* Class Membership: +* CmpFrame initialiser. + +* Description: +* This function is provided for use by class implementations to +* initialise a new CmpFrame object. It allocates memory (if +* necessary) to accommodate the CmpFrame plus any additional data +* associated with the derived class. It then initialises a +* CmpFrame 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 CmpFrame at the start of the memory passed +* via the "vtab" parameter. + +* Parameters: +* mem +* A pointer to the memory in which the CmpFrame is to be +* created. This must be of sufficient size to accommodate the +* CmpFrame data (sizeof(CmpFrame)) 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 CmpFrame (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 CmpFrame structure, so a valid value must be +* supplied even if not required for allocating memory. +* init +* A logical flag indicating if the CmpFrame'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 CmpFrame. +* 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 first Frame to be included in the new CmpFrame. +* frame2 +* Pointer to the second Frame to be included in the new CmpFrame. + +* Returned Value: +* A pointer to the new CmpFrame. + +* 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: */ + AstCmpFrame *new; /* Pointer to new CmpFrame */ + int axis; /* Loop counter for axes */ + int naxes; /* Number of CmpFrame axes */ + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* If necessary, initialise the virtual function table. */ + if ( init ) astInitCmpFrameVtab( vtab, name ); + +/* Initialise a Frame structure (the parent class) as the first + component within the CmpFrame structure, allocating memory if + necessary. Set the number of Frame axes to zero, since all axis + information is stored within the component Frames. */ + new = (AstCmpFrame *) astInitFrame( mem, size, 0, (AstFrameVtab *) vtab, + name, 0 ); + + if ( astOK ) { + +/* Initialise the CmpFrame data. */ +/* ----------------------------- */ +/* Clone the component Frame pointers. */ + new->frame1 = astClone( frame1 ); + new->frame2 = astClone( frame2 ); + +/* Determine the number of CmpFrame axes. */ + naxes = astGetNaxes( frame1 ) + astGetNaxes( frame2 ); + +/* Allocate memory to hold the axis permutation array and initialise + this array. */ + new->perm = astMalloc( sizeof( int ) * (size_t) naxes ); + if ( astOK ) { + for ( axis = 0; axis < naxes; axis++ ) new->perm[ 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; +} + +AstCmpFrame *astLoadCmpFrame_( void *mem, size_t size, + AstCmpFrameVtab *vtab, const char *name, + AstChannel *channel, int *status ) { +/* +*+ +* Name: +* astLoadCmpFrame + +* Purpose: +* Load a CmpFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "cmpframe.h" +* AstCmpFrame *astLoadCmpFrame( void *mem, size_t size, +* AstCmpFrameVtab *vtab, const char *name, +* AstChannel *channel ) + +* Class Membership: +* CmpFrame loader. + +* Description: +* This function is provided to load a new CmpFrame 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 +* CmpFrame structure in this memory, using data read from the +* input Channel. + +* Parameters: +* mem +* A pointer to the memory into which the CmpFrame is to be +* loaded. This must be of sufficient size to accommodate the +* CmpFrame data (sizeof(CmpFrame)) 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 CmpFrame (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 CmpFrame 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(AstCmpFrame) is used instead. +* vtab +* Pointer to the start of the virtual function table to be +* associated with the new CmpFrame. If this is NULL, a pointer +* to the (static) virtual function table for the CmpFrame 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 "CmpFrame" is used instead. + +* Returned Value: +* A pointer to the new CmpFrame. + +* 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: */ + AstCmpFrame *new; /* Pointer to the new CmpFrame */ + char key[ KEY_LEN + 1 ]; /* Buffer for keywords */ + int axis; /* Loop counter for axes */ + int naxes; /* Number of CmpFrame 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 CmpFrame. In this case the + CmpFrame belongs to this class, so supply appropriate values to be + passed to the parent class loader (and its parent, etc.). */ + if ( !vtab ) { + size = sizeof( AstCmpFrame ); + vtab = &class_vtab; + name = "CmpFrame"; + +/* If required, initialise the virtual function table for this class. */ + if ( !class_init ) { + astInitCmpFrameVtab( 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 CmpFrame. */ + 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, "CmpFrame" ); + +/* 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. */ + +/* Component Frames. */ +/* ----------------- */ +/* Read both component Frames, supplying a default 1-dimensional Frame + if necessary. */ + new->frame1 = astReadObject( channel, "framea", NULL ); + if ( !new->frame1 ) new->frame1 = astFrame( 1, "", status ); + + new->frame2 = astReadObject( channel, "frameb", NULL ); + if ( !new->frame2 ) new->frame2 = astFrame( 1, "", status ); + +/* Axis permutation array. */ +/* ----------------------- */ +/* Obtain the number of CmpFrame axes and allocate memory to hold the + axis permutation array. */ + naxes = GetNaxes( (AstFrame *) new, status ); + new->perm = astMalloc( sizeof( int ) * (size_t) naxes ); + +/* If OK, loop to read the array value for each axis. */ + if ( astOK ) { + for ( axis = 0; axis < naxes; axis++ ) { + +/* Convert from 1-based to zero-based axis numbering at this + point. The default is the "un-permuted" value. */ + sprintf( key, "axp%d", axis + 1 ); + new->perm[ axis ] = astReadInt( channel, key, axis + 1 ) - 1; + +/* Quit looping if an error occurs. */ + if ( !astOK ) break; + } + } + +/* If an error occurred, clean up by deleting the new CmpFrame. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return the new CmpFrame 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. */ + + + + + |