summaryrefslogtreecommitdiffstats
path: root/ast/cmpframe.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2018-01-09 19:28:07 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2018-01-09 19:28:07 (GMT)
commit3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58 (patch)
treef278119398ae5d67a6a338705a76db420f6b8f7e /ast/cmpframe.c
parent1332d38f2805d986ea130e43218c0d2e870b4dc1 (diff)
downloadblt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.zip
blt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.tar.gz
blt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.tar.bz2
update ast 8.6.2
Diffstat (limited to 'ast/cmpframe.c')
-rw-r--r--ast/cmpframe.c10846
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. */
+
+
+
+
+