summaryrefslogtreecommitdiffstats
path: root/ast/frameset.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/frameset.c
parent1332d38f2805d986ea130e43218c0d2e870b4dc1 (diff)
downloadblt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.zip
blt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.tar.gz
blt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.tar.bz2
update ast 8.6.2
Diffstat (limited to 'ast/frameset.c')
-rw-r--r--ast/frameset.c13337
1 files changed, 13337 insertions, 0 deletions
diff --git a/ast/frameset.c b/ast/frameset.c
new file mode 100644
index 0000000..d3bcc06
--- /dev/null
+++ b/ast/frameset.c
@@ -0,0 +1,13337 @@
+/*
+*class++
+* Name:
+* FrameSet
+
+* Purpose:
+* Set of inter-related coordinate systems.
+
+* Constructor Function:
+c astFrameSet
+f AST_FRAMESET
+
+* Description:
+* A FrameSet consists of a set of one or more Frames (which
+* describe coordinate systems), connected together by Mappings
+* (which describe how the coordinate systems are inter-related). A
+* FrameSet makes it possible to obtain a Mapping between any pair
+* of these Frames (i.e. to convert between any of the coordinate
+* systems which it describes). The individual Frames are
+* identified within the FrameSet by an integer index, with Frames
+* being numbered consecutively from one as they are added to the
+* FrameSet.
+*
+* Every FrameSet has a "base" Frame and a "current" Frame (which
+* are allowed to be the same). Any of the Frames may be nominated
+* to hold these positions, and the choice is determined by the
+* values of the FrameSet's Base and Current attributes, which hold
+* the indices of the relevant Frames. By default, the first Frame
+* added to a FrameSet is its base Frame, and the last one added is
+* its current Frame.
+*
+* The base Frame describes the "native" coordinate system of
+* whatever the FrameSet is used to calibrate (e.g. the pixel
+* coordinates of an image) and the current Frame describes the
+* "apparent" coordinate system in which it should be viewed
+* (e.g. displayed, etc.). Any further Frames represent a library
+* of alternative coordinate systems, which may be selected by
+* making them current.
+*
+* When a FrameSet is used in a context that requires a Frame,
+* (e.g. obtaining its Title value, or number of axes), the current
+* Frame is used. A FrameSet may therefore be used in place of its
+* current Frame in most situations.
+*
+* When a FrameSet is used in a context that requires a Mapping,
+* the Mapping used is the one between its base Frame and its
+* current Frame. Thus, a FrameSet may be used to convert "native"
+* coordinates into "apparent" ones, and vice versa. Like any
+c Mapping, a FrameSet may also be inverted (see astInvert), which
+f Mapping, a FrameSet may also be inverted (see AST_INVERT), which
+* has the effect of interchanging its base and current Frames and
+* hence of reversing the Mapping between them.
+*
+* Regions may be added into a FrameSet (since a Region is a type of
+* Frame), either explicitly or as components within CmpFrames. In this
+* case the Mapping between a pair of Frames within a FrameSet will
+* include the effects of the clipping produced by any Regions included
+* in the path between the Frames.
+
+* Inheritance:
+* The FrameSet class inherits from the Frame class.
+
+* Attributes:
+* In addition to those attributes common to all Frames, every
+* FrameSet also has the following attributes:
+*
+* - AllVariants: List of all variant mappings stored with current Frame
+* - Base: FrameSet base Frame index
+* - Current: FrameSet current Frame index
+* - Nframe: Number of Frames in a FrameSet
+* - Variant: Name of variant mapping in use by current Frame
+
+* Every FrameSet also inherits any further attributes that belong
+* to its current Frame, regardless of that Frame's class. (For
+* example, the Equinox attribute, defined by the SkyFrame class, is
+* inherited by any FrameSet which has a SkyFrame as its current
+* Frame.) The set of attributes belonging to a FrameSet may therefore
+* change when a new current Frame is selected.
+
+* Functions:
+c In addition to those functions applicable to all Frames, the
+c following functions may also be applied to all FrameSets:
+f In addition to those routines applicable to all Frames, the
+f following routines may also be applied to all FrameSets:
+*
+c - astAddFrame: Add a Frame to a FrameSet to define a new coordinate
+c system
+c - astAddVariant: Add a variant Mapping to the current Frame
+c - astGetFrame: Obtain a pointer to a specified Frame in a FrameSet
+c - astGetMapping: Obtain a Mapping between two Frames in a FrameSet
+c - astMirrorVariants: Make the current Frame mirror variant Mappings in another Frame
+c - astRemapFrame: Modify a Frame's relationship to the other Frames in a
+c FrameSet
+c - astRemoveFrame: Remove a Frame from a FrameSet
+f - AST_ADDFRAME: Add a Frame to a FrameSet to define a new coordinate
+f system
+f - AST_ADDVARIANT: Add a variant Mapping to the current Frame
+f - AST_GETFRAME: Obtain a pointer to a specified Frame in a FrameSet
+f - AST_GETMAPPING: Obtain a Mapping between two Frames in a FrameSet
+f - AST_MIRRORVARIANTS: Make the current Frame mirror variant Mappings in another Frame
+f - AST_REMAPFRAME: Modify a Frame's relationship to the other Frames in a
+f FrameSet
+f - AST_REMOVEFRAME: Remove a Frame from a FrameSet
+
+* Copyright:
+* Copyright (C) 1997-2006 Council for the Central Laboratory of the
+* Research Councils
+
+* Licence:
+* This program is free software: you can redistribute it and/or
+* modify it under the terms of the GNU 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)
+
+* History:
+* 16-FEB-1996 (RFWS):
+* Original version.
+* 5-JUN-1996 (RFWS):
+* Tidied up, etc.
+* 2-JUL-1996 (RFWS):
+* Fixed bug in astRemoveFrame which caused the base/current
+* Frame index to be wrong.
+* 12-JUL-1996 (RFWS):
+* Over-ride the astReportPoints method to provide
+* Frame-specific formatting.
+* 12-AUG-1996 (RFWS):
+* Upgraded to provide a public interface, plus improvements to
+* astAlign and the handling of nodes as Frames are
+* added/removed.
+* 11-SEP-1996 (RFWS):
+* Added Gap.
+* 25-SEP-1996 (RFWS):
+* Added I/O facilities.
+* 30-MAY-1997 (RFWS):
+* Add special treatment for the ID attribute (which is not
+* derived from the current Frame).
+* 10-JUN-1997 (RFWS):
+* Rationalised the astConvert implementation.
+* 11-JUN-1997 (RFWS):
+* Added the FindFrame implementation.
+* 27-JUN-1997 (RFWS):
+* Fixed bug which caused certain Mapping attributes to be
+* handled by the current Frame instead of by the member
+* functions defined by this class.
+* 3-JUL-1997 (RFWS):
+* Fixed bug: failing to extend the invert array in
+* astRemapFrame.
+* 10-JUL-1997 (RFWS):
+* Over-ride the astSimplify method.
+* 14-NOV-1997 (RFWS):
+* Fixed error in loop implementing search over domains in
+* FindFrame.
+* 20-NOV-1997 (RFWS):
+* Fixed bug in default Base and Current attribute values when a
+* FrameSet has been inverted.
+* 20-NOV-1997 (RFWS):
+* Modified astConvert to use the current Frame of the "to"
+* FrameSet as the destination coordinate system (instead of the
+* base Frame) and to modify its Base attribute instead of its
+* Current attribute.
+* 22-DEC-1997 (RFWS):
+* Further modified astConvert to convert from the Current Frame
+* of the "from" FrameSet and to modify its Base
+* attribute. Frame search order also reversed if the Invert
+* attribute is non-zero for either FrameSet.
+* 19-JAN-1998 (RFWS):
+* Installed the TidyNodes function.
+* 20-JAN-1998 (RFWS):
+* Implemented preservation of FrameSet integrity when attribute
+* values associated with the current Frame are modified.
+* 24-FEB-1998 (RFWS):
+* Added the ForceCopy function to allow integrity to be preserved
+* when there are multiple references to the same Frame.
+* 25-FEB-1998 (RFWS):
+* Over-ride the astUnformat method.
+* 24-MAR-1998 (RFWS):
+* Fixed unterminated comment causing problems in CombineMaps.
+* 6-APR-1998 (RFWS):
+* Fixed another unterminated comment in CombineMaps.
+* 27-MAY-1998 (RFWS):
+* Fixed bug: failure to record new invert flag value after
+* simplifying a CmpMap in TidyNodes.
+* 17-DEC-2002 (DSB):
+* Override accessors for Frame attributes Top, Bottom, Epoch,
+* System, AlignSystem and ActiveUnit.
+* 8-JAN-2003 (DSB):
+* Changed private InitVtab method to protected astInitFrameSetVtab
+* method.
+* 24-JAN-2004 (DSB):
+* o Override the astFields method.
+* o Add argument "fmt" to Abbrev.
+* 23-MAR-2004 (DSB):
+* Modified astGetMapping and Span to include the clipping effect of
+* any Regions in the path between the two supplied Frames.
+* 24-AUG-2004 (DSB):
+* - Override various methods inherited from Frame (astAngle,
+* astAxAngle, astAxDistance, astAxOffset, astCheckPerm, astOffset2,
+* astResolve, astSystemCode, astSystemString, astValidateSystem,
+* astValidateAxisSelection). These should have been overridden a
+* long time ago!
+* 8-SEP-2004 (DSB):
+* Override astResolvePoints.
+* 12-MAY-2005 (DSB):
+* Override astNormBox method.
+* 12-AUG-2005 (DSB):
+* Override ObsLat and ObsLon accessor methods.
+* 14-FEB-2006 (DSB):
+* Override astGetObjSize.
+* 15-MAY-2006 (DSB):
+* Override astEqual.
+* 30-JUN-2006 (DSB):
+* Allow astAbbrev to have a null "str1" value.
+* 22-JUN-2007 (DSB):
+* Modify VSet to avoid using the args va_list twice since the
+* first use (by the parent VSet function) invalidates the va_list
+* causing a segvio to be generated by the second use (when
+* formatting an error message).
+* 11-JAN-2008 (DSB):
+* Override the astRate method.
+* 17-NOV-2008 (DSB):
+* Correct parent class in invocation of astMAKE_ISA.
+* 14-JAN-2009 (DSB):
+* Override the astIntersect method.
+* 18-JUN-2009 (DSB):
+* Override ObsAlt accessor methods.
+* 30-OCT-2009 (DSB):
+* Make the Ident attribute relate to the FrameSet, not the current
+* Frame.
+* 22-MAR-2011 (DSB):
+* Override astFrameGrid method.
+* 29-APR-2011 (DSB):
+* Prevent astFindFrame from matching a subclass template against a
+* superclass target.
+* 2-SEP-2011 (DSB):
+* Fix FrameSet implememntation of astEqual (mapping comparison
+* tests were logically inverted).
+* 3-OCT-2012 (DSB):
+* Fix bug in AppendAxes that could cause internal Mappings to
+* be inverted unintentionally when astAddFrame is called with
+* iframe=AST__ALLFRAMES.
+* 29-APR-2013 (DSB):
+* Added attributes AllVariants and Variant. Also added methods
+* astAddVariant and astMirrorVariants.
+* 25-SEP-2014 (DSB):
+* Allow Base and Current attributes to be specified by giving a
+* Domain name.
+* 17-APR-2015 (DSB):
+* Added Centre.
+* 28-APR-2015 (DSB):
+* astAdFrame now takes deep copies of the supplied mapping and
+* frame, rather than just cloning their pointers. So the modified
+* FrameSet is now independent of the supplied Mapping and Frame
+* objects.
+* 26-OCT-2016 (DSB):
+* Override the AxNorm method.
+* 07-APR-2017 (GSB):
+* Override Dtai and Dut1 accessor methods.
+* 07-NOV-2017 (GSB):
+* In AddFrame, check to see if a FrameSet is supplied in place of
+* a Mapping and if so, use the FrameSet's base -> current Mapping
+* instead.
+* 11-DEC-2017 (DSB):
+* Added method astGetNode.
+*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 FrameSet
+
+#define GETALLVARIANTS_BUFF_LEN 200
+
+/*
+* Name:
+* MAKE_CLEAR
+
+* Purpose:
+* Define a function to clear an attribute value for a FrameSet.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frameset.h"
+* MAKE_CLEAR(attribute)
+
+* Class Membership:
+* Defined by the FrameSet class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static void Clear<Attribute>( AstFrame *this )
+*
+* that clears the value of a specified attribute for the current Frame
+* of a FrameSet (this). This function is intended to over-ride the
+* astClear<Attribute> method inherited from the Frame class.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+*/
+
+/* Define the macro. */
+#define MAKE_CLEAR(attribute) \
+static void Clear##attribute( AstFrame *this_frame, int *status ) { \
+\
+/* Local Variables: */ \
+ AstFrame *fr; /* Pointer to current Frame */ \
+ AstFrameSet *this; /* Pointer to the FrameSet structure */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Obtain a pointer to the FrameSet structure. */ \
+ this = (AstFrameSet *) this_frame; \
+\
+/* Obtain a pointer to the current Frame and invoke its astClear<Attribute> \
+ method. Annul the Frame pointer afterwards. */ \
+ fr = astGetFrame( this, AST__CURRENT ); \
+ astClear##attribute( fr ); \
+ fr = astAnnul( fr ); \
+}
+
+/*
+* Name:
+* MAKE_CLEAR_AXIS
+
+* Purpose:
+* Define a function to clear an attribute value for a FrameSet axis.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frameset.h"
+* MAKE_CLEAR_AXIS(attribute)
+
+* Class Membership:
+* Defined by the FrameSet class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static void Clear<Attribute>( AstFrame *this, int axis )
+*
+* that clears the value of a specified attribute for an axis of
+* the current Frame of a FrameSet (this). This function is
+* intended to over-ride the astClear<Attribute> method inherited
+* from the Frame class.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+*/
+
+/* Define the macro. */
+#define MAKE_CLEAR_AXIS(attribute) \
+static void Clear##attribute( AstFrame *this_frame, int axis, int *status ) { \
+\
+/* Local Variables: */ \
+ AstFrame *fr; /* Pointer to current Frame */ \
+ AstFrameSet *this; /* Pointer to the FrameSet structure */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Obtain a pointer to the FrameSet structure. */ \
+ this = (AstFrameSet *) this_frame; \
+\
+/* Validate the axis index supplied. */ \
+ (void) astValidateAxis( this, axis, 1, "astClear" #attribute ); \
+\
+/* Obtain a pointer to the FrameSet's current Frame and invoke its \
+ astClear<Attribute> method. Annul the Frame pointer afterwards. */ \
+ fr = astGetFrame( this, AST__CURRENT ); \
+ astClear##attribute( fr, axis ); \
+ fr = astAnnul( fr ); \
+}
+
+/*
+* Name:
+* MAKE_GET
+
+* Purpose:
+* Define a function to get an attribute value for a FrameSet.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frameset.h"
+* MAKE_GET(attribute,type)
+
+* Class Membership:
+* Defined by the FrameSet class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static <type> Get<Attribute>( AstFrame *this )
+*
+* that gets the value of a specified attribute for the current Frame
+* of a FrameSet (this). This function is intended to over-ride the
+* astGet<Attribute> method inherited from the Frame class.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+* type
+* The C type of the attribute.
+*/
+
+/* Define the macro. */
+#define MAKE_GET(attribute,type) \
+static type Get##attribute( AstFrame *this_frame, int *status ) { \
+\
+/* Local Variables: */ \
+ AstFrame *fr; /* Pointer to current Frame */ \
+ AstFrameSet *this; /* Pointer to the FrameSet structure */ \
+ type result; /* Value to return */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return (type) 0; \
+\
+/* Obtain a pointer to the FrameSet structure. */ \
+ this = (AstFrameSet *) this_frame; \
+\
+/* Obtain a pointer to the current Frame and invoke its \
+ astGet<Attribute> method. Annul the Frame pointer afterwards. */ \
+ fr = astGetFrame( this, AST__CURRENT ); \
+ result = astGet##attribute( fr ); \
+ fr = astAnnul( fr ); \
+\
+/* If an error occurred, clear the result value. */ \
+ if ( !astOK ) result = (type) 0; \
+\
+/* Return the result. */ \
+ return result; \
+}
+
+/*
+* Name:
+* MAKE_GET_AXIS
+
+* Purpose:
+* Define a function to get an attribute value for a FrameSet axis.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frameset.h"
+* MAKE_GET_AXIS(attribute,type)
+
+* Class Membership:
+* Defined by the FrameSet class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static <type> Get<Attribute>( AstFrame *this, int axis )
+*
+* that gets the value of a specified attribute for an axis of the
+* current Frame of a FrameSet (this). This function is intended to
+* over-ride the astGet<Attribute> method inherited from the Frame
+* class.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+* type
+* The C type of the attribute.
+*/
+
+/* Define the macro. */
+#define MAKE_GET_AXIS(attribute,type) \
+static type Get##attribute( AstFrame *this_frame, int axis, int *status ) { \
+\
+/* Local Variables: */ \
+ AstFrame *fr; /* Pointer to current Frame */ \
+ AstFrameSet *this; /* Pointer to the FrameSet structure */ \
+ type result; /* Value to return */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return (type) 0; \
+\
+/* Obtain a pointer to the FrameSet structure. */ \
+ this = (AstFrameSet *) this_frame; \
+\
+/* Validate the axis index supplied. */ \
+ (void) astValidateAxis( this, axis, 1, "astGet" #attribute ); \
+\
+/* Obtain a pointer to the FrameSet's current Frame and invoke its \
+ astGet<Attribute> method. Annul the Frame pointer afterwards. */ \
+ fr = astGetFrame( this, AST__CURRENT ); \
+ result = astGet##attribute( fr, axis ); \
+ fr = astAnnul( fr ); \
+\
+/* If an error occurred, clear the result value. */ \
+ if ( !astOK ) result = (type) 0; \
+\
+/* Return the result. */ \
+ return result; \
+}
+
+/*
+* Name:
+* MAKE_SET
+
+* Purpose:
+* Define a function to set an attribute value for a FrameSet.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frameset.h"
+* MAKE_SET(attribute,type)
+
+* Class Membership:
+* Defined by the FrameSet class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static void Set<Attribute>( AstFrame *this, <type> value )
+*
+* that sets the value of a specified attribute for the current Frame
+* of a FrameSet (this). This function is intended to over-ride the
+* astSet<Attribute> method inherited from the Frame class.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+* type
+* The C type of the attribute.
+*/
+
+/* Define the macro. */
+#define MAKE_SET(attribute,type) \
+static void Set##attribute( AstFrame *this_frame, type value, int *status ) { \
+\
+/* Local Variables: */ \
+ AstFrame *fr; /* Pointer to current Frame */ \
+ AstFrameSet *this; /* Pointer to the FrameSet structure */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Obtain a pointer to the FrameSet structure. */ \
+ this = (AstFrameSet *) this_frame; \
+\
+/* Obtain a pointer to the FrameSet's current Frame and invoke its \
+ astSet<Attribute> method. Annul the Frame pointer afterwards. */ \
+ fr = astGetFrame( this, AST__CURRENT ); \
+ astSet##attribute( fr, value ); \
+ fr = astAnnul( fr ); \
+}
+
+/*
+* Name:
+* MAKE_SET_AXIS
+
+* Purpose:
+* Define a function to set an attribute value for a FrameSet axis.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frameset.h"
+* MAKE_SET_AXIS(attribute,type)
+
+* Class Membership:
+* Defined by the FrameSet 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 )
+*
+* that sets the value of a specified attribute for an axis of the
+* current Frame of a FrameSet (this). This function is intended to
+* over-ride the astSet<Attribute> method inherited from the Frame
+* class.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+* type
+* The C type of the attribute.
+*/
+
+/* Define the macro. */
+#define MAKE_SET_AXIS(attribute,type) \
+static void Set##attribute( AstFrame *this_frame, int axis, type value, int *status ) { \
+\
+/* Local Variables: */ \
+ AstFrame *fr; /* Pointer to current Frame */ \
+ AstFrameSet *this; /* Pointer to the FrameSet structure */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Obtain a pointer to the FrameSet structure. */ \
+ this = (AstFrameSet *) this_frame; \
+\
+/* Validate the axis index supplied. */ \
+ (void) astValidateAxis( this, axis, 1, "astSet" #attribute ); \
+\
+/* Obtain a pointer to the FrameSet's current Frame and invoke its \
+ astSet<Attribute> method. Annul the Frame pointer afterwards. */ \
+ fr = astGetFrame( this, AST__CURRENT ); \
+ astSet##attribute( fr, axis, value ); \
+ fr = astAnnul( fr ); \
+}
+
+/*
+* Name:
+* MAKE_TEST
+
+* Purpose:
+* Define a function to test if an attribute value is set for a FrameSet.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frameset.h"
+* MAKE_TEST(attribute)
+
+* Class Membership:
+* Defined by the FrameSet class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static int Test<Attribute>( AstFrame *this )
+*
+* that returns a boolean result (0 or 1) to indicate if the value
+* of a specified attribute for the current Frame of a FrameSet
+* (this) is set. This function is intended to over-ride the
+* astTest<Attribute> method inherited from the Frame class.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+*/
+
+/* Define the macro. */
+#define MAKE_TEST(attribute) \
+static int Test##attribute( AstFrame *this_frame, int *status ) { \
+\
+/* Local Variables: */ \
+ AstFrame *fr; /* Pointer to current Frame */ \
+ AstFrameSet *this; /* Pointer to FrameSet structure */ \
+ int result; /* Result to return */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return 0; \
+\
+/* Obtain a pointer to the FrameSet structure. */ \
+ this = (AstFrameSet *) this_frame; \
+\
+/* Obtain a pointer to the FrameSet's current Frame and invoke its \
+ astTest<Attribute> method. Annul the Frame pointer afterwards. */ \
+ fr = astGetFrame( this, AST__CURRENT ); \
+ result = astTest##attribute( fr ); \
+ fr = astAnnul( fr ); \
+\
+/* If an error occurred, clear the result value. */ \
+ if ( !astOK ) result = 0; \
+\
+/* Return the result. */ \
+ return result; \
+}
+
+/*
+* Name:
+* MAKE_TEST_AXIS
+
+* Purpose:
+* Define a function to test if an attribute value is set for a FrameSet
+* axis.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frameset.h"
+* MAKE_TEST_AXIS(attribute)
+
+* Class Membership:
+* Defined by the FrameSet class.
+
+* Description:
+* This macro expands to an implementation of a private member function
+* of the form:
+*
+* static int Test<Attribute>( AstFrame *this, int axis )
+*
+* that returns a boolean result (0 or 1) to indicate if the value
+* of a specified attribute for an axis of the current Frame of a
+* FrameSet (this) is set. This function is intended to over-ride
+* the astTest<Attribute> method inherited from the Frame class.
+
+* Parameters:
+* attribute
+* Name of the attribute, as it appears in the function name.
+*/
+
+/* Define the macro. */
+#define MAKE_TEST_AXIS(attribute) \
+static int Test##attribute( AstFrame *this_frame, int axis, int *status ) { \
+\
+/* Local Variables: */ \
+ AstFrame *fr; /* Pointer to current Frame */ \
+ AstFrameSet *this; /* Pointer to the FrameSet structure */ \
+ int result; /* Value to return */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return 0; \
+\
+/* Obtain a pointer to the FrameSet structure. */ \
+ this = (AstFrameSet *) this_frame; \
+\
+/* Validate the axis index supplied. */ \
+ (void) astValidateAxis( this, axis, 1, "astTest" #attribute ); \
+\
+/* Obtain a pointer to the FrameSet's current Frame and invoke its \
+ astTest<Attribute> method. Annul the Frame pointer afterwards. */ \
+ fr = astGetFrame( this, AST__CURRENT ); \
+ result = astTest##attribute( fr, axis ); \
+ fr = astAnnul( fr ); \
+\
+/* If an error occurred, clear the result value. */ \
+ if ( !astOK ) result = 0; \
+\
+/* Return the result. */ \
+ return result; \
+}
+
+/* Header files. */
+/* ============= */
+/* Interface definitions. */
+/* ---------------------- */
+
+#include "globals.h" /* Thread-safe global data access */
+#include "error.h" /* Error reporting facilities */
+#include "memory.h" /* Memory allocation facilities */
+#include "object.h" /* Base Object class */
+#include "mapping.h" /* Coordinate Mappings */
+#include "unitmap.h" /* Unit Mappings */
+#include "permmap.h" /* Coordinate permutation Mappings */
+#include "cmpmap.h" /* Compound Mappings */
+#include "frame.h" /* Parent Frame class */
+#include "frameset.h" /* Interface definition for this class */
+#include "cmpframe.h" /* Compound coordinate frames */
+
+/* Error code definitions. */
+/* ----------------------- */
+#include "ast_err.h" /* AST error codes */
+
+/* C header files. */
+/* --------------- */
+#include <ctype.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.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 int (* parent_getobjsize)( AstObject *, int * );
+static void (* parent_clear)( AstObject *, const char *, int * );
+static int (* parent_getusedefs)( AstObject *, int * );
+static void (* parent_vset)( AstObject *, const char *, char **, va_list, int * );
+
+#if defined(THREAD_SAFE)
+static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
+#endif
+
+/* Define macros for accessing each item of thread specific global data. */
+#ifdef THREAD_SAFE
+
+/* Define how to initialise thread-specific globals. */
+#define GLOBAL_inits \
+ globals->Class_Init = 0; \
+ globals->GetAttrib_Buff[ 0 ] = 0; \
+ globals->Integrity_Frame = NULL; \
+ globals->Integrity_Method = ""; \
+ globals->Integrity_Lost = 0; \
+ globals->GetAllVariants_Buff[ 0 ] = 0; \
+
+/* Create the function that initialises global data for this module. */
+astMAKE_INITGLOBALS(FrameSet)
+
+/* Define macros for accessing each item of thread specific global data. */
+#define class_init astGLOBAL(FrameSet,Class_Init)
+#define class_vtab astGLOBAL(FrameSet,Class_Vtab)
+#define getattrib_buff astGLOBAL(FrameSet,GetAttrib_Buff)
+#define integrity_frame astGLOBAL(FrameSet,Integrity_Frame)
+#define integrity_method astGLOBAL(FrameSet,Integrity_Method)
+#define integrity_lost astGLOBAL(FrameSet,Integrity_Lost)
+#define getallvariants_buff astGLOBAL(FrameSet,GetAllVariants_Buff)
+
+
+
+/* If thread safety is not needed, declare and initialise globals at static
+ variables. */
+#else
+
+/* Buffer returned by GetAttrib. */
+static char getattrib_buff[ AST__FRAMESET_GETATTRIB_BUFF_LEN + 1 ];
+
+/* Variables associated with preserving FrameSet integrity. */
+static AstFrame *integrity_frame = NULL; /* Pointer to copy of current Frame */
+static const char *integrity_method = ""; /* Name of method being used */
+static int integrity_lost = 0; /* Current Frame modified? */
+
+
+/* Define the class virtual function table and its initialisation flag
+ as static variables. */
+static AstFrameSetVtab class_vtab; /* Virtual function table */
+static int class_init = 0; /* Virtual function table initialised? */
+
+/* String buffers. */
+static char getallvariants_buff[ AST__FRAMESET_GETALLVARIANTS_BUFF_LEN + 1 ];
+
+#endif
+
+
+/* Prototypes for Private Member Functions. */
+/* ======================================== */
+static AstAxis *GetAxis( AstFrame *, int, int * );
+static AstFrame *GetFrame( AstFrameSet *, int, int * );
+static AstFrame *PickAxes( AstFrame *, int, const int[], AstMapping **, int * );
+static AstFrameSet *Convert( AstFrame *, AstFrame *, const char *, int * );
+static AstFrameSet *ConvertX( AstFrame *, AstFrame *, const char *, int * );
+static AstFrameSet *FindFrame( AstFrame *, AstFrame *, const char *, int * );
+static AstLineDef *LineDef( AstFrame *, const double[2], const double[2], int * );
+static AstMapping *CombineMaps( AstMapping *, int, AstMapping *, int, int, int * );
+static AstMapping *GetMapping( AstFrameSet *, int, 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 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 *GetAttrib( AstObject *, const char *, int * );
+static const char *GetDomain( AstFrame *, int * );
+static const char *GetFormat( AstFrame *, int, int * );
+static const char *GetLabel( AstFrame *, int, int * );
+static const char *GetSymbol( AstFrame *, int, int * );
+static const char *GetTitle( AstFrame *, int * );
+static const char *GetUnit( AstFrame *, int, int * );
+static const char *GetAllVariants( AstFrameSet *, 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 AxAngle( AstFrame *, const double[], const double[], int, int * );
+static double AxDistance( AstFrame *, int, double, double, int * );
+static double AxOffset( AstFrame *, int, double, double, int * );
+static double Distance( AstFrame *, const double[], const double[], int * );
+static double Centre( AstFrame *, int, double, double, int * );
+static double Gap( AstFrame *, int, double, int *, int * );
+static double Offset2( AstFrame *, const double[2], double, double, double[2], int * );
+static double Rate( AstMapping *, double *, int, int, int * );
+static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * );
+static int Equal( AstObject *, AstObject *, int * );
+static int Fields( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * );
+static int ForceCopy( AstFrameSet *, int, int * );
+static int GetActiveUnit( AstFrame *, int * );
+static int GetBase( AstFrameSet *, int * );
+static int GetCurrent( AstFrameSet *, int * );
+static int GetDigits( AstFrame *, int * );
+static int GetDirection( AstFrame *, int, int * );
+static int GetIsLinear( AstMapping *, int * );
+static int GetMatchEnd( AstFrame *, int * );
+static int GetMaxAxes( AstFrame *, int * );
+static int GetMinAxes( AstFrame *, int * );
+static int GetNaxes( AstFrame *, int * );
+static int GetNframe( AstFrameSet *, int * );
+static int GetNin( AstMapping *, int * );
+static int GetNode( AstFrameSet *, int, int *, int *, AstMapping **, int *, int * );
+static int GetNout( AstMapping *, int * );
+static int GetObjSize( AstObject *, int * );
+static int GetPermute( AstFrame *, int * );
+static int GetPreserveAxes( AstFrame *, int * );
+static int GetTranForward( AstMapping *, int * );
+static int GetTranInverse( AstMapping *, int * );
+static int GetVarFrm( AstFrameSet *, int, int * );
+static int IsUnitFrame( AstFrame *, int * );
+static int LineContains( AstFrame *, AstLineDef *, int, double *, int * );
+static int LineCrossing( AstFrame *, AstLineDef *, AstLineDef *, double **, int * );
+static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
+static int Span( AstFrameSet *, AstFrame **, int, int, int, AstMapping **, int *, int * );
+static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
+static int TestActiveUnit( AstFrame *, int * );
+static int TestAttrib( AstObject *, const char *, int * );
+static int TestBase( AstFrameSet *, int * );
+static int TestCurrent( AstFrameSet *, int * );
+static int TestDigits( AstFrame *, int * );
+static int TestDirection( AstFrame *, int, int * );
+static int TestDomain( AstFrame *, int * );
+static int TestFormat( AstFrame *, int, int * );
+static int TestLabel( AstFrame *, int, int * );
+static int TestMatchEnd( AstFrame *, int * );
+static int TestMaxAxes( AstFrame *, int * );
+static int TestMinAxes( AstFrame *, int * );
+static int TestPermute( AstFrame *, int * );
+static int TestPreserveAxes( AstFrame *, int * );
+static int TestSymbol( AstFrame *, int, int * );
+static int TestTitle( AstFrame *, int * );
+static int TestUnit( AstFrame *, int, int * );
+static int Unformat( AstFrame *, int, const char *, double *, int * );
+static int ValidateAxis( AstFrame *, int, int, const char *, int * );
+static int ValidateFrameIndex( AstFrameSet *, int, const char *, int * );
+static void AddFrame( AstFrameSet *, int, AstMapping *, AstFrame *, int * );
+static void AppendAxes( AstFrameSet *, AstFrame *, int * );
+static void AxNorm( AstFrame *, int, int, int, double *, int * );
+static void CheckPerm( AstFrame *, const int *, const char *, int * );
+static void Clear( AstObject *, const char *, int * );
+static void ClearAttrib( AstObject *, const char *, int * );
+static void ClearBase( AstFrameSet *, int * );
+static void ClearCurrent( AstFrameSet *, int * );
+static void ClearDigits( AstFrame *, int * );
+static void ClearDirection( AstFrame *, int, int * );
+static void ClearDomain( AstFrame *, int * );
+static void ClearFormat( AstFrame *, int, int * );
+static void ClearLabel( AstFrame *, int, int * );
+static void ClearMatchEnd( AstFrame *, int * );
+static void ClearMaxAxes( AstFrame *, int * );
+static void ClearMinAxes( AstFrame *, int * );
+static void ClearPermute( AstFrame *, int * );
+static void ClearPreserveAxes( AstFrame *, int * );
+static void ClearSymbol( AstFrame *, int, int * );
+static void ClearTitle( AstFrame *, int * );
+static void ClearUnit( AstFrame *, int, int * );
+static void Copy( const AstObject *, AstObject *, int * );
+static void Delete( AstObject *, int * );
+static void Dump( AstObject *, AstChannel *, int * );
+static void Intersect( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * );
+static void LineOffset( AstFrame *, AstLineDef *, double, double, double[2], int * );
+static void MatchAxes( AstFrame *, AstFrame *, int *, 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 PermAxes( AstFrame *, const int[], int * );
+static void PrimaryFrame( AstFrame *, int, AstFrame **, int *, int * );
+static void RecordIntegrity( AstFrameSet *, int * );
+static void AddVariant( AstFrameSet *, AstMapping *, const char *, int * );
+static void MirrorVariants( AstFrameSet *, int, int * );
+static void RemapFrame( AstFrameSet *, int, AstMapping *, int * );
+static void RemoveFrame( AstFrameSet *, int, int * );
+static void RemoveMirrors( AstFrameSet *, int, int * );
+static void ReportPoints( AstMapping *, int, AstPointSet *, AstPointSet *, int * );
+static void Resolve( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * );
+static void RestoreIntegrity( AstFrameSet *, int * );
+static void SetActiveUnit( AstFrame *, int, int * );
+static void SetAttrib( AstObject *, const char *, int * );
+static void SetAxis( AstFrame *, int, AstAxis *, int * );
+static void SetBase( AstFrameSet *, int, int * );
+static void SetCurrent( AstFrameSet *, int, int * );
+static void SetDigits( AstFrame *, int, int * );
+static void SetDirection( AstFrame *, int, int, int * );
+static void SetDomain( AstFrame *, const char *, int * );
+static void SetFormat( AstFrame *, int, const char *, int * );
+static void SetLabel( AstFrame *, int, const char *, int * );
+static void SetMatchEnd( AstFrame *, int, int * );
+static void SetMaxAxes( AstFrame *, int, int * );
+static void SetMinAxes( AstFrame *, int, int * );
+static void SetPermute( AstFrame *, int, int * );
+static void SetPreserveAxes( AstFrame *, int, int * );
+static void SetSymbol( AstFrame *, int, const char *, int * );
+static void SetTitle( AstFrame *, const char *, int * );
+static void SetUnit( AstFrame *, int, const char *, int * );
+static void TidyNodes( AstFrameSet *, int * );
+static void VSet( AstObject *, const char *, char **, va_list, int * );
+static void ValidateAxisSelection( AstFrame *, int, const int *, const char *, int * );
+
+static double GetBottom( AstFrame *, int, int * );
+static int TestBottom( AstFrame *, int, int * );
+static void ClearBottom( AstFrame *, int, int * );
+static void SetBottom( AstFrame *, int, double, int * );
+
+static double GetTop( AstFrame *, int, int * );
+static int TestTop( AstFrame *, int, int * );
+static void ClearTop( AstFrame *, int, int * );
+static void SetTop( AstFrame *, int, double, int * );
+
+static double GetEpoch( AstFrame *, int * );
+static int TestEpoch( AstFrame *, int * );
+static void ClearEpoch( AstFrame *, int * );
+static void SetEpoch( AstFrame *, double, int * );
+
+static double GetDtai( AstFrame *, int * );
+static int TestDtai( AstFrame *, int * );
+static void ClearDtai( AstFrame *, int * );
+static void SetDtai( AstFrame *, double, int * );
+
+static double GetDut1( AstFrame *, int * );
+static int TestDut1( AstFrame *, int * );
+static void ClearDut1( AstFrame *, int * );
+static void SetDut1( AstFrame *, double, int * );
+
+static double GetObsAlt( AstFrame *, int * );
+static int TestObsAlt( AstFrame *, int * );
+static void ClearObsAlt( AstFrame *, int * );
+static void SetObsAlt( AstFrame *, double, int * );
+
+static double GetObsLat( AstFrame *, int * );
+static int TestObsLat( AstFrame *, int * );
+static void ClearObsLat( AstFrame *, int * );
+static void SetObsLat( AstFrame *, double, int * );
+
+static double GetObsLon( AstFrame *, int * );
+static int TestObsLon( AstFrame *, int * );
+static void ClearObsLon( AstFrame *, int * );
+static void SetObsLon( AstFrame *, double, int * );
+
+static int GetUseDefs( AstObject *, int * );
+
+static AstSystemType GetSystem( AstFrame *, int * );
+static int TestSystem( AstFrame *, int * );
+static void ClearSystem( AstFrame *, int * );
+static void SetSystem( AstFrame *, AstSystemType, int * );
+
+static AstSystemType GetAlignSystem( AstFrame *, int * );
+static int TestAlignSystem( AstFrame *, int * );
+static void ClearAlignSystem( AstFrame *, int * );
+static void SetAlignSystem( AstFrame *, AstSystemType, int * );
+
+static const char *GetVariant( AstFrameSet *, int * );
+static int TestVariant( AstFrameSet *, int * );
+static void ClearVariant( AstFrameSet *, int * );
+static void SetVariant( AstFrameSet *, const char *, 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 FrameSet axis value by skipping leading fields.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* const char *Abbrev( AstFrame *this, int axis, const char *fmt,
+* const char *str1, const char *str2, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astAbbrev
+* method inherited from the Frame class).
+
+* Description:
+* This function compares two FrameSet 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 FrameSet.
+* axis
+* The number of the FrameSet 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 FrameSet axis.
+* - A pointer to the start of "str2" will be returned if this
+* function is invoked with the global error status set, or if it
+* should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ const char *result; /* Pointer value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return str2;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astAbbrev" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astAbbrev method to perform the processing. Annul the Frame
+ pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astAbbrev( fr, axis, fmt, str1, str2 );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = str2;
+
+/* Return the result. */
+ return result;
+}
+
+static void AddFrame( AstFrameSet *this, int iframe, AstMapping *map0,
+ AstFrame *frame, int *status ) {
+/*
+*++
+* Name:
+c astAddFrame
+f AST_ADDFRAME
+
+* Purpose:
+* Add a Frame to a FrameSet to define a new coordinate system.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frameset.h"
+c void astAddFrame( AstFrameSet *this, int iframe, AstMapping *map,
+c AstFrame *frame )
+f CALL AST_ADDFRAME( THIS, IFRAME, MAP, FRAME, STATUS )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+c This function adds a new Frame and an associated Mapping to a
+f This routine adds a new Frame and an associated Mapping to a
+* FrameSet so as to define a new coordinate system, derived from
+* one which already exists within the FrameSet. The new Frame then
+* becomes the FrameSet's current Frame.
+*
+c This function
+f This routine
+* may also be used to merge two FrameSets, or to append extra axes
+* to every Frame in a FrameSet.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the FrameSet.
+c iframe
+f IFRAME = INTEGER (Given)
+* The index of the Frame within the FrameSet which describes
+* the coordinate system upon which the new one is to be based.
+* This value should lie in the range from 1 to the number of
+* Frames already in the FrameSet (as given by its Nframe
+* attribute). As a special case, AST__ALLFRAMES may be supplied,
+* in which case the axes defined by the supplied Frame are appended
+* to every Frame in the FrameSet (see the Notes section for details).
+c map
+f MAP = INTEGER (Given)
+* Pointer to a Mapping which describes how to convert
+* coordinates from the old coordinate system (described by the
+c Frame with index "iframe") into coordinates in the new
+f Frame with index IFRAME) into coordinates in the new
+* system. The Mapping's forward transformation should perform
+* this conversion, and its inverse transformation should
+* convert in the opposite direction. The supplied Mapping is ignored
+c if parameter "iframe"is equal to AST__ALLFRAMES.
+f if parameter IFRAME is equal to AST__ALLFRAMES.
+c frame
+f FRAME = INTEGER (Given)
+* Pointer to a Frame that describes the new coordinate system.
+* Any class of Frame may be supplied (including Regions and
+* FrameSets).
+*
+c This function may also be used to merge two FrameSets by
+c supplying a pointer to a second FrameSet for this parameter
+f This routine may also be used to merge two FrameSets by
+f supplying a pointer to a second FrameSet for this argument
+* (see the Notes section for details).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - Deep copies of the supplied
+c "mapping" and "frame"
+f MAPPING and FRAME
+* objects are stored within the modified FrameSet. So any changes made
+* to the FrameSet after calling this method will have no effect on the
+* supplied Mapping and Frame objects.
+* - A value of AST__BASE or AST__CURRENT may be given for the
+c "iframe" parameter to specify the base Frame or the current
+f IFRAME argument to specify the base Frame or the current
+* Frame respectively.
+c - This function sets the value of the Current attribute for the
+f - This routine sets the value of the Current attribute for the
+* FrameSet so that the new Frame subsequently becomes the current
+* Frame.
+* - The number of input coordinate values accepted by the supplied
+* Mapping (its Nin attribute) must match the number of axes in the
+c Frame identified by the "iframe" parameter. Similarly, the
+f Frame identified by the IFRAME argument. Similarly, the
+* number of output coordinate values generated by this Mapping
+* (its Nout attribute) must match the number of axes in the new
+* Frame.
+* - As a special case, if a pointer to a FrameSet is given for the
+c "frame" parameter, this is treated as a request to merge a pair of
+f FRAME argument, this is treated as a request to merge a pair of
+* FrameSets. This is done by appending all the new Frames (in the
+c "frame" FrameSet) to the original FrameSet, while preserving
+f FRAME FrameSet) to the original FrameSet, while preserving
+* their order and retaining all the inter-relationships
+* (i.e. Mappings) between them. The two sets of Frames are
+* inter-related within the merged FrameSet by using the Mapping
+* supplied. This should convert between the Frame identified by
+c the "iframe" parameter (in the original FrameSet) and the current
+c Frame of the "frame" FrameSet. This latter Frame becomes the
+f the IFRAME argument (in the original FrameSet) and the current
+f Frame of the FRAME FrameSet. This latter Frame becomes the
+* current Frame in the merged FrameSet.
+* - As another special case, if a value of AST__ALLFRAMES is supplied
+* for parameter
+c "iframe",
+f IFRAME,
+* then the supplied Mapping is ignored, and the axes defined by the
+* supplied Frame are appended to each Frame in the FrameSet. In detail,
+* each Frame in the FrameSet is replaced by a CmpFrame containing the
+* original Frame and the Frame specified by parameter
+c "frame".
+f FRAME.
+* In addition, each Mapping in the FrameSet is replaced by a CmpMap
+* containing the original Mapping and a UnitMap in parallel. The Nin and
+* Nout attributes of the UnitMap are set equal to the number of axes
+* in the supplied Frame. Each new CmpMap is simplified using
+c astSimplify
+f AST_SIMPLIFY
+* before being stored in the FrameSet.
+
+*--
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to Frame identified by "iframe" */
+ AstFrameSet *frameset; /* Pointer to new FrameSet (if given) */
+ AstMapping *inode_map; /* Temporarily saved Mapping pointer */
+ AstMapping *map; /* The supplied Mapping */
+ AstMapping *next_map; /* Temporarily saved Mapping pointer */
+ int current; /* Current Frame index in merged FrameSet */
+ int current_node; /* Node number for current Frame */
+ int ifr; /* Loop counter for Frames */
+ int inode; /* Loop counter for nodes */
+ int inode_invert; /* Temporarily saved invert flag value */
+ int inode_link; /* Temporarily saved link value */
+ int naxes; /* Number of Frame axes */
+ int ncoord; /* Number of Mapping coordinates per point */
+ int next; /* Number of next node in path */
+ int next_invert; /* Temporarily saved invert flag value */
+ int next_link; /* Temporarily saved link value */
+ int nframe; /* Number of Frames in merged FrameSet */
+ int nnode; /* Number of nodes in merged FrameSet */
+ int node_zero; /* Location of "node zero" after merging */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* First handle cases where we are appending axes to the existing
+ Frames in a FrameSet. */
+ if( iframe == AST__ALLFRAMES ) {
+ AppendAxes( this, frame, status );
+ return;
+ }
+
+/* Now handle cases where we are adding a new Frame into the FrameSet.
+ Initialise variables to avoid "used of uninitialised variable"
+ messages from dumb compilers. */
+ inode_map = NULL;
+ next_map = NULL;
+ inode_invert = 0;
+ next = 0;
+ next_invert = 0;
+ next_link = 0;
+
+/* If a FrameSet was supplied instead of a Mapping, use the Mapping from
+ its base Frame to its current Frame. */
+ if( astIsAFrameSet( map0 ) ) {
+ map = astGetMapping( map0, AST__BASE, AST__CURRENT );
+ } else {
+ map = astClone( map0 );
+ }
+
+/* Validate and translate the Frame index supplied. */
+ iframe = astValidateFrameIndex( this, iframe, "astAddFrame" );
+
+/* Obtain a pointer to the Frame from which the new coordinate system
+ will be derived and determine how many axes it has. Annul the Frame
+ pointer afterwards. */
+ if ( astOK ) {
+ fr = astGetFrame( this, iframe );
+ naxes = astGetNaxes( fr );
+ fr = astAnnul( fr );
+
+/* Obtain the number of input coordinate values per point for the
+ Mapping supplied and check that this matches the number of axes
+ obtained above. Report an error if it does not. */
+ ncoord = astGetNin( map );
+ if ( astOK && ( naxes != ncoord ) ) {
+ astError( AST__NCPIN, "astAddFrame(%s): Bad number of %s input "
+ "coordinate values (%d).", status, astGetClass( this ),
+ astGetClass( map ), ncoord );
+ astError( AST__NCPIN, "The %s given should accept %d coordinate "
+ "value%s for each input point.", status, astGetClass( map ), naxes,
+ ( naxes == 1 ) ? "" : "s" );
+ }
+ }
+
+/* Similarly, obtain the number of output coordinate values per point
+ for the Mapping and check that this equals the number of axes for
+ the Frame supplied. Report an error if necessary. */
+ if ( astOK ) {
+ ncoord = astGetNout( map );
+ naxes = astGetNaxes( frame );
+ if ( astOK && ( ncoord != naxes ) ) {
+ astError( AST__NCPIN, "astAddFrame(%s): Bad number of %s output "
+ "coordinate values (%d).", status, astGetClass( this ),
+ astGetClass( map ), ncoord );
+ astError( AST__NCPIN, "The %s given should generate %d "
+ "coordinate value%s for each output point.", status,
+ astGetClass( map ), naxes, ( naxes == 1 ) ? "" : "s" );
+ }
+ }
+
+/* Normal Frame supplied. */
+/* ====================== */
+/* Check that the Frame supplied is not a FrameSet (handling a
+ FrameSet is a special case which is addressed later). */
+ if ( !astIsAFrameSet( frame ) && astOK ) {
+
+/* Increase the size of the FrameSet's arrays to accommodate one new
+ Frame. */
+ this->frame = astGrow( this->frame, this->nframe + 1,
+ sizeof( AstFrame * ) );
+ this->varfrm = astGrow( this->varfrm, this->nframe + 1,
+ sizeof( int ) );
+ this->node = astGrow( this->node, this->nframe + 1, sizeof( int ) );
+ this->map = astGrow( this->map, this->nnode, sizeof( AstMapping * ) );
+ this->link = astGrow( this->link, this->nnode, sizeof( int ) );
+ this->invert = astGrow( this->invert, this->nnode, sizeof( int ) );
+ if ( astOK ) {
+
+/* Copy pointers to the Frame and Mapping supplied and store these pointers
+ in the FrameSet arrays. */
+ this->frame[ this->nframe ] = astCopy( frame );
+ this->map[ this->nnode - 1 ] = astCopy( map );
+
+/* Indicate the Frame does not reflect the variant Mappings of any other
+ Frame. */
+ this->varfrm[ this->nframe ] = 0;
+
+/* Associate the Frame with the Mapping via the "node" array. */
+ this->node[ this->nframe ] = this->nnode;
+
+/* Add a "link" value which identifies the node from which the new
+ node is derived and store the current value of the Invert attribute
+ for the Mapping. */
+ this->link[ this->nnode - 1 ] = this->node[ iframe - 1 ];
+ this->invert[ this->nnode - 1 ] = astGetInvert( map );
+
+/* If successful, increment the FrameSet's Frame and node counts and
+ set the Current attribute so that the new Frame becomes the current
+ Frame. */
+ if ( astOK ) {
+ this->nframe++;
+ this->nnode++;
+ astSetCurrent( this, this->nframe );
+
+/* If an error occurred while filling the FrameSet's arrays, clear any values
+ that may have been added, annulling any copied pointers. */
+ } else {
+ this->frame[ this->nframe ] =
+ astAnnul( this->frame[ this->nframe ] );
+ this->node[ this->nframe ] = -1;
+ this->map[ this->nnode - 1 ] =
+ astAnnul( this->map[ this->nnode - 1 ] );
+ this->link[ this->nnode - 1 ] = -1;
+ }
+ }
+
+/* FrameSet supplied. */
+/* ================== */
+/* If the Frame supplied is a FrameSet, we handle this as a special
+ case by merging the two FrameSets (so that the final result
+ contains references to all the Frames from both FrameSets). */
+ } else if ( astOK ) {
+
+/* Obtain a pointer to the FrameSet structure containing the new Frame
+ references and calculate how many Frames and nodes the combined
+ FrameSet will contain. */
+ frameset = (AstFrameSet *) frame;
+ nframe = this->nframe + frameset->nframe;
+ nnode = this->nnode + frameset->nnode;
+
+/* Extend the original FrameSet's arrays to accommodate the new Frames
+ and nodes. */
+ this->frame = astGrow( this->frame, nframe, sizeof( AstFrame * ) );
+ this->varfrm = astGrow( this->varfrm, nframe, sizeof( int ) );
+ this->node = astGrow( this->node, nframe, sizeof( int ) );
+ this->map = astGrow( this->map, nnode - 1, sizeof( AstMapping * ) );
+ this->link = astGrow( this->link, nnode - 1, sizeof( int ) );
+ this->invert = astGrow( this->invert, nnode - 1, sizeof( int ) );
+
+/* If OK, loop to transfer the new Frame data into the new array
+ elements, cloning each Frame pointer. Increment each "node" value
+ to allow for the new node numbering which will apply when the new
+ node data is appended to the new arrays. */
+ if ( astOK ) {
+ for ( ifr = 1; ifr <= frameset->nframe; ifr++ ) {
+ this->frame[ this->nframe + ifr - 1 ] =
+ astCopy( frameset->frame[ ifr - 1 ] );
+ this->node[ this->nframe + ifr - 1 ] =
+ frameset->node[ ifr - 1 ] + this->nnode;
+ if( frameset->varfrm[ ifr - 1 ] > 0 ) {
+ this->varfrm[ this->nframe + ifr - 1 ] =
+ frameset->varfrm[ ifr - 1 ] + this->nframe;
+ } else {
+ this->varfrm[ this->nframe + ifr - 1 ] = 0;
+ }
+ }
+
+/* Similarly, transfer the new node data, cloning each Mapping
+ pointer. Increment each "link" value to allow for the new node
+ numbering. */
+ for ( inode = 1; inode < frameset->nnode; inode++ ) {
+ this->map[ this->nnode + inode - 1 ] =
+ astCopy( frameset->map[ inode - 1 ] );
+ this->link[ this->nnode + inode - 1 ] =
+ frameset->link[ inode - 1 ] + this->nnode;
+ this->invert[ this->nnode + inode - 1 ] =
+ frameset->invert[ inode - 1 ];
+ }
+
+/* In transferring the node data (above), we left an empty array
+ element which will later be filled with data corresponding to node
+ zero in the new FrameSet (there are no data to be copied for this
+ node). Initialise the data for this element to null values. */
+ this->map[ this->nnode - 1 ] = NULL;
+ this->link[ this->nnode - 1 ] = -1;
+ this->invert[ this->nnode - 1 ] = -1;
+
+/* Determine which is the current Frame in the new FrameSet and
+ convert this into the corresponding Frame number in the combined
+ one. */
+ current = astGetCurrent( frameset ) + this->nframe;
+
+/* We must now form a new link between this Frame and Frame "iframe"
+ (using the Mapping supplied) in order to inter-relate the Frames
+ from the two FrameSets. However, this cannot be done immediately
+ because in general the node corresponding to Frame "current" will
+ already have a link pointing to another node. Moreover, the node
+ which was originally node zero (in the new FrameSet) still has
+ no data in our merged FrameSet.
+
+ To overcome this, we must re-structure the links within the
+ transferred data. We do this by starting at the node corresponding
+ to Frame "current" and working back through each link until the
+ original node zero is reached. At each step along this path, we
+ reverse the direction of the link. This involves shifting the
+ associated data by one step along the path, so that it becomes
+ associated with the next node. This results in the final
+ (initialised-to-null) node acquiring some data, and the starting
+ node being left free to receive our new link.
+
+ We compensate for reversing the links by reversing the sense of the
+ "invert" flag associated with each Mapping along the path, so that
+ the overall structure of the FrameSet is unchanged. */
+
+/* Identify the starting node (the one corresponding to Frame
+ "current"). */
+ if ( astOK ) {
+ current_node = this->node[ current - 1 ];
+
+/* Obtain the value which a "link" element will now have if it
+ originally identified node zero in the new FrameSet. We will use
+ this value to detect the end of the path. */
+ node_zero = this->nnode;
+
+/* If we are not already at "node zero", save the data for the current
+ node. */
+ if ( current_node != node_zero ) {
+ inode_map = this->map[ current_node - 1 ];
+ inode_link = this->link[ current_node - 1 ];
+ inode_invert = this->invert[ current_node - 1 ];
+
+/* Reset the node's data to null values (pending setting up the new
+ link using the Mapping supplied). */
+ this->map[ current_node - 1 ] = NULL;
+ this->link[ current_node - 1 ] = -1;
+ this->invert[ current_node - 1 ] = -1;
+
+/* Identify the next node in the path. */
+ next = inode_link;
+ }
+
+/* Follow the path until "node zero" is reached. */
+ inode = current_node;
+ while( inode != node_zero ) {
+
+/* If the next node on the path is not "node zero", save its data
+ (because we are about to write over it). */
+ if ( next != node_zero ) {
+ next_map = this->map[ next - 1 ];
+ next_link = this->link[ next - 1 ];
+ next_invert = this->invert[ next - 1 ];
+ }
+
+/* Reverse the link from the current node to the "next" node. This
+ involves transferring the "map" and "invert" values to the "next"
+ node and inverting the sense of the latter to compensate. Make the
+ "next" node point back to the current one. */
+ this->map[ next - 1 ] = inode_map;
+ this->link[ next - 1 ] = inode;
+ this->invert[ next - 1 ] = !inode_invert;
+
+/* Move on to consider the next node. */
+ inode = next;
+
+/* If we have not reached "node zero" yet, transfer the node data we
+ saved above into the variables from which it will be transferred to
+ the following node on the next pass through this loop. */
+ if ( inode != node_zero ) {
+ inode_map = next_map;
+ inode_link = next_link;
+ inode_invert = next_invert;
+
+/* Identify the node that follows the next one. */
+ next = inode_link;
+ }
+ }
+
+/* Once the necessary links have been re-structured, establish the new
+ link that inter-relates the Frames from the two FrameSets. */
+ this->map[ current_node - 1 ] = astCopy( map );
+ this->link[ current_node - 1 ] = this->node[ iframe - 1 ];
+ this->invert[ current_node - 1 ] = astGetInvert( map );
+ }
+
+/* If successful, update the Frame and node counts and make the
+ appropriate Frame current. */
+ if ( astOK ) {
+ this->nframe = nframe;
+ this->nnode = nnode;
+ astSetCurrent( this, current );
+
+/* If an error occurred, loop through all the new Frame and node array
+ elements and clear them, ensuring that any remaining Object
+ pointers are annulled. */
+ } else {
+ for ( ifr = 1; ifr <= frameset->nframe; ifr++ ) {
+ this->frame[ this->nframe + ifr - 1 ] =
+ astAnnul( this->frame[ this->nframe + ifr - 1 ] );
+ this->node[ this->nframe + ifr - 1 ] = -1;
+ this->varfrm[ this->nframe + ifr - 1 ] = 0;
+ }
+ for ( inode = 0; inode < frameset->nnode; inode++ ) {
+ this->map[ this->nnode + inode - 1 ] =
+ astAnnul( this->map[ this->nnode + inode - 1 ] );
+ this->link[ this->nnode + inode - 1 ] = -1;
+ this->invert[ this->nnode + inode - 1 ] = -1;
+ }
+ }
+ }
+ }
+
+/* Annul the local pointer to the supplied Mapping. */
+ map = astAnnul( map );
+}
+
+static void AddVariant( AstFrameSet *this, AstMapping *map,
+ const char *name, int *status ) {
+/*
+*++
+* Name:
+c astAddVariant
+f AST_ADDVARIANT
+
+* Purpose:
+* Store a new variant Mapping for the current Frame in a FrameSet.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frameset.h"
+c void astAddVariant( AstFrameSet *this, AstMapping *map,
+c const char *name )
+f CALL AST_ADDVARIANT( THIS, MAP, NAME, STATUS )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+c This function
+f This routine
+* allows a new variant Mapping to be stored with the current Frame
+* in a FrameSet. See the "Variant" attribute for more details. It can
+* also be used to rename the currently selected variant Mapping.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the FrameSet.
+c map
+f MAP = INTEGER (Given)
+* Pointer to a Mapping which describes how to convert
+* coordinates from the current Frame to the new variant of the
+* current Frame. If
+c NULL
+f AST__NULL
+* is supplied, then the name associated with the currently selected
+* variant of the current Frame is set to the value supplied for
+c "name", but no new variant is added.
+f NAME, but no new variant is added.
+c name
+f NAME = CHARACTER * ( * ) (Given)
+* The name to associate with the new variant Mapping (or the currently
+* selected variant Mapping if
+c "map" is NULL).
+f MAP is AST__NULL).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - The newly added Variant becomes the current variant on exit (this is
+* equivalent to setting the Variant attribute to the value supplied for
+c "name).
+f NAME).
+* - An error is reported if a variant with the supplied name already
+* exists in the current Frame.
+* - An error is reported if the current Frame is a mirror for the
+* variant Mappings in another Frame. This is only the case if the
+c astMirrorVariants function
+f AST_MIRRORVARIANTS routine
+* has been called to make the current Frame act as a mirror.
+
+*--
+*/
+
+/* Local Variables: */
+ AstCmpMap *map2;
+ AstFrame *frm;
+ AstFrame *tfrm;
+ AstFrame *vfrm;
+ AstFrameSet *tfs;
+ AstFrameSet *vfs;
+ AstMapping *map1;
+ AstMapping *map3;
+ char *myname;
+ const char *dom;
+ int icur;
+ int ifrm;
+ int new;
+ int nfrm;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get the one-based index of the current Frame. */
+ icur = astGetCurrent( this );
+
+/* Report an error if the current Frame is just a mirror. */
+ if( this->varfrm[ icur - 1 ] > 0 && astOK ) {
+ astError( AST__MIRRO, "astAddVariant(%s): Illegal attempt to "
+ "add a variant Mapping to a mirror Frame (programming "
+ "error).", status, astGetClass( this ) );
+ }
+
+/* Get a copy of the supplied string and clean it. */
+ myname = astStore( NULL, name, strlen( name ) + 1 );
+ astRemoveLeadingBlanks( myname );
+ astChrCase( NULL, myname, 1, 0 );
+ if( astOK ) {
+ myname[ astChrLen( myname ) ] = 0;
+
+/* Get the Variants FrameSet for the current Frame in "this". */
+ frm = astGetFrame( this, icur );
+ vfs = astGetFrameVariants( frm );
+
+/* If current Frame of this has no Variant FrameSet, create a Variants
+ FrameSet containing a copy of the current Frame (retain its Domain
+ as the default variant name). */
+ if( !vfs ) {
+ tfrm = astCopy( frm );
+ vfs = astFrameSet( tfrm, " ", status );
+ tfrm = astAnnul( tfrm );
+ new = 1;
+ } else {
+ new = 0;
+ }
+
+/* Check the Variants FrameSet does not already contain a Frame with
+ a Domain equal to the supplied name. */
+ nfrm = astGetNframe( vfs );
+ for( ifrm = 0; ifrm < nfrm && astOK; ifrm++ ) {
+ vfrm = astGetFrame( vfs, ifrm + 1 );
+ dom = astGetDomain( vfrm );
+ if( astOK && !strcmp( dom, myname ) ) {
+ astError( AST__BDVNM, "astAddVariant(%s): Cannot add a "
+ "variant %s Frame with name '%s' because one "
+ "already exists in the %s (programming "
+ "error).", status, astGetClass( this ),
+ astGetDomain( frm ), myname, astGetClass( this ) );
+ }
+ vfrm = astAnnul( vfrm );
+ }
+
+/* If no Mapping was supplied, just set the name of the currently
+ selected variant. The names are stored in the Domain attribute of
+ the Frames in the variants FrameSet, so set teh DOmain for the current
+ Frame. */
+ if( !map ){
+ vfrm = astGetFrame( vfs, AST__CURRENT );
+ astSetDomain( vfrm, name );
+ vfrm = astAnnul( vfrm );
+
+/* If a Mapping was supplied.... */
+ } else {
+
+/* Get the Mapping from the current Frame in the variants FrameSet to the
+ current Frame in "this". Temporarily match the Domains so that
+ astConvert can work. */
+ vfrm = astGetFrame( vfs, AST__CURRENT );
+ dom = astGetDomain( frm );
+ if( dom ) dom = astStore( NULL, dom, strlen( dom ) + 1 );
+ astSetDomain( frm, astGetDomain( vfrm ) );
+ tfs = astConvert( vfrm, frm, "" );
+ astSetDomain( frm, dom );
+ if( tfs ) {
+ map1 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
+ tfs = astAnnul( tfs );
+
+/* Concatenate it with the supplied Mapping to get the mapping from the
+ current Frame in the Variants FrameSet to the new variant Frame. */
+ map2 = astCmpMap( map1, map, 1, " ", status );
+ map3 = astSimplify( map2 );
+
+/* Add a copy of parent Frame into Variants FrameSet, using the above
+ mapping to connect it to the original current Variants Frame. Set
+ its Domain to the supplied name. Re-instate the original current Frame
+ afterwards. Remove the variant frame info before adding it. */
+ (void) astAnnul( vfrm );
+ vfrm = astCopy( frm );
+ astSetFrameVariants( vfrm, NULL );
+ astSetDomain( vfrm, name );
+ icur = astGetCurrent( vfs );
+ astAddFrame( vfs, AST__CURRENT, map3, vfrm );
+ astSetCurrent( vfs, icur );
+
+/* Free resources. */
+ map1 = astAnnul( map1 );
+ map2 = astAnnul( map2 );
+ map3 = astAnnul( map3 );
+
+/* Report an error if a Mapping cannot be found from the new variant Frame
+ to the current Frame in "this". */
+ } else if( astOK ) {
+ astError( AST__INTER, "astAddVariant(%s): Cannot convert "
+ "from a %s with Domain '%s' to a %s with Domain "
+ "'%s' (internal programming error).", status,
+ astGetClass( this ), astGetClass( vfrm ),
+ astGetDomain( vfrm ), astGetClass( frm ),
+ astGetDomain( frm ) );
+ }
+
+/* Free resources. */
+ dom = astFree( (void *) dom );
+ vfrm = astAnnul( vfrm );
+ }
+
+/* If all is well, and the Variants FrameSet is new, store a pointer to
+ it in the current Frame of "this". */
+ if( new ) astSetFrameVariants( frm, vfs );
+
+/* Make the new Variant the current variant. */
+ if( map ) astSetVariant( this, name );
+
+/* Free remaining resources. */
+ frm = astAnnul( frm );
+ vfs = astAnnul( vfs );
+ }
+ myname = astFree( myname );
+}
+
+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 "frameset.h"
+* double Angle( AstFrame *this, const double a[], const double b[],
+* const double c[], int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astAngle
+* method inherited from the Frame class).
+
+* Description:
+* This function finds the angle at point B between the line joining points
+* A and B, and the line joining points C and B. These lines will in fact be
+* geodesic curves appropriate to the Frame in use. For instance, in
+* SkyFrame, they will be great circles.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* a
+* An array of double, with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the first point.
+* b
+* An array of double, with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the second point.
+* c
+* An array of double, with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the third point.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* astAngle
+* The angle in radians, from the line AB to the line CB. If the
+* Frame is 2-dimensional, it will be in the range $\pm \pi$,
+* and positive rotation is in the same sense as rotation from
+* the positive direction of axis 2 to the positive direction of
+* axis 1. If the Frame has more than 2 axes, a positive value will
+* always be returned in the range zero to $\pi$.
+
+* Notes:
+* - A value of AST__BAD will also be returned if points A and B are
+* co-incident, or if points B and C are co-incident.
+* - A value of AST__BAD will also be returned if this function is
+* invoked with the AST error status set, or if it should fail for
+* any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double result; /* Value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astAngle method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astAngle( fr, a, b, c );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = AST__BAD;
+
+/* Return the result. */
+ return result;
+}
+
+static void AppendAxes( AstFrameSet *this, AstFrame *frame, int *status ) {
+/*
+* Name:
+* AppendAxes
+
+* Purpose:
+* Append axes to every Frame in a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void AppendAxes( AstFrameSet *this, AstFrame *frame, int *status )
+
+* Class Membership:
+* FrameSet member function
+
+* Description:
+* This function replaces every Frame in the FrameSet with a CmpFrame
+* holding the original Frame and the supplied Frame. It also replaces
+* every Mapping in the FrameSet with a parallel CmpMap holding the
+* original Mapping and a UnitMap. The Nin and Nout attributes of every
+* UnitMap are equal to the number of axes in the supplied Frame. Each
+* CmpMap is simplified before being stored in the FrameSet.
+
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* frame
+* Pointer to a Frame holding the new axes to add to every Frame in
+* the FrameSet.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstCmpFrame *frm; /* Pointer to new Frame */
+ AstCmpMap *map; /* UnitMap to new Mapping */
+ AstUnitMap *umap; /* UnitMap to feed the new axes */
+ int iframe; /* Frame index */
+ int imap; /* Mapping index */
+ int inv_orig; /* Original value of Invert attribute */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Loop round every Frame in the FrameSet. */
+ for ( iframe = 0; iframe < this->nframe; iframe++ ) {
+
+/* Create a CmpFrame holding the original Frame and the new Frame. */
+ frm = astCmpFrame( this->frame[ iframe ], frame, " ", status );
+
+/* Annul the original Frame pointer and store the new CmpFrame pointer. */
+ (void) astAnnul( this->frame[ iframe ] );
+ this->frame[ iframe ] = (AstFrame *) frm;
+ }
+
+/* Create a UnitMap with the number of inputs and outputs equal to the
+ number of axes in the supplied Frame. */
+ umap = astUnitMap( astGetNaxes( frame ), " ", status );
+
+/* Loop round every Mapping in the FrameSet. */
+ for ( imap = 0; imap < this->nnode - 1; imap++ ) {
+
+/* The Invert attribute of the Mapping may have been changed via a
+ different pointer since it was first added into the FrameSet. To
+ ensure that the FrameSet continues to behave as was originally
+ intended, we set the Invert attribute back to the value it had when
+ the Mapping was first added into the FrameSet. First, note the
+ current value of the Invert flag so that it can be re-instated later. */
+ inv_orig = astGetInvert( this->map[ imap ] );
+ astSetInvert( this->map[ imap ], this->invert[ imap ] );
+
+/* Create a parallel CmpMap holding the original Mapping and the UnitMap. */
+ map = astCmpMap( this->map[ imap ], umap, 0, " ", status );
+
+/* Re-instate the original value for the Invert flag, and then annul the
+ original Mapping pointer. */
+ astSetInvert( this->map[ imap ], inv_orig );
+ (void) astAnnul( this->map[ imap ] );
+
+/* Simplify the new Mapping, and store it in the FrameSet. */
+ this->map[ imap ] = astSimplify( map );
+
+/* Store a copy of the Invert attribute that should be used with this
+ Mapping within the FrameSet (just in case it is modified via some
+ excternal reference). */
+ this->invert[ imap ] = astGetInvert( this->map[ imap ] );
+
+/* Annul the un-simplified Mapping pointer. */
+ map = astAnnul( map );
+ }
+
+/* Annul the UnitMap pointer. */
+ umap = astAnnul( umap );
+}
+
+static double AxAngle( AstFrame *this_frame, const double a[], const double b[], int axis, int *status ) {
+/*
+* Name:
+* AxAngle
+
+* Purpose:
+* Returns the angle from an axis, to a line through two points.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* double AxAngle( AstFrame *this, const double a[], const double b[], int axis, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astAxAngle
+* method inherited from the Frame class).
+
+* Description:
+* This function finds the angle, as seen from point A, between the positive
+* direction of a specified axis, and the geodesic curve joining point
+* A to point B.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* a
+* An array of double, with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the first point.
+* b
+* An array of double, with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the second point.
+* axis
+* The number of the Frame axis from which the angle is to be
+* measured (one-based).
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The angle in radians, from the positive direction of the
+* specified axis, to the line AB. If the Frame is 2-dimensional,
+* it will be in the range $\pm \pi$, and positive rotation is in
+* the same sense as rotation from the positive direction of axis 2
+* to the positive direction of axis 1. If the Frame has more than 2
+* axes, a positive value will always be returned in the range zero
+* to $\pi$.
+
+* Notes:
+* - The geodesic curve used by this function is the path of
+* shortest distance between two points, as defined by the
+* astDistance function.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value, or if the require
+* position angle is undefined.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double result; /* Value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis - 1, 1, "astAxAngle" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astAxAngle method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astAxAngle( fr, a, b, axis );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = AST__BAD;
+
+/* Return the result. */
+ return result;
+}
+
+static double AxDistance( AstFrame *this_frame, int axis, double v1, double v2, int *status ) {
+/*
+* Name:
+* AxDistance
+
+* Purpose:
+* Find the distance between two axis values.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* double AxDistance( AstFrame *this, int axis, double v1, double v2, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astAxDistance
+* method inherited from the Frame class).
+
+* Description:
+* This function returns a signed value representing the axis increment
+* from axis value v1 to axis value v2.
+*
+* For a simple Frame, this is a trivial operation returning the
+* difference between the two axis values. But for other derived classes
+* of Frame (such as a SkyFrame) this is not the case.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The index of the axis to which the supplied values refer. The
+* first axis has index 1.
+* v1
+* The first axis value.
+* v2
+* The second axis value.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The distance between the two axis values.
+
+* Notes:
+* - This function will return a "bad" result value (AST__BAD) if
+* any of the input vaues has this value.
+* - A "bad" value will also be returned if this function is
+* invoked with the AST error status set, or if it should fail for
+* any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double result; /* Value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis - 1, 1, "astAxDistance" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astAxDistance method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astAxDistance( fr, axis, v1, v2 );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = AST__BAD;
+
+/* Return the result. */
+ return result;
+}
+
+static void AxNorm( AstFrame *this_frame, int axis, int oper, int nval,
+ double *values, int *status ){
+/*
+* Name:
+* AxNorm
+
+* Purpose:
+* Normalise an array of axis values.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void AxNorm( AstFrame *this, int axis, int oper, int nval,
+* double *values, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astAxNorm
+* method inherited from the Frame class).
+
+* Description:
+* This function modifies a supplied array of axis values so that
+* they are normalised in the manner indicated by parameter "oper".
+*
+* No normalisation is possible for a simple Frame and so the supplied
+* values are returned unchanged. However, this may not be the case for
+* specialised sub-classes of Frame. For instance, a SkyFrame has a
+* discontinuity at zero longitude and so a longitude value can be
+* expressed in the range [-Pi,+PI] or the range [0,2*PI].
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The index of the axis to which the supplied values refer. The
+* first axis has index 1.
+* oper
+* Indicates the type of normalisation to be applied. If zero is
+* supplied, the normalisation will be the same as that performed by
+* function astNorm. If 1 is supplied, the normalisation will be
+* chosen automatically so that the resulting list has the smallest
+* range.
+* nval
+* The number of points in the values array.
+* values
+* On entry, the axis values to be normalised. Modified on exit to
+* hold the normalised values.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis - 1, 1, "astAxNorm" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astAxNorm method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astAxNorm( fr, axis, oper, nval, values );
+ fr = astAnnul( fr );
+}
+
+static double AxOffset( AstFrame *this_frame, int axis, double v1, double dist, int *status ) {
+/*
+* Name:
+* AxOffset
+
+* Purpose:
+* Add an increment onto a supplied axis value.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* double AxOffset( AstFrame *this, int axis, double v1, double dist, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astAxOffset
+* method inherited from the Frame class).
+
+* Description:
+* This function returns an axis value formed by adding a signed axis
+* increment onto a supplied axis value.
+*
+* For a simple Frame, this is a trivial operation returning the
+* sum of the two supplied values. But for other derived classes
+* of Frame (such as a SkyFrame) this is not the case.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The index of the axis to which the supplied values refer. The
+* first axis has index 1.
+* v1
+* The original axis value.
+* dist
+* The axis increment to add to the original axis value.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The incremented axis value.
+
+* Notes:
+* - This function will return a "bad" result value (AST__BAD) if
+* any of the input vaues has this value.
+* - A "bad" value will also be returned if this function is
+* invoked with the AST error status set, or if it should fail for
+* any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double result; /* Value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis - 1, 1, "astAxOffset" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astAxOffset method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astAxOffset( fr, axis, v1, dist );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = AST__BAD;
+
+/* Return the result. */
+ return result;
+}
+
+static 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 "frameset.h"
+* AstObject *Cast( AstObject *this, AstObject *obj, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astCast
+* method inherited from the Frame class).
+
+* Description:
+* This function returns a deep copy of an ancestral component of the
+* supplied object. The required class of the ancestral component is
+* specified by another object. Specifically, if "this" and "new" are
+* of the same class, a copy of "this" is returned. If "this" is an
+* instance of a subclass of "obj", then a copy of the component
+* of "this" that matches the class of "obj" is returned. Otherwise,
+* a NULL pointer is returned without error.
+
+* Parameters:
+* this
+* Pointer to the Object to be cast.
+* obj
+* Pointer to an Object that defines the class of the returned Object.
+* The returned Object will be of the same class as "obj".
+
+* Returned Value:
+* A pointer to the new Object. NULL if "this" is not a sub-class of
+* "obj", or if an error occurs.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables; */
+ AstFrame *cfrm;
+ AstObject *new;
+ astDECLARE_GLOBALS
+ int generation_gap;
+
+/* Initialise */
+ new = NULL;
+
+/* Check inherited status */
+ if( !astOK ) return new;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* See how many steps up the class inheritance ladder it is from "obj"
+ to this class (FrameSet). A positive value is returned if FrameSet
+ is a sub-class of "obj". A negative value is returned if "obj" is
+ a sub-class of FrameSet. Zero is returned if "obj" is a FrameSet.
+ AST__COUSIN is returned if "obj" is not on the same line of descent
+ as FrameSet. */
+ generation_gap = astClassCompare( (AstObjectVtab *) &class_vtab,
+ astVTAB( obj ) );
+
+/* If "obj" is a FrameSet or a sub-class of FrameSet, 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 FrameSet or a sub-class of FrameSet (e.g. a Frame or
+ some sub-class of Frame), we attempt to cast the current Frame into
+ the class indicated by "obj". */
+ } else {
+ cfrm = astGetFrame( (AstFrameSet *) this_object, AST__CURRENT );
+ new = astCast( cfrm, obj );
+ 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 Frame axis values.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* double Centre( AstFrame *this_frame, int axis, double value,
+* double gap, int *status )
+
+* Class Membership:
+* FrameSet 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: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double result; /* Value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0.0;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astCentre" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astCentre method to obtain the required value. Annul the
+ Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astCentre( fr, axis, value, gap );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = 0.0;
+
+/* Return the result. */
+ return result;
+}
+
+static void CheckPerm( AstFrame *this_frame, const int *perm, const char *method, int *status ) {
+/*
+* Name:
+* CheckPerm
+
+* Purpose:
+* Check that an array contains a valid permutation.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void CheckPerm( AstFrame *this, const int *perm, const char *method, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astCheckPerm
+* method inherited from the Frame class).
+
+* Description:
+* This function checks the validity of a permutation array that
+* will be used to permute the order of a Frame's axes. If the
+* permutation specified by the array is not valid, an error is
+* reported and the global error status is set. Otherwise, the
+* function returns without further action.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* perm
+* Pointer to an array of integers with the same number of
+* elements as there are axes in the Frame. For each axis, the
+* corresponding integer gives the (zero based) axis index to be
+* used to identify the information for that axis (using the
+* un-permuted axis numbering). To be valid, the integers in
+* this array should therefore all lie in the range zero to
+* (naxes-1) inclusive, where "naxes" is the number of Frame
+* axes, and each value should occur exactly once.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate a permutation array. This method name is used
+* solely for constructing error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - Error messages issued by this function refer to the external
+* (public) numbering system used for axes (which is one-based),
+* whereas zero-based axis indices are used internally.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astCheckPerm method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astCheckPerm( fr, perm, method );
+ fr = astAnnul( fr );
+
+}
+
+static void Clear( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* Clear
+
+* Purpose:
+* Clear attribute values for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void Clear( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the public astClear method
+* inherited from the Object class).
+
+* Description:
+* This function clears the values of a specified set of attributes
+* for a FrameSet. Clearing an attribute cancels any value that has
+* previously been explicitly set for it, so that the standard
+* default attribute value will subsequently be used instead. This
+* also causes the astTest function to return the value zero for
+* the attribute, indicating that no value has been set.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* attrib
+* Pointer to a null-terminated character string containing a
+* comma-separated list of the names of the attributes to be
+* cleared.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - This function preserves the integrity of the FrameSet (if
+* possible) by appropriately remapping its current Frame to take
+* account of its changed attribute values.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstFrame *save_frame; /* Saved pointer to integrity Frame */
+ AstFrameSet *this; /* Pointer to FrameSet structure */
+ const char *save_method; /* Saved pointer to method name */
+ int ok; /* Status OK? */
+ int save_lost; /* Saved integrity modified flag */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_object);
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* To allow this function to be invoked recursively, we first save any
+ existing FrameSet integrity information in local variables. */
+ save_frame = integrity_frame;
+ save_lost= integrity_lost;
+ save_method = integrity_method;
+
+/* Set the name of the method being used (for use in error
+ messages). */
+ integrity_method = "astClear";
+
+/* Record the initial integrity state of the FrameSet. */
+ RecordIntegrity( this, status );
+
+/* Invoke the parent astClear method to clear the FrameSet's attribute
+ values and note if this succeeds. */
+ (*parent_clear)( this_object, attrib, status );
+ ok = astOK;
+
+/* Restore the FrameSet's integrity. */
+ RestoreIntegrity( this, status );
+
+/* If integrity could not be restored, then add contextual error
+ information. */
+ if ( !astOK && ok ) {
+ astError( astStatus, "Unable to accommodate clearing the \"%s\" "
+ "attribute(s).", status, attrib );
+ }
+
+/* Restore any saved FrameSet integrity information. */
+ integrity_frame = save_frame;
+ integrity_lost = save_lost;
+ integrity_method = save_method;
+}
+
+static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* ClearAttrib
+
+* Purpose:
+* Clear an attribute value for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void ClearAttrib( AstObject *this, const char *attrib )
+
+* Class Membership:
+* FrameSet 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
+* FrameSet, so that the default value will subsequently be used.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* attrib
+* Pointer to a null terminated string specifying the attribute
+* name. This should be in lower case with no surrounding white
+* space.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_object);
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* Check the attribute name and clear the appropriate attribute. */
+
+/* We first handle attributes that apply to the FrameSet as a whole
+ (rather than to the current Frame). */
+
+/* Base. */
+/* ----- */
+ if ( !strcmp( attrib, "base" ) ) {
+ astClearBase( this );
+
+/* Current. */
+/* -------- */
+/* Since this determines the choice of current Frame, we must restore
+ the integrity state of the FrameSet before changing this attribute
+ and record the new integrity state afterwards. */
+ } else if ( !strcmp( attrib, "current" ) ) {
+ RestoreIntegrity( this, status );
+ astClearCurrent( this );
+ RecordIntegrity( this, status );
+
+/* ID. */
+/* --- */
+ } else if ( !strcmp( attrib, "id" ) ) {
+ astClearID( this );
+
+/* Ident. */
+/* ------ */
+ } else if ( !strcmp( attrib, "ident" ) ) {
+ astClearIdent( this );
+
+/* Invert. */
+/* ------- */
+/* Since this affects the choice of current Frame, we must restore the
+ integrity state of the FrameSet before changing this attribute and
+ record the new integrity state afterwards. */
+ } else if ( !strcmp( attrib, "invert" ) ) {
+ RestoreIntegrity( this, status );
+ astClearInvert( this );
+ RecordIntegrity( this, status );
+
+/* Report. */
+/* ------- */
+ } else if ( !strcmp( attrib, "report" ) ) {
+ astClearReport( this );
+
+/* Variant. */
+/* -------- */
+ } else if ( !strcmp( attrib, "variant" ) ) {
+ astClearVariant( this );
+
+/* If the name was not recognised, test if it matches any of the
+ read-only attributes of this class. If it does, then report an
+ error. */
+ } else if ( !strcmp( attrib, "allvariants" ) ||
+ !strcmp( attrib, "class" ) ||
+ !strcmp( attrib, "nframe" ) ||
+ !strcmp( attrib, "nin" ) ||
+ !strcmp( attrib, "nobject" ) ||
+ !strcmp( attrib, "nout" ) ||
+ !strcmp( attrib, "refcount" ) ||
+ !strcmp( attrib, "tranforward" ) ||
+ !strcmp( attrib, "traninverse" ) ) {
+ astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" "
+ "value for a %s.", status, attrib, astGetClass( this ) );
+ astError( AST__NOWRT, "This is a read-only attribute." , status);
+
+/* Pass unrecognised attributes on to the FrameSet's current Frame for
+ further interpretation. */
+ } else {
+
+/* Force a copy to be made of the current Frame, if needed, to make it
+ independent of other Frames within the FrameSet. */
+ (void) ForceCopy( this, AST__CURRENT, status );
+
+/* Obtain a pointer to the current Frame and invoke its astClearAttrib
+ method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astClearAttrib( fr, attrib );
+ fr = astAnnul( fr );
+
+/* Note that the current Frame has been modified. */
+ integrity_lost = 1;
+ }
+}
+
+static void ClearBase( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astClearBase
+
+* Purpose:
+* Clear the value of the Base attribute of a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* void astClearBase( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function clears the value of the Base attribute of a
+* FrameSet. This value is an index that identifies the base Frame
+* for the FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+*-
+*/
+
+/* Local Variables: */
+ int invert; /* FrameSet is inverted? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Determine if the FrameSet has been inverted. */
+ invert = astGetInvert( this );
+
+/* If it has not been inverted, clear the base Frame index, otherwise
+ clear the current Frame index instead. */
+ if ( astOK ) *( invert ? &this->current : &this->base ) = -INT_MAX;
+}
+
+static void ClearCurrent( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astClearCurrent
+
+* Purpose:
+* Clear the value of the Current attribute for a FrameSet.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astClearCurrent( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function clears the value of the Current attribute for a
+* FrameSet. This attribute is an index that identifies the current
+* Frame for the FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+*-
+*/
+
+/* Local Variables: */
+ int invert; /* FrameSet is inverted? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Determine if the FrameSet has been inverted. */
+ invert = astGetInvert( this );
+
+/* If it has not been inverted, clear the current frame index,
+ otherwise clear the base Frame index instead. */
+ if ( astOK ) *( invert ? &this->base : &this->current ) = -INT_MAX;
+}
+
+static void ClearVariant( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astClearVariant
+
+* Purpose:
+* Clear the value of the Variant attribute of a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* void astClearVariant( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function clears the value of the Variant attribute of a
+* FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+*-
+*/
+
+/* Local Variables: */
+ AstFrame *frm;
+ int icur;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get the one-based index of the Frame to use. */
+ icur = GetVarFrm( this, astGetCurrent( this ), status );
+
+/* Get a pointer to the current Frame in the FrameSet. */
+ frm = astGetFrame( this, icur );
+
+/* Replace any Variants FrameSet in the Frame with a NULL pointer. */
+ astSetFrameVariants( frm, NULL );
+
+/* Annul the current Frame pointer. */
+ frm = astAnnul( frm );
+
+}
+
+static AstMapping *CombineMaps( AstMapping *mapping1, int invert1,
+ AstMapping *mapping2, int invert2,
+ int series, int *status ) {
+/*
+* Name:
+* CombineMaps
+
+* Purpose:
+* Combine two Mappings with specified Invert flags into a CmpMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstMapping *CombineMaps( AstMapping *mapping1, int invert1,
+* AstMapping *mapping2, int invert2,
+* int series )
+
+* Class Membership:
+* FrameSet member function.
+
+* Description:
+* This function combines two Mappings into a CmpMap (compound
+* Mapping) as if their Invert flags were set to specified values
+* when the CmpMap is created. However, the individual Mappings are
+* returned with their Invert flag values unchanged from their
+* original state.
+
+* Parameters:
+* mapping1
+* Pointer to the first Mapping.
+* invert1
+* The (boolean) Invert flag value required for the first Mapping.
+* mapping2
+* Pointer to the second Mapping.
+* invert2
+* The (boolean) Invert flag value required for the second Mapping.
+* series
+* Whether the Mappings are to be combined in series (as opposed to
+* in parallel).
+
+* Returned Value:
+* A pointer to the resulting compound Mapping (a CmpMap).
+
+* Notes:
+* - This function is a wrap-up for the astCmpMap constructor and
+* temporarily assigns the required Invert flag values while
+* creating the required CmpMap. However, it also takes account of
+* the possibility that the two Mapping pointers supplied may point
+* at the same Mapping.
+* - A null Object pointer (AST__NULL) will be returned if this
+* function is invoked with the AST error status set, or if it
+* should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstMapping *map1; /* First temporary Mapping pointer */
+ AstMapping *map2; /* Second temporary Mapping pointer */
+ AstMapping *result; /* Pointer to result Mapping */
+ int copy; /* Copy needed? */
+ int inv1; /* First original Invert flag value */
+ int inv2; /* Second original Invert flag value */
+ int set1; /* First Invert flag originally set? */
+ int set2; /* Second Invert flag originally set? */
+
+/* Initialise */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Limit incoming values to 0 or 1. */
+ invert1 = ( invert1 != 0 );
+ invert2 = ( invert2 != 0 );
+
+/* Obtain the Invert flag values for each Mapping. */
+ inv1 = astGetInvert( mapping1 );
+ inv2 = astGetInvert( mapping2 );
+
+/* Also determine if these values are explicitly set. */
+ set1 = astTestInvert( mapping1 );
+ set2 = astTestInvert( mapping2 );
+
+/* If both Mappings are actually the same but we need different Invert
+ flag values to be set, then this can only be achieved by making a
+ copy. Note if this is necessary. */
+ copy = ( ( mapping1 == mapping2 ) && ( invert1 != invert2 ) );
+
+/* Clone the first Mapping pointer. Do likewise for the second but
+ make a copy instead if necessary. */
+ map1 = astClone( mapping1 );
+ map2 = copy ? astCopy( mapping2 ) : astClone( mapping2 );
+
+/* If the Invert value for the first Mapping needs changing, make the
+ change. */
+ if ( invert1 != inv1 ) {
+ if ( invert1 ) {
+ astSetInvert( map1, 1 );
+ } else {
+ astClearInvert( map1 );
+ }
+ }
+
+/* Similarly, change the Invert flag for the second Mapping if
+ necessary. */
+ if ( invert2 != inv2 ) {
+ if ( invert2 ) {
+ astSetInvert( map2, 1 );
+ } else {
+ astClearInvert( map2 );
+ }
+ }
+
+/* Combine the two Mappings into a CmpMap. */
+ result = (AstMapping *) astCmpMap( map1, map2, series, "", status );
+
+/* If the first Mapping's Invert value was changed, restore it to its
+ original state. */
+ if ( invert1 != inv1 ) {
+ if ( set1 ) {
+ astSetInvert( map1, inv1 );
+ } else {
+ astClearInvert( map1 );
+ }
+ }
+
+/* Similarly, restore the second Mapping's Invert value if
+ necessary. This step is not needed, however, if a copy was made. */
+ if ( ( invert2 != inv2 ) && !copy ) {
+ if ( set2 ) {
+ astSetInvert( map2, inv2 );
+ } else {
+ astClearInvert( map2 );
+ }
+ }
+
+/* Annul the temporary Mapping pointers. */
+ map1 = astAnnul( map1 );
+ map2 = astAnnul( map2 );
+
+/* If an error occurred, then annul the result pointer. */
+ if ( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static AstFrameSet *Convert( AstFrame *from, AstFrame *to,
+ const char *domainlist, int *status ) {
+/*
+* Name:
+* Convert
+
+* Purpose:
+* Determine how to convert between two coordinate systems.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstFrameSet *Convert( AstFrame *from, AstFrame *to,
+* const char *domainlist, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the public astConvert
+* method inherited fromm the Frame class).
+
+* Description:
+* This function compares two FrameSets and determines whether it
+* is possible to convert between the coordinate systems which
+* their current Frames represent. If conversion is possible, it
+* returns a FrameSet which describes the conversion and which may
+* be used (as a Mapping) to transform coordinate values in either
+* direction.
+*
+* If conversion is possible, the Base attributes of both FrameSets
+* will be modified on exit to identify the Frames which were used
+* as the intermediate coordinate system.
+
+* Parameters:
+* from
+* Pointer to a FrameSet whose current Frame represents the
+* "source" coordinate system. Note that the Base attribute of
+* the FrameSet may be modified by this function.
+* to
+* Pointer to a FrameSet whose current Frame represents the
+* "destination" coordinate system. Note that the Base
+* attribute of the FrameSet may be modified by this function.
+* domainlist
+* Pointer to a null-terminated character string containing a
+* comma-separated list of Frame domains. This may be used to
+* define a priority order for the different intermediate
+* coordinate systems that might be used to perform the
+* conversion.
+*
+* The function will first try to obtain a conversion by making
+* use only of intermediate Frames whose Domain attribute
+* matches the first domain in this list. If this fails, the
+* second domain in the list will be used, and so on, until
+* conversion is achieved. A blank domain (e.g. two consecutive
+* commas) indicates that all Frames should be considered,
+* regardless of their Domain attributes. The list is
+* case-insensitive and all white space is ignored.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* If the requested coordinate conversion is possible, the
+* function returns a pointer to a FrameSet which describes the
+* conversion. Otherwise, a null Object pointer (AST__NULL) is
+* returned without error.
+*
+* If a FrameSet is returned, it will contain two Frames. Frame
+* number 1 (its base Frame) will describe the source coordinate
+* system, corresponding to the "from" parameter. Frame number 2
+* (its current Frame) will describe the destination coordinate
+* system, corresponding to the "to" parameter. The Mapping
+* which inter-relates these Frames will perform the required
+* conversion between the two coordinate systems.
+
+* Notes:
+* - Either of the "from" and "to" pointers may identify a basic
+* Frame instead of a FrameSet, in which case the function behaves
+* as if it were a FrameSet containing only a single Frame.
+* - 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 is simply a wrap-up for the ConvertX function
+* which performs the required processing but swaps the order of the
+* first two arguments. This is a trick to allow the astConvert
+* method to be over-ridden by derived classes on the basis of the
+* class of either of the first two arguments.
+*/
+
+/* Check the inherited status. */
+ if ( !astOK ) return NULL;
+
+/* Invoke the private "ConvertX" member function with the first two
+ arguments swapped. */
+ return ConvertX( to, from, domainlist, status );
+}
+
+static AstFrameSet *ConvertX( AstFrame *to, AstFrame *from,
+ const char *domainlist, int *status ) {
+/*
+* Name:
+* ConvertX
+
+* Purpose:
+* Determine how to convert between two coordinate systems.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstFrameSet *ConvertX( AstFrame *to, AstFrame *from,
+* const char *domainlist )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected "astConvertX"
+* method inherited from the Frame class).
+
+* Description:
+* This function performs the processing for the public astConvert
+* method (as inherited from the Frame class and over-ridden by the
+* FrameSet class) and has exactly the same interface except that
+* the order of the first two arguments is swapped. This is a trick
+* to allow the astConvert method to be over-ridden by derived
+* classes on the basis of the class of either of its first two
+* arguments.
+*
+* See the astConvert method for details of the interface.
+*/
+
+/* Local Variables: */
+ AstFrame *from_frame; /* Pointer to "from" Frame */
+ AstFrame *to_frame; /* Pointer to "to" Frame */
+ AstFrameSet *cvt; /* Pointer to conversion FrameSet */
+ AstFrameSet *result; /* Pointer to FrameSet to be returned */
+ AstMapping *from_map; /* Pointer to "from" Mapping */
+ AstMapping *map; /* Pointer to conversion Mapping */
+ AstMapping *result_map; /* Pointer to result Mapping */
+ AstMapping *tmp; /* Temporary Mapping pointer */
+ AstMapping *to_map; /* Pointer to "to" Mapping */
+ char *domain; /* Pointer to individual domain string */
+ char *domain_end; /* Pointer to final null of domain string */
+ char *domainlist_copy; /* Pointer to copy of domains list */
+ int *from_order; /* List of Frame indices in search order */
+ int *to_order; /* List of Frame indices in search order */
+ int best_score; /* Score from best match */
+ int from_base; /* Index of "from" base Frame */
+ int from_current; /* Index of "from" current Frame */
+ int from_index; /* Index of "from" Frame */
+ int from_isframe; /* "from" is a Frame (not a FrameSet)? */
+ int from_nframe; /* Number of "from" Frames */
+ int from_number; /* Loop counter for "from" Frames */
+ int iframe_from; /* Index of best "from" Frame */
+ int iframe_to; /* Index of best "to" Frame */
+ int match; /* Possible match found? */
+ int n; /* Count of Frames */
+ int perfect; /* Perfect match found? */
+ int score; /* Score from latest match */
+ int to_base; /* Index of "to" base Frame */
+ int to_current; /* Index of "to" current Frame */
+ int to_index; /* Index of "to" Frame */
+ int to_isframe; /* "to" is a Frame (not a FrameSet)? */
+ int to_nframe; /* Number of "to" Frames */
+ int to_number; /* Loop counter for "to" Frames */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Initialise variables to avoid "used of uninitialised variable"
+ messages from dumb compilers. */
+ result_map = NULL;
+ iframe_from = 0;
+ iframe_to = 0;
+
+/* Determine the number of Frames in "from" and the indices of its
+ base and current Frames. Use values of 1 if "from" is a Frame and
+ not a FrameSet. */
+ from_isframe = !astIsAFrameSet( from );
+ from_nframe = from_isframe ? 1 : astGetNframe( from );
+ from_base = from_isframe ? 1 : astGetBase( from );
+ from_current = from_isframe ? 1 : astGetCurrent( from );
+
+/* Obtain similar values for "to". */
+ to_isframe = !astIsAFrameSet( to );
+ to_nframe = to_isframe ? 1 : astGetNframe( to );
+ to_base = to_isframe ? 1 : astGetBase( to );
+ to_current = to_isframe ? 1 : astGetCurrent( to );
+
+/* Allocate memory for arrays which will hold the indices of "from"
+ and "to" Frames. */
+ from_order = astMalloc( sizeof( int ) * (size_t) from_nframe );
+ to_order = astMalloc( sizeof( int ) * (size_t) to_nframe );
+
+/* Make a temporary copy of the domains list. */
+ domainlist_copy = astStore( NULL, domainlist,
+ strlen( domainlist ) + (size_t) 1 );
+ if ( astOK ) {
+
+/* Fill the "from_order" array with the indices of all the Frames in
+ "from", in the order in which they will be used for searching. Use
+ the base Frame first. */
+ n = 0;
+ from_order[ n++ ] = from_base;
+
+/* Then add all the "from" Frames in the appropriate order, omitting
+ the base and current Frames. */
+ if ( !astGetInvert( from ) ) {
+ for ( from_index = 1; from_index <= from_nframe; from_index++ ) {
+ if ( ( from_index != from_base ) &&
+ ( from_index != from_current ) ) {
+ from_order[ n++ ] = from_index;
+ }
+ }
+ } else {
+ for ( from_index = from_nframe; from_index >= 1; from_index-- ) {
+ if ( ( from_index != from_base ) &&
+ ( from_index != from_current ) ) {
+ from_order[ n++ ] = from_index;
+ }
+ }
+ }
+
+/* Finish with the current Frame, if different from the base Frame. */
+ if ( from_current != from_base ) from_order[ n++ ] = from_current;
+
+/* Repeat this process for the "to" Frame. */
+ n = 0;
+ to_order[ n++ ] = to_base;
+ if ( !astGetInvert( to ) ) {
+ for ( to_index = 1; to_index <= to_nframe; to_index++ ) {
+ if ( ( to_index != to_base ) && ( to_index != to_current ) ) {
+ to_order[ n++ ] = to_index;
+ }
+ }
+ } else {
+ for ( to_index = to_nframe; to_index >= 1; to_index-- ) {
+ if ( ( to_index != to_base ) && ( to_index != to_current ) ) {
+ to_order[ n++ ] = to_index;
+ }
+ }
+ }
+ if ( to_current != to_base ) to_order[ n++ ] = to_current;
+
+/* Loop to inspect each comma-separated field in the domains list
+ until an error occurs, all the domains are used up, or a match is
+ found. */
+ domain = domainlist_copy;
+ match = 0;
+ while ( astOK && domain && !match ) {
+
+/* Change the comma at the end of each field to a null to terminate
+ the domain. */
+ if ( ( domain_end = strchr( domain, ',' ) ) ) *domain_end = '\0';
+
+/* For any given domain, we will ignore imperfect matches in favour of
+ better ones by assigning a score to each match. Initialise the best
+ score value for the current domain. */
+ best_score = -1;
+
+/* Loop through each Frame in "to". Quit looping early if an error
+ occurs or a perfect match is found. */
+ perfect = 0;
+ for ( to_number = 0;
+ astOK && !perfect && ( to_number < to_nframe );
+ to_number++ ) {
+
+/* Permute the "to" Frame number into a Frame index to implement the
+ required search order, and obtain a pointer to the required "to"
+ Frame. */
+ to_index = to_order[ to_number ];
+ to_frame = to_isframe ? astClone( to ) :
+ astGetFrame( to, to_index );
+
+/* Loop through each Frame in "from". Quit looping early if an error
+ occurs or a perfect match is found. */
+ for ( from_number = 0;
+ astOK && !perfect && ( from_number < from_nframe );
+ from_number++ ) {
+
+/* Permute the "from" Frame number into a Frame index to implement the
+ required search order, and obtain a pointer to the required "from"
+ Frame. */
+ from_index = from_order[ from_number ];
+ from_frame = from_isframe ? astClone( from ) :
+ astGetFrame( from, from_index );
+
+/* Attempt to obtain a FrameSet which describes the conversion between
+ the selected "from" and "to" Frames and test if successful. If so,
+ we have a potential route to construct the overall Mapping we
+ want. */
+ cvt = astConvert( from_frame, to_frame, domain );
+ if ( astOK && cvt ) {
+
+/* Extract the required Mapping from the returned FrameSet. */
+ map = astGetMapping( cvt, AST__BASE, AST__CURRENT );
+
+/* If necessary, prefix the Mapping between the "from" current Frame
+ and the individual "from" Frame we have selected. */
+ if ( from_index != from_current ) {
+ from_map = astGetMapping( from, AST__CURRENT,
+ from_index );
+ tmp = (AstMapping *) astCmpMap( from_map, map, 1, "", status );
+ from_map = astAnnul( from_map );
+ map = astAnnul( map );
+ map = tmp;
+ }
+
+/* Similarly, if necessary, append the Mapping between the selected
+ "to" Frame and the "to" current Frame. */
+ if ( to_index != to_current ) {
+ to_map = astGetMapping( to, to_index, AST__CURRENT );
+ tmp = (AstMapping *) astCmpMap( map, to_map, 1, "", status );
+ to_map = astAnnul( to_map );
+ map = astAnnul( map );
+ map = tmp;
+ }
+
+/* Simplify the resulting overall Mapping (this is done here because
+ it may sometimes affect the attribute values used to assign a score
+ below). */
+ tmp = astSimplify( map );
+ map = astAnnul( map );
+ map = tmp;
+
+/* Assign a score that favours Mappings with both transformations
+ available over those with only one, and Mappings with only a
+ forward transformation over those with only an inverse
+ transformation. */
+ score = ( astGetTranForward( map ) ? 2 : 0 ) +
+ ( astGetTranInverse( map ) ? 1 : 0 );
+
+/* If the new score is better than the previous one (or is the first
+ one), note that we have a possible match. */
+ if ( astOK && ( score > best_score ) ) {
+ match = 1;
+
+/* Update the best score and note if it indicates a perfect match (in
+ which case we can stop searching at this point). */
+ best_score = score;
+ perfect = ( best_score >= 3 );
+
+/* Annul any previous result Mapping pointer and replace it with this
+ better one. */
+ if ( result_map ) result_map = astAnnul( result_map );
+ result_map = astClone( map );
+
+/* Note which "from" and "to" Frames were used. */
+ iframe_from = from_index;
+ iframe_to = to_index;
+ }
+
+/* Annul pointers to the intermediate Objects. */
+ map = astAnnul( map );
+ cvt = astAnnul( cvt );
+ }
+ from_frame = astAnnul( from_frame );
+ }
+ to_frame = astAnnul( to_frame );
+ }
+
+/* Go on to consider the next field in the domains list. */
+ domain = domain_end ? domain_end + 1 : NULL;
+ }
+ }
+
+/* Free the memory allocated for temporary arrays. */
+ domainlist_copy = astFree( domainlist_copy );
+ from_order = astFree( from_order );
+ to_order = astFree( to_order );
+
+/* If a result is being returned, then obtain a pointer to the current
+ "from" Frame and use it to start constructing the result
+ FrameSet. */
+ if ( result_map ) {
+ from_frame = from_isframe ? astClone( from ) :
+ astGetFrame( from, AST__CURRENT );
+ result = astFrameSet( from_frame, "", status );
+ from_frame = astAnnul( from_frame );
+
+/* Similarly. obtain a pointer to the current "to" frame and add it to
+ the result FrameSet (related to the base Frame by the result
+ Mapping). */
+ to_frame = to_isframe ? astClone( to ) :
+ astGetFrame( to, AST__CURRENT );
+ astAddFrame( result, AST__BASE, result_map, to_frame );
+ to_frame = astAnnul( to_frame );
+
+/* Annul the result Mapping pointer. */
+ result_map = astAnnul( result_map );
+ }
+
+/* If successful, and a FrameSet is being returned, then set the base
+ Frames of "from" and "to" (if they are FrameSets) to indicate the
+ route used to generate the result Mapping. */
+ if ( astOK && result ) {
+ if ( !from_isframe ) astSetBase( from, iframe_from );
+ if ( !to_isframe ) astSetBase( to, iframe_to );
+ }
+
+/* If an error occurred, annul the returned FrameSet pointer. */
+ if ( !astOK && result ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static double Distance( AstFrame *this_frame,
+ const double point1[], const double point2[], int *status ) {
+/*
+* Name:
+* Distance
+
+* Purpose:
+* Calculate the distance between two points.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* double Distance( AstFrame *this,
+* const double point1[], const double point2[], int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astDistance
+* method inherited from the Frame class).
+
+* Description:
+* This function finds the distance between two points whose
+* FrameSet coordinates are given. The distance calculated is that
+* along the geodesic curve that joins the two points.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* point1
+* An array of double, with one element for each FrameSet axis
+* containing the coordinates of the first point.
+* point2
+* An array of double, with one element for each FrameSet axis
+* containing the coordinates of the second point.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The distance between the two points.
+
+* Notes:
+* - This function will return a "bad" result value (AST__BAD) if
+* any of the input coordinates has this value.
+* - A "bad" value will also be returned if this function is
+* invoked with the AST error status set or if it should fail for
+* any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double result; /* Value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astDistance method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astDistance( fr, point1, point2 );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = AST__BAD;
+
+/* Return the result. */
+ return result;
+}
+
+static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
+/*
+* Name:
+* Equal
+
+* Purpose:
+* Test if two FrameSets are equivalent.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int Equal( AstObject *this, AstObject *that, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astEqual protected
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns a boolean result (0 or 1) to indicate whether
+* two FrameSets are equivalent.
+
+* Parameters:
+* this
+* Pointer to the first FrameSet.
+* that
+* Pointer to the second FrameSet.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* One if the FrameSets are equivalent, zero otherwise.
+
+* Notes:
+* - The two FrameSets are considered equivalent if all the encapsulated
+* Frames are equal and all the encapsulated Mappings are equal.
+* - 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: */
+ AstFrameSet *that; /* Pointer to the second FrameSet structure */
+ AstFrameSet *this; /* Pointer to the first FrameSet structure */
+ int i; /* Loop index */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Checks that the second object is of the same class as the first . */
+ if( !strcmp( astGetClass( this_object ), astGetClass( that_object ) ) ){
+
+/* Obtain pointers to the two FrameSet structures. */
+ this = (AstFrameSet *) this_object;
+ that = (AstFrameSet *) that_object;
+
+/* Check the number of nodes and frames are equal. Also check the indices
+ of the base and current Frames are equal */
+ if( this->nframe == that->nframe &&
+ this->nnode == that->nnode &&
+ this->base == that->base &&
+ this->current == that->current ) {
+
+/* Check the Frames and nodes are equal. */
+ result = 1;
+ for ( i = 0; i < this->nframe; i++ ) {
+ if( !astEqual( this->frame[ i ], that->frame[ i ] ) ||
+ this->node[ i ] != that->node[ i ] ){
+ result = 0;
+ break;
+ }
+ }
+
+/* Check the Mappings, links and invert flags are equal. */
+ if( result ) {
+ for ( i = 0; i < this->nnode - 1; i++ ) {
+ if( !astEqual( this->map[ i ], that->map[ i ] ) ||
+ this->link[ i ] != that->link[ i ] ||
+ this->invert[ i ] != that->invert[ i ] ) {
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* 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 FrameSet axis value.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astFields( AstFrame *this, int axis, const char *fmt,
+* const char *str, int maxfld, char **fields,
+* int *nc, double *val )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astFields
+* method inherited from the Frame class).
+
+* Description:
+* This function identifies the numerical fields within a FrameSet 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 FrameSet.
+* axis
+* The number of the FrameSet 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: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int result; /* Result field count to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astFields" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astFields method to perform the processing. Annul the Frame
+ pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astFields( fr, axis, fmt, str, maxfld, fields, nc, val );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static AstFrameSet *FindFrame( AstFrame *target_frame, AstFrame *template,
+ const char *domainlist, int *status ) {
+/*
+* Name:
+* FindFrame
+
+* Purpose:
+* Find a coordinate system with specified characteristics.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstFrameSet *FindFrame( AstFrame *target, AstFrame *template,
+* const char *domainlist, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astFindFrame method
+* inherited from the Frame class).
+
+* Description:
+* This function uses a "template" Frame to search a FrameSet to
+* identify a coordinate system which has a specified set of
+* characteristics. If a suitable coordinate system can be found,
+* the function returns a pointer to a FrameSet which describes the
+* required coordinate system and how to convert coordinates to and
+* from it.
+
+* Parameters:
+* target
+* Pointer to the target FrameSet. Note that if a suitable
+* coordinate system is found, then the FrameSet's Current
+* attribute will be modified to indicate which Frame was used
+* to obtain attribute values which were not specified by the
+* template.
+* template
+* Pointer to the template Frame, which should be an instance of
+* the type of Frame you wish to find.
+* domainlist
+* Pointer to a null-terminated character string containing a
+* comma-separated list of Frame domains. This may be used to
+* establish a priority order for the different types of
+* coordinate system that might be found.
+*
+* The function will first try to find a suitable coordinate
+* system whose Domain attribute equals the first domain in this
+* list. If this fails, the second domain in the list will be
+* used, and so on, until a result is obtained. A blank domain
+* (e.g. two consecutive commas) indicates that any coordinate
+* system is acceptable (subject to the template) regardless of
+* its domain.
+*
+* This list is case-insensitive and all white space is ignored.
+* If you do not wish to restrict the domain in this way, you
+* should supply an empty string.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* If the search is successful, the function returns a pointer to a
+* FrameSet which contains the Frame found and a description of how
+* to convert to (and from) the coordinate system it
+* represents. Otherwise, a null Object pointer (AST__NULL) is
+* returned without error.
+*
+* If a FrameSet is returned, it will contain two Frames. Frame
+* number 1 (its base Frame) represents the target coordinate
+* system and will be the same as the (base Frame of the)
+* target. Frame number 2 (its current Frame) will be a Frame
+* representing the coordinate system which the function found. The
+* Mapping which inter-relates these two Frames will describe how
+* to convert between their respective coordinate systems.
+
+* Notes:
+* - A null Object pointer (AST__NULL) will be returned if this
+* function is invoked with the AST error status set, or if it
+* should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *base_frame; /* Pointer to target base Frame */
+ AstFrame *frame; /* Pointer to result Frame */
+ AstFrame *selected_frame; /* Pointer to selected target Frame */
+ AstFrameSet *found; /* FrameSet pointer (result of search) */
+ AstFrameSet *result; /* Pointer to result FrameSet */
+ AstFrameSet *target; /* Pointer to target FrameSet structure */
+ AstMapping *map; /* Pointer to result Mapping */
+ AstMapping *prefix; /* Pointer to prefix Mapping */
+ AstMapping *tmp; /* Temporary Mapping pointer */
+ char *domain; /* Pointer to individual domain field */
+ char *domain_end; /* Pointer to null at end of domain */
+ char *domainlist_copy; /* Pointer to copy of domains list */
+ int *target_order; /* Array of indices defining search order */
+ int match; /* Match obtained? */
+ int n; /* Count of target_order elements */
+ int target_base; /* Index of target base Frame */
+ int target_current; /* Index of target current Frame */
+ int target_index; /* Index of selected target Frame */
+ int target_nframe; /* Number of Frames in target FrameSet */
+ int target_number; /* Loop index for search */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Initialise variables to avoid "used of uninitialised variable"
+ messages from dumb compilers. */
+ target_index = 0;
+
+/* Obtain a pointer to the target FrameSet structure. */
+ target = (AstFrameSet *) target_frame;
+
+/* Determine the number of Frames in the target FrameSet and the
+ indices of the current and base Frames. */
+ target_nframe = astGetNframe( target );
+ target_current = astGetCurrent( target );
+ target_base = astGetBase( target );
+
+/* Allocate an array to hold a list of all the target Frame indices. */
+ target_order = astMalloc( sizeof( int ) * (size_t) target_nframe );
+
+/* Make a temporary copy of the domains list. */
+ domainlist_copy = astStore( NULL, domainlist,
+ strlen( domainlist ) + (size_t) 1 );
+ if ( astOK ) {
+
+/* Form a list of the indices of all the Frames in the target in the
+ order they will be searched for a match. Add the current Frame
+ index first. */
+ n = 0;
+ target_order[ n++ ] = target_current;
+
+/* Follow this by the base Frame index, if different. */
+ if ( target_base != target_current ) target_order[ n++ ] = target_base;
+
+/* Then add all the remaining target Frame indices. */
+ for ( target_index = 1; target_index <= target_nframe; target_index++ ) {
+ if ( ( target_index != target_current ) &&
+ ( target_index != target_base ) ) {
+ target_order[ n++ ] = target_index;
+ }
+ }
+
+/* Loop to inspect each comma-separated field in the domains list
+ until an error occurs, all the domains are used up, or a match is
+ found. */
+ domain = domainlist_copy;
+ match = 0;
+ while ( astOK && domain && !match ) {
+
+/* Change the comma at the end of each field to a null to terminate
+ the domain. */
+ if ( ( domain_end = strchr( domain, ',' ) ) ) *domain_end = '\0';
+
+/* Loop to try and match each target Frame in turn, in the order
+ identified above. Quit the loop early if an error occurs or a match
+ is found. */
+ for ( target_number = 0;
+ astOK && !match && ( target_number < target_nframe );
+ target_number++ ) {
+
+/* Permute the target Frame number into a Frame index to implement the
+ required search order. Then obtain a pointer to the selected target
+ Frame. */
+ target_index = target_order[ target_number ];
+ selected_frame = astGetFrame( target, target_index );
+
+/* Search the target Frame using the template supplied, together with
+ the current domain. */
+ found = astFindFrame( selected_frame, template, domain );
+
+/* Note if a match is found, and extract pointers to the conversion
+ Mapping and the result Frame from the FrameSet produced. */
+ if ( astOK && found ) {
+ match = 1;
+ map = astGetMapping( found, AST__BASE, AST__CURRENT );
+ frame = astGetFrame( found, AST__CURRENT );
+
+/* Obtain a pointer to the Mapping between the target base Frame and
+ the selected target Frame, and prefix this Mapping to the one
+ obtained above. */
+ prefix = astGetMapping( target, AST__BASE, target_index );
+ tmp = (AstMapping *) astCmpMap( prefix, map, 1, "", status );
+ prefix = astAnnul( prefix );
+ map = astAnnul( map );
+ map = tmp;
+
+/* Simplify the resulting Mapping. */
+ tmp = astSimplify( map );
+ map = astAnnul( map );
+ map = tmp;
+
+/* Obtain a pointer to the target base Frame, and use this to start
+ building the result FrameSet. */
+ base_frame = astGetFrame( target, AST__BASE );
+ result = astFrameSet( base_frame, "", status );
+ base_frame = astAnnul( base_frame );
+
+/* Add the result Frame, which is related to the base Frame by the
+ result Mapping. */
+ astAddFrame( result, AST__BASE, map, frame );
+
+/* Annul pointers to all intermediate Objects. */
+ map = astAnnul( map );
+ frame = astAnnul( frame );
+ found = astAnnul( found );
+ }
+ selected_frame = astAnnul( selected_frame );
+ }
+
+/* Go on to consider the next field in the domains list. */
+ domain = domain_end ? domain_end + 1 : NULL;
+ }
+ }
+
+/* Free the temporary arrays. */
+ target_order = astFree( target_order );
+ domainlist_copy = astFree( domainlist_copy );
+
+/* If a result is being returned, set the current Frame of the target
+ to indicate where the result Frame was found. */
+ if ( astOK && result ) astSetCurrent( target, target_index );
+
+/* If an error occurred, annul any result FrameSet pointer. */
+ if ( !astOK && result ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static AstPointSet *FrameGrid( AstFrame *this_frame, 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 "frameset.h"
+* AstPointSet *FrameGrid( AstFrame *this_frame, int size,
+* const double *lbnd, const double *ubnd,
+* int *status )
+
+* Class Membership:
+* FrameSet 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: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ AstPointSet *result; /* Value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astFrameGrid method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astFrameGrid( fr, size, lbnd, ubnd );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static int ForceCopy( AstFrameSet *this, int iframe, int *status ) {
+/*
+* Name:
+* ForceCopy
+
+* Purpose:
+* Force a copy to be made of a Frame, if necessary.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int ForceCopy( AstFrameSet *this, int iframe, int *status )
+
+* Class Membership:
+* FrameSet member function.
+
+* Description:
+* This function examines a Frame within a FrameSet, identified by its
+* Frame index. If the same Frame is found to be referenced a second time
+* within the FrameSet, then the original reference is replaced with an
+* independent copy of the Frame.
+*
+* This process supports the preservation of FrameSet integrity in cases
+* where the same Frame is referenced more than once. After using this
+* function, the nominated Frame's attributes may be modified without
+* danger of affecting other parts of the FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* iframe
+* The index of the Frame to be examined.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* One if a copy of the nominated Frame was made, otherwise zero.
+
+* Notes:
+* - Using this function a second time on the same Frame will have no
+* effect, since the first usage will make the Frame independent of any
+* other Frames within the FrameSet.
+* - 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: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstFrame *frame; /* Pointer to Frame */
+ AstFrame *tmp; /* Temporary Frame pointer */
+ int ifr; /* Loop counter for Frames */
+ int result; /* Value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* Validate and translate the Frame index supplied. */
+ iframe = astValidateFrameIndex( this, iframe, integrity_method );
+
+/* If OK, obtain the corresponding Frame pointer (don't clone it). */
+ if ( astOK ) {
+ frame = this->frame[ iframe - 1 ];
+
+/* Loop to inspect each Frame in the FrameSet. */
+ for ( ifr = 1; ifr <= this->nframe; ifr++ ) {
+
+/* If the same Frame is referenced anywhere else, then make a copy of it. */
+ if ( ( ifr != iframe ) && ( this->frame[ ifr - 1 ] == frame ) ) {
+ tmp = astCopy( frame );
+
+/* If successful, replace the original reference to the Frame with a pointer
+ to this copy and annul the original pointer. */
+ if ( astOK ) {
+ this->frame[ iframe - 1 ] = tmp;
+ frame = astAnnul( frame );
+
+/* Set the returned result. */
+ if ( astOK ) result = 1;
+ }
+
+/* Quit looping once a copy has been made. */
+ break;
+ }
+ }
+ }
+
+/* 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 FrameSet axis.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* const char *Format( AstFrame *this, int axis, double value, int *status )
+
+* Class Membership:
+* FrameSet 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
+* FrameSet axis. The formatting applied is that specified by a
+* previous invocation of the astSetFormat method. A suitable
+* default format is applied if necessary.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* axis
+* The number of the axis (zero-based) for which formatting is
+* to be performed.
+* value
+* The coordinate value to be formatted.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to a null-terminated string containing the formatted
+* value.
+
+* Notes:
+* - The returned string pointer may point at memory allocated
+* within the FrameSet object, or at static memory. The contents of
+* the string may be over-written or the pointer may become invalid
+* following a further invocation of the same function or deletion
+* of the FrameSet. A copy of the string should therefore be made
+* if necessary.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ const char *result; /* Pointer value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astFormat" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astFormat method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astFormat( fr, axis, value );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+static double Gap( AstFrame *this_frame, int axis, double gap, int *ntick, int *status ) {
+/*
+* Name:
+* Gap
+
+* Purpose:
+* Find a "nice" gap for tabulating FrameSet axis values.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status )
+
+* Class Membership:
+* FrameSet 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 FrameSet 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 FrameSet.
+* axis
+* The number of the axis (zero-based) for which a gap is to be found.
+* gap
+* The target gap size.
+* ntick
+* Address of an int in which to return a convenient number of
+* divisions into which the gap can be divided.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The nice gap size.
+
+* Notes:
+* - A value of zero is returned if the target gap size is zero.
+* - A negative gap size is returned if the supplied gap size is negative.
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double result; /* Gap value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0.0;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astGap" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astGap method to obtain the required gap value. Annul the
+ Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astGap( fr, axis, gap, ntick );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = 0.0;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetNode( AstFrameSet *this, int inode, int *nnodes,
+ int *iframe, AstMapping **map, int *parent,
+ int *status ) {
+/*
+*+
+* Name:
+* astGetNode
+
+* Purpose:
+* Get information about a single node in a FrameSet tree.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astGetNode( AstFrameSet *this, int inode, int *nnodes,
+* int *iframe, AstMapping **map, int *parent )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns information about a specified node in a
+* FrameSet. It is documented as protected, because it should not
+* be used in general purpose software since it depends on the internal
+* details of the FrameSet class. However, it is in fact public so that
+* it can be used in external software that needs to know about the
+* internal structure of a FrameSet (for instance, a graphical FrameSet
+* visualisation system).
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* inode
+* The zero-based index of the required node.
+* nnodes
+* Address of an int returned holding the number of nodes defined
+* in the FrameSet.
+* iframe
+* Address of an int returned holding the one-based index of the
+* Frame associated with the node. AST__NOFRAME is returned if the
+* node has no Frame.
+* map
+* Address of a Mapping pointer returned holding a pointer to a
+* deep copy of the Mapping, if any, from the parent node to the
+* requested node. NULL is returned if the node has no parent.
+* parent
+* Address of an int returned holding the zero-based index of the
+* node from which the requested node is derived. -1 is returned if
+* the requested node has no parent (i.e. is the root of the tree).
+
+* Returned Value:
+* A non-zero value is returned if the "inode" value is within bounds.
+* Otherwise, zero is returned.
+
+*-
+*/
+
+/* Local Variables: */
+ int jframe;
+ int result;
+
+/* Initialise returned values. */
+ *nnodes = 0;
+ *iframe = AST__NOFRAME;
+ *map = NULL;
+ *parent = -1;
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Return the number of nodes. */
+ *nnodes = this->nnode;
+
+/* Check the index of the requested node. */
+ if( inode >= 0 && inode < this->nnode ) {
+
+/* Get the index of the Frame - if any - associated with the node. */
+ for( jframe = 0; jframe < this->nframe; jframe++ ) {
+ if( this->node[ jframe ] == inode ) {
+ *iframe = jframe + 1;
+ break;
+ }
+ }
+
+/* Get the Mapping - if any - associated with the node. The root node -
+ node zero - has no mapping or parent node. */
+ if( inode > 0 ) {
+ *map = astCopy( this->map[ inode - 1 ] );
+ if( astGetInvert( *map ) != this->invert[ inode - 1 ] ) {
+ astSetInvert( *map, this->invert[ inode - 1 ] );
+ }
+
+/* The index of the parent node. */
+ *parent = this->link[ inode - 1 ];
+ }
+
+/* Indicate success. */
+ result = 1;
+ }
+
+ 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 "frameset.h"
+* int GetObjSize( AstObject *this, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astGetObjSize protected
+* method inherited from the parent class).
+
+* Description:
+* This function returns the in-memory size of the supplied FrameSet,
+* in bytes.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* 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: */
+ AstFrameSet *this; /* Pointer to FrameSet structure */
+ int result; /* Result value to return */
+ int iframe; /* Loop counter for Frames */
+ int inode; /* Loop counter for nodes */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointers to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* Invoke the GetObjSize method inherited from the parent class, and then
+ add on any components of the class structure defined by thsi class
+ which are stored in dynamically allocated memory. */
+ result = (*parent_getobjsize)( this_object, status );
+
+ for ( iframe = 0; iframe < this->nframe; iframe++ ) {
+ result += astGetObjSize( this->frame[ iframe ] );
+ }
+
+ for ( inode = 0; inode < this->nnode - 1; inode++ ) {
+ result += astGetObjSize( this->map[ inode ] );
+ }
+
+ result += astTSizeOf( this->frame );
+ result += astTSizeOf( this->varfrm );
+ result += astTSizeOf( this->node );
+ result += astTSizeOf( this->map );
+ result += astTSizeOf( this->link );
+ result += astTSizeOf( this->invert );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result, */
+ return result;
+}
+
+static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* GetAttrib
+
+* Purpose:
+* Get the value of a specified attribute for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* const char *GetAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* FrameSet 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 FrameSet, formatted as a character string.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* attrib
+* Pointer to a null-terminated string containing the name of
+* the attribute whose value is required. This name should be in
+* lower case, with all white space removed.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* - Pointer to a null-terminated string containing the attribute
+* value.
+
+* Notes:
+* - The returned string pointer may point at memory allocated
+* within the FrameSet, 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 FrameSet. A copy of the string should
+* therefore be made if necessary.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ const char *result; /* Pointer value to return */
+ int base; /* Base attribute value */
+ int current; /* Current attribute value */
+ int invert; /* Invert attribute value */
+ int nframe; /* Nframe attribute value */
+ int nin; /* Nin attribute value */
+ int nobject; /* Nobject attribute value */
+ int nout; /* Nout attribute value */
+ int ref_count; /* RefCount attribute value */
+ int report; /* Report attribute value */
+ int tranforward; /* TranForward attribute value */
+ int traninverse; /* TranInverse attribute value */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_object);
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* Compare "attrib" with each recognised attribute name in turn,
+ obtaining the value of the required attribute. If necessary, write
+ the value into "getattrib_buff" as a null-terminated string in an appropriate
+ format. Set "result" to point at the result string. */
+
+/* We first handle attributes that apply to the FrameSet as a whole
+ (rather than to the current Frame). */
+
+/* AllVariants. */
+/* ------------ */
+ if ( !strcmp( attrib, "allvariants" ) ) {
+ result = astGetAllVariants( this );
+
+/* Base. */
+/* ----- */
+ } else if ( !strcmp( attrib, "base" ) ) {
+ base = astGetBase( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", base );
+ result = getattrib_buff;
+ }
+
+/* Class. */
+/* ------ */
+ } else if ( !strcmp( attrib, "class" ) ) {
+ result = astGetClass( this );
+
+/* Current. */
+/* -------- */
+ } else if ( !strcmp( attrib, "current" ) ) {
+ current = astGetCurrent( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", current );
+ result = getattrib_buff;
+ }
+
+/* ID. */
+/* --- */
+ } else if ( !strcmp( attrib, "id" ) ) {
+ result = astGetID( this );
+
+/* Ident. */
+/* ------ */
+ } else if ( !strcmp( attrib, "ident" ) ) {
+ result = astGetIdent( this );
+
+/* Invert. */
+/* ------- */
+ } else if ( !strcmp( attrib, "invert" ) ) {
+ invert = astGetInvert( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", invert );
+ result = getattrib_buff;
+ }
+
+/* Nframe. */
+/* ------- */
+ } else if ( !strcmp( attrib, "nframe" ) ) {
+ nframe = astGetNframe( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", nframe );
+ result = getattrib_buff;
+ }
+
+/* Nin. */
+/* ---- */
+ } else if ( !strcmp( attrib, "nin" ) ) {
+ nin = astGetNin( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", nin );
+ result = getattrib_buff;
+ }
+
+/* Nobject. */
+/* -------- */
+ } else if ( !strcmp( attrib, "nobject" ) ) {
+ nobject = astGetNobject( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", nobject );
+ result = getattrib_buff;
+ }
+
+/* Nout. */
+/* ----- */
+ } else if ( !strcmp( attrib, "nout" ) ) {
+ nout = astGetNout( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", nout );
+ result = getattrib_buff;
+ }
+
+/* RefCount. */
+/* --------- */
+ } else if ( !strcmp( attrib, "refcount" ) ) {
+ ref_count = astGetRefCount( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", ref_count );
+ result = getattrib_buff;
+ }
+
+/* Report. */
+/* ------- */
+ } else if ( !strcmp( attrib, "report" ) ) {
+ report = astGetReport( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", report );
+ result = getattrib_buff;
+ }
+
+/* TranForward. */
+/* ------------ */
+ } else if ( !strcmp( attrib, "tranforward" ) ) {
+ tranforward = astGetTranForward( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", tranforward );
+ result = getattrib_buff;
+ }
+
+/* TranInverse. */
+/* ------------ */
+ } else if ( !strcmp( attrib, "traninverse" ) ) {
+ traninverse = astGetTranInverse( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", traninverse );
+ result = getattrib_buff;
+ }
+
+/* Variant. */
+/* -------- */
+ } else if ( !strcmp( attrib, "variant" ) ) {
+ result = astGetVariant( this );
+
+/* Pass unrecognised attributes on to the FrameSet's current Frame for
+ further interpretation. */
+ } else {
+
+/* Obtain a pointer to the current Frame and invoke its astGetAttrib
+ method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astGetAttrib( fr, attrib );
+ fr = astAnnul( fr );
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+static AstAxis *GetAxis( AstFrame *this_frame, int axis, int *status ) {
+/*
+* Name:
+* GetAxis
+
+* Purpose:
+* Obtain a pointer to a specified Axis from a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstAxis *GetAxis( AstFrame *this, int axis, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astGetAxis method
+* inherited from the Frame class).
+
+* Description:
+* This function returns a pointer to the Axis object associated
+* with one of the axes of the current Frame of a FrameSet. This
+* object describes the quantity which is represented along that
+* axis.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* axis
+* The number of the axis (zero-based) for which an Axis pointer
+* is required.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to the requested Axis object.
+
+* Notes:
+* - The reference count of the requested Axis object will be
+* incremented by one to reflect the additional pointer returned by
+* this function.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstAxis *result; /* Pointer to Axis */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astGetAxis" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astGetAxis method to obtain the required Axis
+ pointer. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astGetAxis( fr, axis );
+ fr = astAnnul( fr );
+
+/* If an error occurred, annul the result. */
+ if ( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static int GetBase( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astGetBase
+
+* Purpose:
+* Obtain the value of the Base attribute for a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astGetBase( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns the value of the Base attribute for a
+* FrameSet. This value is an index that identifies the base Frame
+* in the FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* The Base attribute value.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ int invert; /* FrameSet is inverted? */
+ int result; /* Value to return */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Determine if the FrameSet has been inverted. */
+ invert = astGetInvert( this );
+
+/* If it has not been inverted, return the base Frame index, otherwise
+ return the index of the current Frame instead. Provide defaults if
+ necessary. */
+ if ( astOK ) {
+ if ( !invert ) {
+ result = ( this->base != -INT_MAX ) ? this->base : 1;
+ } else {
+ result = ( this->current != -INT_MAX ) ? this->current :
+ astGetNframe( this );
+ }
+ }
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetCurrent( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astGetCurrent
+
+* Purpose:
+* Obtain the value of the Current attribute for a FrameSet.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astGetCurrent( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns the value of the Current attribute for a
+* FrameSet. This attribute is an index that identifies the
+* current Frame in a FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* Value of the Current attribute.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ int invert; /* FrameSet is inverted? */
+ int result; /* Value to return */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Determine if the FrameSet has been inverted. */
+ invert = astGetInvert( this );
+
+/* If it has not been inverted, return the current Frame index,
+ otherwise return the index of the base Frame instead. Provide
+ defaults if necessary. */
+ if ( astOK ) {
+ if ( !invert ) {
+ result = ( this->current != -INT_MAX ) ? this->current :
+ astGetNframe( this );
+ } else {
+ result = ( this->base != -INT_MAX ) ? this->base : 1;
+ }
+ }
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static AstFrame *GetFrame( AstFrameSet *this, int iframe, int *status ) {
+/*
+*++
+* Name:
+c astGetFrame
+f AST_GETFRAME
+
+* Purpose:
+* Obtain a pointer to a specified Frame in a FrameSet.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frameset.h"
+c AstFrame *astGetFrame( AstFrameSet *this, int iframe )
+f RESULT = AST_GETFRAME( THIS, IFRAME, STATUS )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns a pointer to a specified Frame in a
+* FrameSet.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the FrameSet.
+c iframe
+f IFRAME = INTEGER (Given)
+* The index of the required Frame within the FrameSet. This
+* value should lie in the range from 1 to the number of Frames
+* in the FrameSet (as given by its Nframe attribute).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astGetFrame()
+f AST_GETFRAME = INTEGER
+* A pointer to the requested Frame.
+
+* Notes:
+* - A value of AST__BASE or AST__CURRENT may be given for the
+c "iframe" parameter to specify the base Frame or the current
+f IFRAME argument to specify the base Frame or the current
+* Frame respectively.
+* - This function increments the RefCount attribute of the
+* selected Frame by one.
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+*--
+*/
+
+/* Local Variables: */
+ AstFrame *result; /* Pointer value to return */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate and translate the Frame index supplied. */
+ iframe = astValidateFrameIndex( this, iframe, "astGetFrame" );
+
+/* If OK, clone a pointer to the requested Frame. */
+ if ( astOK ) result = astClone( this->frame[ iframe - 1 ] );
+
+/* Return the result. */
+ return result;
+}
+
+static int GetIsLinear( AstMapping *this_mapping, int *status ){
+/*
+* Name:
+* GetIsLinear
+
+* Purpose:
+* Return the value of the IsLinear attribute for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "mapping.h"
+* void GetIsLinear( AstMapping *this, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astGetIsLinear
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns the value of the IsLinear attribute for a
+* FrameSet, which is the IsLinear value of he base->current Mapping.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+*/
+/* Local Variables: */
+ AstMapping *map;
+ int result;
+
+/* Check global status */
+ if( !astOK ) return 0;
+
+/* Get the Mapping. */
+ map = astGetMapping( (AstFrameSet *) this_mapping, AST__BASE,
+ AST__CURRENT );
+
+/* Get its IsLinear attribute value. */
+ result = astGetIsLinear( map );
+
+/* Free the Mapping. */
+ map = astAnnul( map );
+
+/* Return the result. */
+ return result;
+}
+
+static AstMapping *GetMapping( AstFrameSet *this, int iframe1, int iframe2, int *status ) {
+/*
+*++
+* Name:
+c astGetMapping
+f AST_GETMAPPING
+
+* Purpose:
+* Obtain a Mapping that converts between two Frames in a FrameSet.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frameset.h"
+c AstMapping *astGetMapping( AstFrameSet *this, int iframe1, int iframe2 )
+f RESULT = AST_GETMAPPING( THIS, IFRAME1, IFRAME2, STATUS )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns a pointer to a Mapping that will convert
+* coordinates between the coordinate systems represented by two
+* Frames in a FrameSet.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the FrameSet.
+c iframe1
+f IFRAME1 = INTEGER (Given)
+* The index of the first Frame in the FrameSet. This Frame describes
+* the coordinate system for the "input" end of the Mapping.
+c iframe2
+f IFRAME2 = INTEGER (Given)
+* The index of the second Frame in the FrameSet. This Frame
+* describes the coordinate system for the "output" end of the
+* Mapping.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astGetMapping()
+f AST_GETMAPPING = INTEGER
+* Pointer to a Mapping whose forward transformation converts
+* coordinates from the first coordinate system to the second
+* one, and whose inverse transformation converts coordinates in
+* the opposite direction.
+
+* Notes:
+* - The returned Mapping will include the clipping effect of any
+* Regions which occur on the path between the two supplied Frames
+* (this includes the two supplied Frames themselves).
+c - The values given for the "iframe1" and "iframe2" parameters
+f - The values given for the IFRAME1 and IFRAME2 arguments
+* should lie in the range from 1 to the number of Frames in the
+* FrameSet (as given by its Nframe attribute). A value of
+* AST__BASE or AST__CURRENT may also be given to identify the
+* FrameSet's base Frame or current Frame respectively. It is
+c permissible for both these parameters to have the same value, in
+f permissible for both these arguments to have the same value, in
+* which case a unit Mapping (UnitMap) is returned.
+* - It should always be possible to generate the Mapping
+* requested, but this does necessarily guarantee that it will be
+* able to perform the required coordinate conversion. If
+* necessary, the TranForward and TranInverse attributes of the
+* returned Mapping should be inspected to determine if the
+* required transformation is available.
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+*--
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Temporary pointer to Frame */
+ AstFrame **frames; /* Pointer to array of Frames */
+ AstMapping **path; /* Pointer to array of conversion Mappings */
+ AstMapping *copy; /* Pointer to copy of Mapping */
+ AstMapping *result; /* Result pointer to be returned */
+ AstMapping *tmp; /* Temporary pointer for joining Mappings */
+ int *forward; /* Pointer to array of Mapping directions */
+ int ipath; /* Loop counter for conversion path steps */
+ int iframe; /* Frame index */
+ int inode; /* Node index */
+ int npath; /* Number of steps in conversion path */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate and translate the Frame indices supplied. */
+ iframe1 = astValidateFrameIndex( this, iframe1, "astGetMapping" );
+ iframe2 = astValidateFrameIndex( this, iframe2, "astGetMapping" );
+
+/* Allocate memory to hold an array of Mapping pointers and associated
+ direction flags - a maximum of one element for each Mapping and one
+ for each Frame in the FrameSet. */
+ path = astMalloc( sizeof( AstMapping * ) * (size_t) ( this->nnode - 1 +
+ this->nframe ) );
+ forward = astMalloc( sizeof( int ) * (size_t) ( this->nnode - 1 +
+ this->nframe ) );
+
+/* Allocate memory to hold a list of the Frame pointers (if any) associated
+ with each node. */
+ frames = astMalloc( sizeof( AstFrame * ) * (size_t) ( this->nnode ) );
+
+/* If OK, set up an array of Frame pointers indexed by node index. If a
+ node has no associated Frame store a NULL pointer. This is needed so
+ that we can find Frame pointers quickly within the Span function. Note,
+ we simply copy the pointers rather than cloning them, so they do not
+ need to be annulled when finished with. */
+ if ( astOK ) {
+ for( inode = 0; inode < this->nnode; inode++ ) frames[ inode ] = NULL;
+ for( iframe = 0; iframe < this->nframe; iframe++ ) {
+ frames[ this->node[ iframe ] ] = this->frame[ iframe ];
+ }
+
+/* Obtain the Mapping pointers and direction flags needed to convert
+ coordinates between the nodes associated with the two specified
+ Frames. */
+ npath = Span( this, frames, this->node[ iframe1 - 1 ],
+ this->node[ iframe2 - 1 ], -1, path, forward, status ) - 1;
+
+/* If this failed, it indicates a corrupt FrameSet object, so report
+ an error. */
+ if ( npath < 0 ) {
+ astError( AST__FRSIN, "astGetMapping(%s): Invalid or corrupt "
+ "%s - could not find conversion path between Frames "
+ "%d and %d.", status, astGetClass( this ), astGetClass( this ),
+ iframe1, iframe2 );
+
+/* If the conversion path is of zero length (i.e. the two Frames are
+ the same) then we will return a Mapping which is equivalent to the
+ Frame. Most classes of Frame are equivalent to a UnitMap. However, we do
+ not hard-wire this equivalence since some classes of Frame (e.g. Regions
+ or CmpFrames containing Regions) do not correspond to a UnitMap. Instead
+ we use the astIsUnitFrame method on the Frame to determine if the
+ Frame is equivalent to a UnitMap.Is os, create a suitable UnitMap. If
+ not, return the Frame itself (a form of Mapping). */
+ } else if ( npath == 0 ) {
+ fr = astGetFrame( this, iframe1 );
+ if( astIsUnitFrame( fr ) ){
+ result = (AstMapping *) astUnitMap( astGetNaxes( fr ), "", status );
+ } else {
+ result = (AstMapping *) astClone( fr );
+ }
+ fr = astAnnul( fr );
+
+/* If the conversion path involves at least one non-trivial Mapping,
+ make a copy of the first Mapping, inverting the copy if
+ necessary. */
+ } else {
+ result = astCopy( path[ 0 ] );
+ if ( !forward[ 0 ] ) astInvert( result );
+
+/* Now loop to concatenate any further Mappings. First make a copy of
+ each additional Mapping and invert the copy if necessary. */
+ for ( ipath = 1; ipath < npath; ipath++ ) {
+ copy = astCopy( path[ ipath ] );
+ if ( !forward[ ipath ] ) astInvert( copy );
+
+/* Concatenate the copy with the result so far, then annul the pointer
+ to the copy and save the pointer to the new result. */
+ tmp = (AstMapping *) astCmpMap( result, copy, 1, "", status );
+ result = astAnnul( result );
+ copy = astAnnul( copy );
+ result = tmp;
+ }
+ }
+ }
+
+/* Free the memory allocated for the conversion path information. */
+ path = astFree( path );
+ forward = astFree( forward );
+ frames = astFree( frames );
+
+/* If an error occurred, annul the returned Mapping. */
+ if ( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static int GetNaxes( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* GetNaxes
+
+* Purpose:
+* Determine how many axes a FrameSet has.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int GetNaxes( AstFrame *this, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astGetNaxes method
+* inherited from the Frame class).
+
+* Description:
+* This function returns the number of axes for a FrameSet. This is equal
+* to the number of axes in its current Frame.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The number of FrameSet axes (zero or more).
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int result; /* Result to be returned */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame. */
+ fr = astGetFrame( this, AST__CURRENT );
+
+/* Obtain the number of axes in this Frame. */
+ result = astGetNaxes( fr );
+
+/* Annul the current Frame pointer. */
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetNframe( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astGetNframe
+
+* Purpose:
+* Determine the number of Frames in a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astGetNframe( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns the number of Frames in a FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* The number of Frames in the FrameSet (always 1 or more).
+
+* 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.
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Return the Frame count. */
+ return this->nframe;
+}
+
+static int GetNin( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* GetNin
+
+* Purpose:
+* Get the number of input coordinates for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int GetNin( AstMapping *this, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astGetNin method
+* inherited from the Frame class).
+
+* Description:
+* This function returns the number of input coordinate values
+* required per point by a FrameSet when used to transform a set of
+* points (i.e. the number of dimensions of the space in which the
+* input points reside).
+*
+* The value returned is equal to the number of axes in the
+* FrameSet's base Frame.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Number of coordinate values required.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to base Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int result; /* Result to be returned */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_mapping;
+
+/* Obtain a pointer to the FrameSet's base Frame. */
+ fr = astGetFrame( this, AST__BASE );
+
+/* Obtain the number of axes in this Frame. */
+ result = astGetNaxes( fr );
+
+/* Annul the base Frame pointer. */
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetNout( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* GetNout
+
+* Purpose:
+* Get the number of output coordinates for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int GetNout( AstMapping *this, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astGetNout method
+* inherited from the Frame class).
+
+* Description:
+* This function returns the number of output coordinate values
+* generated per point by a FrameSet when used to transform a set
+* of points (i.e. the number of dimensions of the space in which
+* the output points reside).
+*
+* The value returned is equal to the number of axes in the
+* FrameSet's current Frame.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Number of coordinate values generated.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Return the number of axes in the FrameSet's current Frame. */
+ return GetNaxes( (AstFrame *) this_mapping, status );
+}
+
+static const int *GetPerm( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* GetPerm
+
+* Purpose:
+* Access the axis permutation array for the current Frame of a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* const int *GetPerm( AstFrame *this, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astGetPerm protected
+* method inherited from the Frame class).
+
+* Description:
+* This function returns a pointer to the axis permutation array
+* for the current Frame of a FrameSet. This array constitutes a
+* lookup-table that converts between an axis number supplied
+* externally and the corresponding index in the Frame's internal
+* axis arrays.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the current Frame's axis permutation array (a
+* constant array of int). Each element of this contains the
+* (zero-based) internal axis index to be used in place of the
+* external index which is used to address the permutation
+* array. If the current Frame has zero axes, this pointer will be
+* NULL.
+
+* Notes:
+* - The pointer returned by this function gives direct access to
+* data internal to the Frame object. It remains valid only so long
+* as the Frame exists. The permutation array contents may be
+* modified by other functions which operate on the Frame and this
+* may render the returned pointer invalid.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to FrameSet structure */
+ const int *result; /* Result pointer value */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and then obtain a
+ pointer to its axis permutation array. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astGetPerm( fr );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetTranForward( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* GetTranForward
+
+* Purpose:
+* Determine if a FrameSet defines a forward coordinate transformation.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int GetTranForward( AstMapping *this )
+
+* Class Membership:
+* Frameset member function (over-rides the astGetTranForward
+* protected method inherited from the Frame class).
+
+* Description:
+* This function returns a value indicating whether a FrameSet is
+* able to perform a coordinate transformation in the "forward"
+* direction.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* Zero if the forward coordinate transformation is not defined, or
+* 1 if it is.
+
+* 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: */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ AstMapping *map; /* Pointer to base->current Mapping */
+ int result; /* Result to be returned */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_mapping;
+
+/* Obtain the Mapping between the base and current Frames in the
+ FrameSet (note this takes account of whether the FrameSet has been
+ inverted). */
+ map = astGetMapping( this, AST__BASE, AST__CURRENT );
+
+/* Determine whether the required transformation is defined. */
+ result = astGetTranForward( map );
+
+/* Annul the Mapping pointer. */
+ map = astAnnul( map );
+
+/* If an error occurred, clear the returned result. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetTranInverse( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* GetTranInverse
+
+* Purpose:
+* Determine if a FrameSet defines an inverse coordinate transformation.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int GetTranInverse( AstMapping *this )
+
+* Class Membership:
+* Frameset member function (over-rides the astGetTranInverse
+* protected method inherited from the Frame class).
+
+* Description:
+* This function returns a value indicating whether a FrameSet is
+* able to perform a coordinate transformation in the "inverse"
+* direction.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* Zero if the inverse coordinate transformation is not defined, or
+* 1 if it is.
+
+* 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: */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ AstMapping *map; /* Pointer to base->current Mapping */
+ int result; /* Result to be returned */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_mapping;
+
+/* Obtain the Mapping between the base and current Frames in the
+ FrameSet (note this takes account of whether the FrameSet has been
+ inverted). */
+ map = astGetMapping( this, AST__BASE, AST__CURRENT );
+
+/* Determine whether the required transformation is defined. */
+ result = astGetTranInverse( map );
+
+/* Annul the Mapping pointer. */
+ map = astAnnul( map );
+
+/* If an error occurred, clear the returned result. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetUseDefs( AstObject *this_object, int *status ) {
+/*
+* Name:
+* GetUseDefs
+
+* Purpose:
+* Get the value of the UseDefs attribute for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int GetUseDefs( AstObject *this_object, int *status ) {
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astGetUseDefs
+* method inherited from the Frame class).
+
+* Description:
+* This function returns the value of the UseDefs attribute for a FrameSet,
+* supplying a suitable default.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* - The USeDefs value.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int result; /* Value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* If the UseDefs value for the FrameSet has been set explicitly, use the
+ Get method inherited from the parent Frame class to get its value> */
+ if( astTestUseDefs( this ) ) {
+ result = (*parent_getusedefs)( this_object, status );
+
+/* Otherwise, supply a default value equal to the UseDefs value of the
+ current Frame. */
+ } else {
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astGetUseDefs( fr );
+ fr = astAnnul( fr );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int GetVarFrm( AstFrameSet *this, int iframe, int *status ) {
+/*
+* Name:
+* GetVarFrm
+
+* Purpose:
+* Get the index of the variants Frame for a nominated Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int GetVarFrm( AstFrameSet *this, int iframe, int *status ) {
+
+* Class Membership:
+* Private function.
+
+* Description:
+* This function returns the index of the variants Frame associated
+* with a nominated mirror Frame. See astMirrorVariants.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* iframe
+* The one-based index of the nominated Frame that may potentially be
+* a mirror for the variant Mappings in another Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The one-based Frame index of the Frame that defines the variant
+* Mappings associated with Frame "iframe". This will be the same as
+* "iframe" unless the nominated Frame is a mirror for another Frame.
+*/
+
+/* Local Variables: */
+ int result; /* Value to return */
+
+/* Initialise. */
+ result = AST__NOFRAME;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Initialise the returned value. */
+ result = iframe;
+
+/* If the nominated Frame is mirroring another Frame, return the index of
+ the mirrored Frame. Walk up the chain until we reach a Frame which is
+ not a mirror for another Frame. */
+ while( this->varfrm[ result - 1 ] > 0 ) {
+ if( this->varfrm[ result - 1 ] == result ) {
+ astError( AST__INTER, "GetVarFrm(FrameSet): FrameSet is corrupt "
+ "(internal programming error).", status );
+ break;
+ } else {
+ result = this->varfrm[ result - 1 ];
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *GetVariant( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astGetVariant
+
+* Purpose:
+* Obtain the value of the Variant attribute for a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* const char *astGetVariant( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns the value of the Variant attribute for a
+* FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* The Variant attribute value.
+
+* Notes:
+* - A NULL value will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstFrame *frm;
+ AstFrame *vfs;
+ const char *result;
+ int icur;
+ int iuse;
+
+/* Initialise */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get the one-based index of the current Frame. */
+ icur = astGetCurrent( this );
+
+/* The current Frame may mirror the variant Mappings in another Frame,
+ rather than defining any variant Mappings itself. Get the one-based
+ index of the Frame that defines the variant Mappings to use. */
+ iuse = GetVarFrm( this, icur, status );
+
+/* Get a pointer to the Variants FrameSet in the used Frame. */
+ frm = astGetFrame( this, iuse );
+ vfs = astGetFrameVariants( frm );
+
+/* If the current Frame has no Variants FrameSet, return the Domain name
+ of the current Frame. */
+ if( !vfs ) {
+ result = astGetDomain( this );
+
+/* Otherwise, return the Domain name of the current Frame in the Variants
+ FrameSet. Then annul the Variants FrameSet pointer. */
+ } else {
+ result = astGetDomain( vfs );
+ vfs = astAnnul( vfs );
+ }
+
+/* Annul the current Frame pointer. */
+ frm = astAnnul( frm );
+
+/* If an error occurred, clear the result. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+void astInitFrameSetVtab_( AstFrameSetVtab *vtab, const char *name, int *status ) {
+/*
+*+
+* Name:
+* astInitFrameSetVtab
+
+* Purpose:
+* Initialise a virtual function table for a FrameSet.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frameset.h"
+* void astInitFrameSetVtab( AstFrameSetVtab *vtab, const char *name )
+
+* Class Membership:
+* FrameSet vtab initialiser.
+
+* Description:
+* This function initialises the component of a virtual function
+* table which is used by the FrameSet class.
+
+* Parameters:
+* vtab
+* Pointer to the virtual function table. The components used by
+* all ancestral classes will be initialised if they have not already
+* been initialised.
+* name
+* Pointer to a constant null-terminated character string which contains
+* the name of the class to which the virtual function table belongs (it
+* is this pointer value that will subsequently be returned by the Object
+* astClass function).
+*-
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstFrameVtab *frame; /* Pointer to Frame component of Vtab */
+ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */
+ AstObjectVtab *object; /* Pointer to Object component of Vtab */
+
+/* Check the local error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Initialize the component of the virtual function table used by the
+ parent class. */
+ astInitFrameVtab( (AstFrameVtab *) vtab, name );
+
+/* Store a unique "magic" value in the virtual function table. This
+ will be used (by astIsAFrameSet) to determine if an object belongs
+ to this class. We can conveniently use the address of the (static)
+ class_check variable to generate this unique value. */
+ vtab->id.check = &class_check;
+ vtab->id.parent = &(((AstFrameVtab *) vtab)->id);
+
+/* Initialise member function pointers. */
+/* ------------------------------------ */
+/* Store pointers to the member functions (implemented here) that
+ provide virtual methods for this class. */
+ vtab->AddFrame = AddFrame;
+ vtab->AddVariant = AddVariant;
+ vtab->ClearBase = ClearBase;
+ vtab->ClearCurrent = ClearCurrent;
+ vtab->GetBase = GetBase;
+ vtab->GetCurrent = GetCurrent;
+ vtab->GetFrame = GetFrame;
+ vtab->GetMapping = GetMapping;
+ vtab->GetNframe = GetNframe;
+ vtab->GetNode = GetNode;
+ vtab->GetAllVariants = GetAllVariants;
+ vtab->MirrorVariants = MirrorVariants;
+ vtab->RemapFrame = RemapFrame;
+ vtab->RemoveFrame = RemoveFrame;
+ vtab->SetBase = SetBase;
+ vtab->SetCurrent = SetCurrent;
+ vtab->TestBase = TestBase;
+ vtab->TestCurrent = TestCurrent;
+ vtab->ValidateFrameIndex = ValidateFrameIndex;
+
+ vtab->ClearVariant = ClearVariant;
+ vtab->GetVariant = GetVariant;
+ vtab->SetVariant = SetVariant;
+ vtab->TestVariant = TestVariant;
+
+/* Save the inherited pointers to methods that will be extended, and
+ replace them with pointers to the new member functions. */
+ object = (AstObjectVtab *) vtab;
+
+ parent_clear = object->Clear;
+ parent_getobjsize = object->GetObjSize;
+ object->GetObjSize = GetObjSize;
+ object->Clear = Clear;
+
+ parent_vset = object->VSet;
+ object->VSet = VSet;
+
+ parent_getusedefs = object->GetUseDefs;
+ object->GetUseDefs = GetUseDefs;
+
+#if defined(THREAD_SAFE)
+ parent_managelock = object->ManageLock;
+ object->ManageLock = ManageLock;
+#endif
+
+/* Store replacement pointers for methods which will be over-ridden by
+ new member functions implemented here. */
+ mapping = (AstMappingVtab *) vtab;
+ frame = (AstFrameVtab *) vtab;
+
+ object->ClearAttrib = ClearAttrib;
+ object->GetAttrib = GetAttrib;
+ object->SetAttrib = SetAttrib;
+ object->TestAttrib = TestAttrib;
+
+ object->GetUseDefs = GetUseDefs;
+ object->Equal = Equal;
+ object->Cast = Cast;
+
+ mapping->GetIsLinear = GetIsLinear;
+ mapping->GetNin = GetNin;
+ mapping->GetNout = GetNout;
+ mapping->GetTranForward = GetTranForward;
+ mapping->GetTranInverse = GetTranInverse;
+ mapping->Rate = Rate;
+ mapping->ReportPoints = ReportPoints;
+ mapping->RemoveRegions = RemoveRegions;
+ mapping->Simplify = Simplify;
+ mapping->Transform = Transform;
+ mapping->MapSplit = MapSplit;
+
+ frame->Abbrev = Abbrev;
+ frame->Angle = Angle;
+ frame->AxAngle = AxAngle;
+ frame->AxDistance = AxDistance;
+ frame->AxNorm = AxNorm;
+ frame->AxOffset = AxOffset;
+ frame->CheckPerm = CheckPerm;
+ frame->ClearDigits = ClearDigits;
+ frame->ClearDirection = ClearDirection;
+ frame->ClearDomain = ClearDomain;
+ frame->ClearFormat = ClearFormat;
+ frame->ClearLabel = ClearLabel;
+ frame->ClearMatchEnd = ClearMatchEnd;
+ frame->ClearMaxAxes = ClearMaxAxes;
+ frame->ClearMinAxes = ClearMinAxes;
+ frame->ClearPermute = ClearPermute;
+ frame->ClearPreserveAxes = ClearPreserveAxes;
+ frame->ClearSymbol = ClearSymbol;
+ frame->ClearTitle = ClearTitle;
+ frame->ClearUnit = ClearUnit;
+ frame->Convert = Convert;
+ frame->ConvertX = ConvertX;
+ frame->Distance = Distance;
+ frame->Fields = Fields;
+ frame->FindFrame = FindFrame;
+ frame->Format = Format;
+ frame->FrameGrid = FrameGrid;
+ frame->Centre = Centre;
+ frame->Gap = Gap;
+ frame->GetAxis = GetAxis;
+ frame->GetDigits = GetDigits;
+ frame->GetDirection = GetDirection;
+ frame->GetDomain = GetDomain;
+ frame->GetFormat = GetFormat;
+ frame->GetLabel = GetLabel;
+ frame->GetMatchEnd = GetMatchEnd;
+ frame->GetMaxAxes = GetMaxAxes;
+ frame->GetMinAxes = GetMinAxes;
+ frame->GetNaxes = GetNaxes;
+ frame->GetPerm = GetPerm;
+ frame->GetPermute = GetPermute;
+ frame->GetPreserveAxes = GetPreserveAxes;
+ frame->GetSymbol = GetSymbol;
+ frame->GetTitle = GetTitle;
+ frame->GetUnit = GetUnit;
+ frame->Intersect = Intersect;
+ frame->IsUnitFrame = IsUnitFrame;
+ frame->LineContains = LineContains;
+ frame->LineCrossing = LineCrossing;
+ frame->LineDef = LineDef;
+ frame->LineOffset = LineOffset;
+ frame->Match = Match;
+ frame->MatchAxes = MatchAxes;
+ frame->MatchAxesX = MatchAxesX;
+ frame->Norm = Norm;
+ frame->NormBox = NormBox;
+ frame->Offset = Offset;
+ frame->Offset2 = Offset2;
+ frame->Overlay = Overlay;
+ frame->PermAxes = PermAxes;
+ frame->PickAxes = PickAxes;
+ frame->PrimaryFrame = PrimaryFrame;
+ frame->Resolve = Resolve;
+ frame->ResolvePoints = ResolvePoints;
+ frame->SetAxis = SetAxis;
+ frame->SetDigits = SetDigits;
+ frame->SetDirection = SetDirection;
+ frame->SetDomain = SetDomain;
+ frame->SetFormat = SetFormat;
+ frame->SetLabel = SetLabel;
+ frame->SetMatchEnd = SetMatchEnd;
+ frame->SetMaxAxes = SetMaxAxes;
+ frame->SetMinAxes = SetMinAxes;
+ frame->SetPermute = SetPermute;
+ frame->SetPreserveAxes = SetPreserveAxes;
+ frame->SetSymbol = SetSymbol;
+ frame->SetTitle = SetTitle;
+ frame->SetUnit = SetUnit;
+ frame->SubFrame = SubFrame;
+ frame->SystemCode = SystemCode;
+ frame->SystemString = SystemString;
+ frame->TestDigits = TestDigits;
+ frame->TestDirection = TestDirection;
+ frame->TestDomain = TestDomain;
+ frame->TestFormat = TestFormat;
+ frame->TestLabel = TestLabel;
+ frame->TestMatchEnd = TestMatchEnd;
+ frame->TestMaxAxes = TestMaxAxes;
+ frame->TestMinAxes = TestMinAxes;
+ frame->TestPermute = TestPermute;
+ frame->TestPreserveAxes = TestPreserveAxes;
+ frame->TestSymbol = TestSymbol;
+ frame->TestTitle = TestTitle;
+ frame->TestUnit = TestUnit;
+ frame->Unformat = Unformat;
+ frame->ValidateAxis = ValidateAxis;
+ frame->ValidateAxisSelection = ValidateAxisSelection;
+ frame->ValidateSystem = ValidateSystem;
+
+ frame->GetActiveUnit = GetActiveUnit;
+ frame->SetActiveUnit = SetActiveUnit;
+ frame->TestActiveUnit = TestActiveUnit;
+
+ frame->GetTop = GetTop;
+ frame->SetTop = SetTop;
+ frame->TestTop = TestTop;
+ frame->ClearTop = ClearTop;
+
+ frame->GetBottom = GetBottom;
+ frame->SetBottom = SetBottom;
+ frame->TestBottom = TestBottom;
+ frame->ClearBottom = ClearBottom;
+
+ frame->GetEpoch = GetEpoch;
+ frame->SetEpoch = SetEpoch;
+ frame->TestEpoch = TestEpoch;
+ frame->ClearEpoch = ClearEpoch;
+
+ frame->GetDtai = GetDtai;
+ frame->SetDtai = SetDtai;
+ frame->TestDtai = TestDtai;
+ frame->ClearDtai = ClearDtai;
+
+ frame->GetDut1 = GetDut1;
+ frame->SetDut1 = SetDut1;
+ frame->TestDut1 = TestDut1;
+ frame->ClearDut1 = ClearDut1;
+
+ frame->GetSystem = GetSystem;
+ frame->SetSystem = SetSystem;
+ frame->TestSystem = TestSystem;
+ frame->ClearSystem = ClearSystem;
+
+ frame->GetAlignSystem = GetAlignSystem;
+ frame->SetAlignSystem = SetAlignSystem;
+ frame->TestAlignSystem = TestAlignSystem;
+ frame->ClearAlignSystem = ClearAlignSystem;
+
+ frame->ClearObsLat = ClearObsLat;
+ frame->TestObsLat = TestObsLat;
+ frame->GetObsLat = GetObsLat;
+ frame->SetObsLat = SetObsLat;
+
+ frame->ClearObsAlt = ClearObsAlt;
+ frame->TestObsAlt = TestObsAlt;
+ frame->GetObsAlt = GetObsAlt;
+ frame->SetObsAlt = SetObsAlt;
+
+ frame->ClearObsLon = ClearObsLon;
+ frame->TestObsLon = TestObsLon;
+ frame->GetObsLon = GetObsLon;
+ frame->SetObsLon = SetObsLon;
+
+/* Declare the copy constructor, destructor and class dump
+ functions. */
+ astSetDelete( vtab, Delete );
+ astSetCopy( vtab, Copy );
+ astSetDump( vtab, Dump, "FrameSet",
+ "Set of inter-related coordinate systems" );
+
+/* If we have just initialised the vtab for the current class, indicate
+ that the vtab is now initialised, and store a pointer to the class
+ identifier in the base "object" level of the vtab. */
+ if( vtab == &class_vtab ) {
+ class_init = 1;
+ astSetVtabClassIdentifier( vtab, &(vtab->id) );
+ }
+}
+
+static void Intersect( AstFrame *this_frame, const double a1[2],
+ const double a2[2], const double b1[2],
+ const double b2[2], double cross[2],
+ int *status ) {
+/*
+* Name:
+* Intersect
+
+* Purpose:
+* Find the point of intersection between two geodesic curves.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void Intersect( AstFrame *this_frame, const double a1[2],
+* const double a2[2], const double b1[2],
+* const double b2[2], double cross[2],
+* int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astIntersect method
+* inherited from the Frame class).
+
+* Description:
+* This function finds the coordinate values at the point of
+* intersection between two geodesic curves. Each curve is specified
+* by two points on the curve.
+
+* Parameters:
+* this
+* Pointer to the SkyFrame.
+* a1
+* An array of double, with one element for each Frame axis.
+* This should contain the coordinates of a point on the first
+* geodesic curve.
+* a2
+* An array of double, with one element for each Frame axis.
+* This should contain the coordinates of a second point on the
+* first geodesic curve.
+* b1
+* An array of double, with one element for each Frame axis.
+* This should contain the coordinates of a point on the second
+* geodesic curve.
+* b2
+* An array of double, with one element for each Frame axis.
+* This should contain the coordinates of a second point on
+* the second geodesic curve.
+* cross
+* An array of double, with one element for each Frame axis
+* in which the coordinates of the required intersection
+* point will be returned. These will be AST__BAD if the curves do
+* not intersect.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - The geodesic curve used by this function is the path of
+* shortest distance between two points, as defined by the
+* astDistance function.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value.
+* - For SkyFrames each curve will be a great circle, and in general
+* each pair of curves will intersect at two diametrically opposite
+* points on the sky. The returned position is the one which is
+* closest to point "a1".
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astIntersect method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astIntersect( fr, a1, a2, b1, b2, cross );
+ fr = astAnnul( fr );
+
+}
+
+static int IsUnitFrame( AstFrame *this_frame, int *status ){
+/*
+* Name:
+* IsUnitFrame
+
+* Purpose:
+* Is this Frame equivalent to a UnitMap?
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int IsUnitFrame( AstFrame *this, int *status )
+
+* Class Membership:
+* FrameSet 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: */
+ AstFrame *fr; /* Pointer to FrameSet's current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int result; /* Result to be returned */
+
+/* Initialise the returned value. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame. */
+ fr = astGetFrame( this, AST__CURRENT );
+
+/* Invoke the astIsUnitFrame method for this Frame. */
+ result = astIsUnitFrame( fr );
+
+/* Annul the Frame pointer. */
+ fr = astAnnul( fr );
+
+/* If an error occurred, clean up by clearing the returned result. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static int LineContains( AstFrame *this_frame, AstLineDef *l, int def, double *point, int *status ) {
+/*
+* Name:
+* LineContains
+
+* Purpose:
+* Determine if a line contains a point.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astLineContains
+* method inherited from the Frame class).
+
+* Description:
+* This function determines if the supplied point is on the supplied
+* line within the supplied Frame.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* l
+* Pointer to the structure defining the line.
+* def
+* Should be set non-zero if the "point" array was created by a
+* call to astLineCrossing (in which case it may contain extra
+* information following the axis values),and zero otherwise.
+* point
+* Point to an array containing the axis values of the point to be
+* tested, possibly followed by extra cached information (see "def").
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A non-zero value is returned if the line contains the point.
+
+* Notes:
+* - The pointer supplied for "l" should have been created using the
+* astLineDef method. These structures contained cached information about
+* the lines which improve the efficiency of this method when many
+* repeated calls are made. An error will be reported if the structure
+* does not refer to the Frame specified by "this".
+* - Zero will be returned if this function is invoked with the global
+* error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ int result; /* Returned value */
+
+/* Initialise */
+ result =0;
+
+/* Obtain a pointer to the FrameSet's current Frame and then invoke the
+ method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( (AstFrameSet *) this_frame, AST__CURRENT );
+ result = astLineContains( fr, l, def, point );
+ fr = astAnnul( fr );
+
+/* Return the result. */
+ return result;
+}
+
+static int LineCrossing( AstFrame *this_frame, AstLineDef *l1, AstLineDef *l2,
+ double **cross, int *status ) {
+/*
+* Name:
+* LineCrossing
+
+* Purpose:
+* Determine if two lines cross.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
+* double **cross, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astLineCrossing
+* method inherited from the Frame class).
+
+* Description:
+* This function determines if the two suplied line segments cross,
+* and if so returns the axis values at the point where they cross.
+* A flag is also returned indicating if the crossing point occurs
+* within the length of both line segments, or outside one or both of
+* the line segments.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* l1
+* Pointer to the structure defining the first line.
+* l2
+* Pointer to the structure defining the second line.
+* cross
+* Pointer to a location at which to put a pointer to a dynamically
+* alocated array containing the axis values at the crossing. If
+* NULL is supplied no such array is returned. Otherwise, the returned
+* array should be freed using astFree when no longer needed. If the
+* lines are parallel (i.e. do not cross) then AST__BAD is returned for
+* all axis values. Note usable axis values are returned even if the
+* lines cross outside the segment defined by the start and end points
+* of the lines. The order of axes in the returned array will take
+* account of the current axis permutation array if appropriate. Note,
+* sub-classes such as SkyFrame may append extra values to the end
+* of the basic frame axis values. A NULL pointer is returned if an
+* error occurs.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A non-zero value is returned if the lines cross at a point which is
+* within the [start,end) segment of both lines. If the crossing point
+* is outside this segment on either line, or if the lines are parallel,
+* zero is returned. Note, the start point is considered to be inside
+* the length of the segment, but the end point is outside.
+
+* Notes:
+* - The pointers supplied for "l1" and "l2" should have been created
+* using the astLineDef method. These structures contained cached
+* information about the lines which improve the efficiency of this method
+* when many repeated calls are made. An error will be reported if
+* either structure does not refer to the Frame specified by "this".
+* - Zero will be returned if this function is invoked with the global
+* error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ int result; /* Returned value */
+
+/* Initialise */
+ result =0;
+
+/* Obtain a pointer to the FrameSet's current Frame and then invoke the
+ method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( (AstFrameSet *) this_frame, AST__CURRENT );
+ result = astLineCrossing( fr, l1, l2, cross );
+ fr = astAnnul( fr );
+
+/* Return the result. */
+ return result;
+}
+
+static AstLineDef *LineDef( AstFrame *this_frame, const double start[2],
+ const double end[2], int *status ) {
+/*
+* Name:
+* LineDef
+
+* Purpose:
+* Creates a structure describing a line segment in a 2D Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstLineDef *LineDef( AstFrame *this, const double start[2],
+* const double end[2], int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astLineDef
+* method inherited from the Frame class).
+
+* Description:
+* This function creates a structure containing information describing a
+* given line segment within the supplied 2D Frame. This may include
+* information which allows other methods such as astLineCrossing to
+* function more efficiently. Thus the returned structure acts as a
+* cache to store intermediate values used by these other methods.
+
+* Parameters:
+* this
+* Pointer to the Frame. Must have 2 axes.
+* start
+* An array of 2 doubles marking the start of the line segment.
+* end
+* An array of 2 doubles marking the end of the line segment.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the memory structure containing the description of the
+* line. This structure should be freed using astFree when no longer
+* needed. A NULL pointer is returned (without error) if any of the
+* supplied axis values are AST__BAD.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstLineDef *result; /* Returned value */
+
+/* Initialise */
+ result = NULL;
+
+/* Obtain a pointer to the FrameSet's current Frame and then invoke the
+ method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( (AstFrameSet *) this_frame, AST__CURRENT );
+ result = astLineDef( fr, start, end );
+ fr = astAnnul( fr );
+
+/* Return the result. */
+ return result;
+}
+
+static void LineOffset( AstFrame *this_frame, AstLineDef *line, double par,
+ double prp, double point[2], int *status ){
+/*
+* Name:
+* LineOffset
+
+* Purpose:
+* Find a position close to a line.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* void LineOffset( AstFrame *this, AstLineDef *line, double par,
+* double prp, double point[2], int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astLineOffset
+* method inherited from the Frame class).
+
+* Description:
+* This function returns a position formed by moving a given distance along
+* the supplied line, and then a given distance away from the supplied line.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* line
+* Pointer to the structure defining the line.
+* par
+* The distance to move along the line from the start towards the end.
+* prp
+* The distance to move at right angles to the line. Positive
+* values result in movement to the left of the line, as seen from
+* the observer, when moving from start towards the end.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - The pointer supplied for "line" should have been created using the
+* astLineDef method. This structure contains cached information about the
+* line which improves the efficiency of this method when many repeated
+* calls are made. An error will be reported if the structure does not
+* refer to the Frame specified by "this".
+*/
+
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+
+/* Obtain a pointer to the FrameSet's current Frame and then invoke the
+ method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( (AstFrameSet *) this_frame, AST__CURRENT );
+ astLineOffset( fr, line, par, prp, point );
+ fr = astAnnul( fr );
+}
+
+static const char *GetAllVariants( AstFrameSet *this, int *status ) {
+/*
+* Name:
+* GetAllVariants
+
+* Purpose:
+* Get a pointer to a list of the variant Mappings for the current Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* const char *getAllVariants( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet member function.
+
+* Description:
+* This function returns a space separated list of names for all the
+* variant Mappings associated with the current Frame. See attribute
+* "Variant". If the current Frame has no variant Mappings, the return
+* value contains just the Domain name of the current Frame in the
+* supplied FrameSet.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+
+* Returned Value:
+* A pointer to a null-terminated string containing the list.
+
+* Notes:
+* - The returned string pointer may point at memory allocated
+* within the FrameSet, or at static memory. The contents of the
+* string may be over-written or the pointer may become invalid
+* following a further invocation of the same function or any
+* modification of the Frame. A copy of the string should
+* therefore be made if necessary.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS
+ AstFrame *frm;
+ AstFrame *vfrm;
+ AstFrameSet *vfs;
+ const char *dom;
+ const char *result;
+ int ifrm;
+ int nc;
+ int icur;
+ int nfrm;
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS( this );
+
+/* Get the one-based index of the Frame that defines the available
+ variant Mappings. */
+ icur = GetVarFrm( this, astGetCurrent( this ), status );
+
+/* Get the variants FrameSet from the Frame selected above. */
+ frm = astGetFrame( this, icur );
+ vfs = astGetFrameVariants( frm );
+
+/* If the Frame does not have a variants FrameSet, just return the DOmain
+ name from the current Frame. */
+ if( !vfs ) {
+ result = astGetDomain( this );
+
+/* If a variants FrameSet was found, form a space sperated list of the
+ Domain names in the FrameSet, stored in the static "getallvariants_buff"
+ string. */
+ } else if( astOK ){
+ nc = 0;
+
+ nfrm = astGetNframe( vfs );
+ for( ifrm = 0; ifrm < nfrm; ifrm++ ) {
+ vfrm = astGetFrame( vfs, ifrm + 1 );
+ dom = astGetDomain( vfrm );
+ if( astOK ){
+ if( ( nc + strlen(dom) + 1 ) < GETALLVARIANTS_BUFF_LEN ) {
+ nc += sprintf( getallvariants_buff + nc, "%s ", dom );
+ } else {
+ astError( AST__INTER, "astGetAllVariants(%s): Buffer "
+ "overflow - too many variants.", status,
+ astGetClass(this) );
+ }
+ }
+ vfrm = astAnnul( vfrm );
+ }
+
+/* Remove the final space. */
+ getallvariants_buff[ nc - 1 ] = 0;
+
+/* Return a pointer to the buffer. */
+ result = getallvariants_buff;
+
+/* Annul the pointer to the variants FrameSet. */
+ vfs = astAnnul( vfs );
+ }
+
+/* Free the pointer to the current Frame. */
+ frm = astAnnul( frm );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+#if defined(THREAD_SAFE)
+static int ManageLock( AstObject *this_object, int mode, int extra,
+ AstObject **fail, int *status ) {
+/*
+* Name:
+* ManageLock
+
+* Purpose:
+* Manage the thread lock on an Object.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "object.h"
+* AstObject *ManageLock( AstObject *this, int mode, int extra,
+* AstObject **fail, int *status )
+
+* Class Membership:
+* FrameSet 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: */
+ AstFrameSet *this; /* Pointer to FrameSet structure */
+ int i; /* Loop count */
+ int result; /* Returned status value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the supplied pointer is not NULL. */
+ if( !this_object ) return result;
+
+/* Obtain a pointers to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* Invoke the ManageLock method inherited from the parent class. */
+ if( !result ) result = (*parent_managelock)( this_object, mode, extra,
+ fail, status );
+
+/* Invoke the astManageLock method on any Objects contained within
+ the supplied Object. */
+ for( i = 0; i < this->nframe; i++ ) {
+ if( !result ) result = astManageLock( this->frame[ i ], mode,
+ extra, fail );
+ }
+
+ for ( i = 0; i < this->nnode - 1; i++ ) {
+ if( !result ) result = astManageLock( this->map[ i ], mode, extra,
+ fail );
+ }
+
+ return result;
+
+}
+#endif
+
+static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){
+/*
+* Name:
+* MapSplit
+
+* Purpose:
+* Create a Mapping representing a subset of the inputs of an existing
+* FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status )
+
+* Class Membership:
+* FrameSet method (over-rides the protected astMapSplit method
+* inherited from the Mapping class).
+
+* Description:
+* This function creates a new Mapping by picking specified inputs from
+* an existing FrameSet. This is only possible if the specified inputs
+* correspond to some subset of the FrameSet outputs. That is, there
+* must exist a subset of the FrameSet outputs for which each output
+* depends only on the selected FrameSet inputs, and not on any of the
+* inputs which have not been selected. If this condition is not met
+* by the supplied FrameSet, then a NULL Mapping is returned.
+
+* Parameters:
+* this
+* Pointer to the FrameSet to be split (the FrameSet is not actually
+* modified by this function).
+* nin
+* The number of inputs to pick from "this".
+* in
+* Pointer to an array of indices (zero based) for the inputs which
+* are to be picked. This array should have "nin" elements. If "Nin"
+* is the number of inputs of the supplied FrameSet, then each element
+* should have a value in the range zero to Nin-1.
+* map
+* Address of a location at which to return a pointer to the new
+* Mapping. This Mapping will have "nin" inputs (the number of
+* outputs may be different to "nin"). A NULL pointer will be
+* returned if the supplied FrameSet has no subset of outputs which
+* depend only on the selected inputs.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to a dynamically allocated array of ints. The number of
+* elements in this array will equal the number of outputs for the
+* returned Mapping. Each element will hold the index of the
+* corresponding output in the supplied FrameSet. The array should be
+* freed using astFree when no longer needed. A NULL pointer will
+* be returned if no output Mapping can be created.
+
+* Notes:
+* - If this function is invoked with the global error status set,
+* or if it should fail for any reason, then NULL values will be
+* returned as the function value and for the "map" pointer.
+*/
+
+/* Local Variables: */
+ AstMapping *bcmap; /* Base->current Mapping */
+ int *result; /* Returned pointer */
+
+/* Initialise */
+ result = NULL;
+ *map = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get the Mapping from base to current Frame and try to split it. */
+ bcmap = astGetMapping( (AstFrameSet *) this_map, AST__BASE, AST__CURRENT );
+ result = astMapSplit( bcmap, nin, in, map );
+ bcmap = astAnnul( bcmap );
+
+/* Free returned resources if an error has occurred. */
+ if( !astOK ) {
+ result = astFree( result );
+ *map = astAnnul( *map );
+ }
+
+/* Return the list of output indices. */
+ return result;
+}
+
+static int Match( AstFrame *this_frame, AstFrame *target, int matchsub,
+ int **template_axes, int **target_axes,
+ AstMapping **map, AstFrame **result, int *status ) {
+/*
+* Name:
+* Match
+
+* Purpose:
+* Determine if conversion is possible between two coordinate systems.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int Match( AstFrame *template, AstFrame *target, int matchsub,
+* int **template_axes, int **target_axes,
+* AstMapping **map, AstFrame **result, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astMatch
+* method inherited from the Frame class).
+
+* Description:
+* This function matches the current Frame of a "template" FrameSet
+* to a "target" frame and determines whether it is possible to
+* convert coordinates between them. If it is, a Mapping that
+* performs the transformation is returned along with a new Frame
+* that describes the coordinate system that results when this
+* Mapping is applied to the current Frame of the target
+* FrameSet. In addition, information is returned to allow the axes
+* in this "result" Frame to be associated with the corresponding
+* axes in the target and template Frames from which they are
+* derived.
+
+* Parameters:
+* template
+* Pointer to the template FrameSet, whose current Frame
+* describes the coordinate system (or set of possible
+* coordinate systems) into which we wish to convert our
+* coordinates.
+* target
+* Pointer to the target Frame. This describes the coordinate
+* system in which we already have coordinates.
+* matchsub
+* If zero then a match only occurs if the template is of the same
+* class as the target, or of a more specialised class. If non-zero
+* then a match can occur even if this is not the case (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 index of the axis in the
+* template FrameSet's current Frame from which it is
+* derived. If it is not derived from any template FrameSet
+* axis, a value of -1 will be returned instead.
+* target_axes
+* Address of a location where a pointer to int will be returned
+* if the requested coordinate conversion is possible. This
+* pointer will point at a dynamically allocated array of
+* integers with one element for each axis of the "result" Frame
+* (see below). It must be freed by the caller (using astFree)
+* when no longer required.
+*
+* For each axis in the result Frame, the corresponding element
+* of this array will return the index of the target Frame axis
+* from which it is derived. If it is not derived from any
+* target Frame axis, a value of -1 will be returned instead.
+* map
+* Address of a location where a pointer to a new Mapping will
+* be returned if the requested coordinate conversion is
+* possible. If returned, the forward transformation of this
+* Mapping may be used to convert coordinates between the target
+* Frame and the result Frame (see below) and the inverse
+* transformation will convert in the opposite direction.
+* result
+* Address of a location where a pointer to a new Frame will be
+* returned if the requested coordinate conversion is
+* possible. If returned, this Frame describes the coordinate
+* system that results from applying the returned Mapping
+* (above) to the "target" coordinate system. In general, this
+* Frame will combine attributes from (and will therefore be
+* more specific than) both the target Frame and the current
+* Frame of the template FrameSet. In particular, when the
+* template allows the possibility of transformaing to any one
+* of a set of alternative coordinate systems, the "result"
+* Frame will indicate which of the alternatives was used.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A non-zero value is returned if the requested coordinate
+* conversion is possible. Otherwise zero is returned (this will
+* not in itself result in an error condition).
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to FrameSet's current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int match; /* Result to be returned */
+
+/* Initialise the returned values. */
+ *template_axes = NULL;
+ *target_axes = NULL;
+ *map = NULL;
+ *result = NULL;
+ match = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return match;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame. */
+ fr = astGetFrame( this, AST__CURRENT );
+
+/* Invoke the astMatch method for this Frame. */
+ match =astMatch( fr, target, matchsub, template_axes, target_axes,
+ map, result );
+
+/* Annul the Frame pointer. */
+ fr = astAnnul( fr );
+
+/* If an error occurred, clean up by freeing any allocated memory,
+ annulling returned objects and clearing the returned result. */
+ 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 MatchAxes( AstFrame *frm1_frame, AstFrame *frm2, int *axes,
+ int *status ) {
+/*
+* Name:
+* MatchAxes
+
+* Purpose:
+* Find any corresponding axes in two Frames.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void MatchAxes( AstFrame *frm1, AstFrame *frm2, int *axes )
+* int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astMatchAxes
+* method inherited from the Frame class).
+
+* Description:
+* This function looks for corresponding axes within two supplied
+* Frames. An array of integers is returned that contains an element
+* for each axis in the second supplied Frame. An element in this array
+* will be set to zero if the associated axis within the second Frame
+* has no corresponding axis within the first Frame. Otherwise, it
+* will be set to the index (a non-zero positive integer) of the
+* corresponding axis within the first supplied Frame.
+
+* Parameters:
+* frm1
+* Pointer to the first Frame.
+* frm2
+* Pointer to the second Frame.
+* axes
+* Pointer to an
+* integer array in which to return the indices of the axes (within
+* the second Frame) that correspond to each axis within the first
+* Frame. Axis indices start at 1. A value of zero will be stored
+* in the returned array for each axis in the first Frame that has
+* no corresponding axis in the second Frame.
+*
+* The number of elements in this array must be greater than or
+* equal to the number of axes in the first Frame.
+* status
+* Pointer to inherited status value.
+
+* Notes:
+* - Corresponding axes are identified by the fact that a Mapping
+* can be found between them using astFindFrame or astConvert. Thus,
+* "corresponding axes" are not necessarily identical. For instance,
+* SkyFrame axes in two Frames will match even if they describe
+* different celestial coordinate systems
+*/
+
+/* Local Variables: */
+ AstFrame *frm1;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the current Frame in the FrameSet. */
+ frm1 = astGetFrame( (AstFrameSet *) frm1_frame, AST__CURRENT );
+
+/* Invoke the astMatchAxesX on the second Frame. */
+ astMatchAxesX( frm2, frm1, axes );
+
+/* Free resources */
+ frm1 = astAnnul( frm1 );
+}
+
+static void MatchAxesX( AstFrame *frm2_frame, AstFrame *frm1, int *axes,
+ int *status ) {
+/*
+* Name:
+* MatchAxesX
+
+* Purpose:
+* Find any corresponding axes in two Frames.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void MatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes )
+* int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astMatchAxesX
+* method inherited from the Frame class).
+
+* This function looks for corresponding axes within two supplied
+* Frames. An array of integers is returned that contains an element
+* for each axis in the second supplied Frame. An element in this array
+* will be set to zero if the associated axis within the second Frame
+* has no corresponding axis within the first Frame. Otherwise, it
+* will be set to the index (a non-zero positive integer) of the
+* corresponding axis within the first supplied Frame.
+
+* Parameters:
+* frm2
+* Pointer to the second Frame.
+* frm1
+* Pointer to the first Frame.
+* axes
+* Pointer to an integer array in which to return the indices of
+* the axes (within the first Frame) that correspond to each axis
+* within the second Frame. Axis indices start at 1. A value of zero
+* will be stored in the returned array for each axis in the second
+* Frame that has no corresponding axis in the first Frame.
+*
+* The number of elements in this array must be greater than or
+* equal to the number of axes in the second Frame.
+* status
+* Pointer to inherited status value.
+
+* Notes:
+* - Corresponding axes are identified by the fact that a Mapping
+* can be found between them using astFindFrame or astConvert. Thus,
+* "corresponding axes" are not necessarily identical. For instance,
+* SkyFrame axes in two Frames will match even if they describe
+* different celestial coordinate systems
+*/
+
+/* Local Variables: */
+ AstFrame *frm2;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the current Frame in the FrameSet. */
+ frm2 = astGetFrame( (AstFrameSet *) frm2_frame, AST__CURRENT );
+
+/* Invoke the astMatchAxesX on the current Frame. */
+ astMatchAxesX( frm2, frm1, axes );
+
+/* Free resources */
+ frm2 = astAnnul( frm2 );
+}
+
+static void MirrorVariants( AstFrameSet *this, int iframe, int *status ) {
+/*
+*++
+* Name:
+c astMirrorVariants
+f AST_MIRRORVARIANTS
+
+* Purpose:
+* Make the current Frame mirror the variant Mappings in another Frame.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frameset.h"
+c void astMirrorVariants( AstFrameSet *this, int iframe )
+f CALL AST_MIRRORVARIANTS( THIS, IFRAME, STATUS )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+c This function
+f This routine
+* indicates that all access to the Variant attribute of the current
+* Frame should should be forwarded to some other nominated Frame in
+* the FrameSet. For instance, if a value is set subsequently for the
+* Variant attribute of the current Frame, the current Frame will be left
+* unchanged and the setting is instead applied to the nominated Frame.
+* Likewise, if the value of the Variant attribute is requested, the
+* value returned is the value stored for the nominated Frame rather
+* than the current Frame itself.
+*
+* This provides a mechanism for propagating the effects of variant
+* Mappings around a FrameSet. If a new Frame is added to a FrameSet
+* by connecting it to an pre-existing Frame that has two or more variant
+* Mappings, then it may be appropriate to set the new Frame so that it
+* mirrors the variants Mappings of the pre-existing Frame. If this is
+* done, then it will be possible to select a specific variant Mapping
+* using either the pre-existing Frame or the new Frame.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the FrameSet.
+c iframe
+f IFRAME = INTEGER (Given)
+* The index of the Frame within the FrameSet which is to be
+* mirrored by the current Frame. This value should lie in the range
+* from 1 to the number of Frames in the FrameSet (as given by its
+* Nframe attribute). If AST__NOFRAME is supplied (or the current
+* Frame is specified), then any mirroring established by a previous
+* call to this
+c function
+f routine
+* is disabled.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - Mirrors can be chained. That is, if Frame B is set to be a mirror
+* of Frame A, and Frame C is set to be a mirror of Frame B, then
+* Frame C will act as a mirror of Frame A.
+* - Variant Mappings cannot be added to the current Frame if it is
+* mirroring another Frame. So calls to the
+c astAddVariant function
+f AST_ADDVARIANT routine
+* will cause an error to be reported if the current Frame is
+* mirroring another Frame.
+* - A value of AST__BASE may be given for the
+c "iframe" parameter
+f IFRAME argument
+* to specify the base Frame.
+* - Any variant Mappings explicitly added to the current Frame using
+c astAddVariant
+f AST_ADDVARIANT
+* will be ignored if the current Frame is mirroring another Frame.
+
+*--
+*/
+
+/* Local Variables: */
+ int icur;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get the current Frame index. */
+ icur = astGetCurrent( this );
+
+/* If AST__NOFRAME, disable any mirroring. */
+ if( iframe == AST__NOFRAME ) {
+ this->varfrm[ icur - 1 ] = 0;
+
+/* Otherwise, validate and translate the Frame index supplied. */
+ } else {
+ iframe = astValidateFrameIndex( this, iframe, "astMirrorVariants" );
+
+/* If the current Frame has been specified, disable any mirroring. */
+ if( iframe == icur ) {
+ this->varfrm[ icur - 1 ] = 0;
+
+/* Otherwise, store the one-based variants frame index. */
+ } else {
+ this->varfrm[ icur - 1 ] = iframe;
+ }
+ }
+}
+
+static void Norm( AstFrame *this_frame, double value[], int *status ) {
+/*
+* Name:
+* Norm
+
+* Purpose:
+* Normalise a set of FrameSet coordinates.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void Norm( AstAxis *this, double value[], int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astNorm method
+* inherited from the Frame class).
+
+* Description:
+* This function converts a set of coordinate values for the
+* current Frame of a FrameSet, which might potentially be
+* unsuitable for display to a user (for instance, may lie outside
+* the expected range of values) into a set of acceptable
+* alternative values suitable for display.
+*
+* Typically, for Frames whose axes represent cyclic values (such
+* as angles or positions on the sky), this function wraps an
+* arbitrary set of coordinates, so that they lie within the first
+* cycle (say zero to 2*pi or -pi/2 to +pi/2). For Frames with
+* ordinary linear axes, without constraints, this function will
+* typically return the original coordinate values unchanged.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* value
+* An array of double, with one element for each FrameSet axis.
+* This should contain the initial set of coordinate values,
+* which will be modified in place.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to the current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astNorm method to obtain the new values. Annul the Frame
+ pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astNorm( fr, value );
+ fr = astAnnul( fr );
+}
+
+static void NormBox( AstFrame *this_frame, double lbnd[], double ubnd[],
+ AstMapping *reg, int *status ) {
+/*
+* Name:
+* NormBox
+
+* Purpose:
+* Extend a box to include effect of any singularities in the Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void astNormBox( AstFrame *this, double lbnd[], double ubnd[],
+* AstMapping *reg, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astNormBox method inherited
+* from the Frame class).
+
+* Description:
+* This function modifies a supplied box to include the effect of any
+* singularities in the co-ordinate system represented by the Frame.
+* For a normal Cartesian coordinate system, the box will be returned
+* unchanged. Other classes of Frame may do other things. For instance,
+* a SkyFrame will check to see if the box contains either the north
+* or south pole and extend the box appropriately.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* lbnd
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). Initially, this should contain a set of
+* lower axis bounds for the box. They will be modified on exit
+* to include the effect of any singularities within the box.
+* ubnd
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). Initially, this should contain a set of
+* upper axis bounds for the box. They will be modified on exit
+* to include the effect of any singularities within the box.
+* reg
+* A Mapping which should be used to test if any singular points are
+* inside or outside the box. The Mapping should leave an input
+* position unchanged if the point is inside the box, and should
+* set all bad if the point is outside the box.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to the current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astNormBox method to obtain the new values. Annul the Frame
+ pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astNormBox( fr, lbnd, ubnd, reg );
+ fr = astAnnul( fr );
+}
+
+static void Offset( AstFrame *this_frame, const double point1[],
+ const double point2[], double offset, double point3[], int *status ) {
+/*
+* Name:
+* Offset
+
+* Purpose:
+* Calculate an offset along a geodesic curve.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* void Offset( AstFrame *this,
+* const double point1[], const double point2[],
+* double offset, double point3[], int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astOffset
+* method inherited from the Frame class).
+
+* Description:
+* This function finds the FrameSet coordinate values of a point
+* which is offset a specified distance along the geodesic curve
+* between two other points.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* point1
+* An array of double, with one element for each FrameSet 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 FrameSet 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 FrameSet axis
+* in which the coordinates of the required point will be
+* returned.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - The geodesic curve used by this function is the path of
+* shortest distance between two points, as defined by the
+* astDistance function.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value.
+* - "Bad" coordinate values will also be returned if the two
+* points supplied are coincident (or otherwise fail to uniquely
+* specify a geodesic curve) but the requested offset is non-zero.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astOffset method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astOffset( fr, point1, point2, offset, point3 );
+ fr = astAnnul( fr );
+}
+
+static double Offset2( AstFrame *this_frame, const double point1[2],
+ double angle, double offset, double point2[2], int *status ){
+/*
+* Name:
+* Offset2
+
+* Purpose:
+* Calculate an offset along a geodesic curve in a 2D Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* double Offset2( AstFrame *this, const double point1[2], double angle,
+* double offset, double point2[2], int *status );
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astOffset2
+* method inherited from the Frame class).
+
+* Description:
+* This function finds the Frame coordinate values of a point which
+* is offset a specified distance along the geodesic curve at a
+* given angle from a specified starting point. It can only be
+* used with 2-dimensional Frames.
+*
+* For example, in a basic Frame, this offset will be along the
+* straight line joining two points. For a more specialised Frame
+* describing a sky coordinate system, however, it would be along
+* the great circle passing through two sky positions.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* point1
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). This should contain the coordinates of the
+* point marking the start of the geodesic curve.
+* angle
+* The angle (in radians) from the positive direction of the second
+* axis, to the direction of the required position, as seen from
+* the starting position. Positive rotation is in the sense of
+* rotation from the positive direction of axis 2 to the positive
+* direction of axis 1.
+* offset
+* The required offset from the first point along the geodesic
+* curve. If this is positive, it will be in the direction of the
+* given angle. If it is negative, it will be in the opposite
+* direction.
+* point2
+* An array of double, with one element for each Frame axis
+* in which the coordinates of the required point will be returned.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The direction of the geodesic curve at the end point. That is, the
+* angle (in radians) between the positive direction of the second
+* axis and the continuation of the geodesic curve at the requested
+* end point. Positive rotation is in the sense of rotation from
+* the positive direction of axis 2 to the positive direction of axis 1.
+
+* Notes:
+* - The geodesic curve used by this function is the path of
+* shortest distance between two points, as defined by the
+* astDistance function.
+* - An error will be reported if the Frame is not 2-dimensional.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double result; /* Value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astOffset2 method for this Frame. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astOffset2( fr, point1, angle, offset, point2 );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = AST__BAD;
+
+/* Return the result. */
+ return result;
+}
+
+static void Overlay( AstFrame *template_frame, const int *template_axes,
+ AstFrame *result, int *status ) {
+/*
+* Name:
+* Overlay
+
+* Purpose:
+* Overlay the attributes of a template FrameSet on to another Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void Overlay( AstFrame *template, const int *template_axes,
+* AstFrame *result, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astOverlay
+* method inherited from the Frame class).
+
+* Description:
+* This function overlays attributes from the current Frame of a
+* FrameSet 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 FrameSet, 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 FrameSet 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: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *template; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ template = (AstFrameSet *) template_frame;
+
+/* Obtain a pointer to the current Frame and invoke its astOverlay
+ method to overlay its attributes. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( template, AST__CURRENT );
+ astOverlay( fr, template_axes, result );
+ fr = astAnnul( fr );
+}
+
+static void PermAxes( AstFrame *this_frame, const int perm[], int *status ) {
+/*
+* Name:
+* PermAxes
+
+* Purpose:
+* Permute the order of a FrameSet's axes.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void PermAxes( AstFrame *this, const int perm[], int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astPermAxes method
+* inherited from the Frame class).
+
+* Description:
+* This function permutes the order in which the axes in the
+* current Frame of a FrameSet occur.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* perm
+* An array of int (with one element for each axis of the
+* FrameSet's current Frame) which lists the axes in their new
+* order. Each element of this array should be a (zero-based)
+* axis index identifying the axes according to their old
+* (un-permuted) order.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - Only genuine permutations of the axis order are permitted, so
+* each axis must be referenced exactly once in the "perm" array.
+* - If more than one axis permutation is applied to the same Frame
+* in a FrameSet, the effects are cumulative.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ AstPermMap *map; /* Pointer to axis permutation Mapping */
+ int *invperm; /* Pointer to inverse permutation array */
+ int axis; /* Loop counter for axes */
+ int naxes; /* Number of FrameSet axes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the permutation array, to check that it describes a
+ genuine permutation. */
+ astCheckPerm( this, perm, "astPermAxes" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astPermAxes method to permute its axes. Annul the Frame
+ pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astPermAxes( fr, perm );
+ fr = astAnnul( fr );
+
+/* Obtain the number of axes in the FrameSet's current Frame and allocate
+ memory to hold an inverse permutation array. */
+ naxes = astGetNaxes( this );
+ invperm = astMalloc( sizeof( int ) * (size_t) naxes );
+
+/* Fill the inverse permutation array with values that will invert the
+ axis permutation supplied. */
+ if ( astOK ) {
+ for ( axis = 0; axis < naxes; axis++ ) invperm[ perm[ axis ] ] = axis;
+
+/* Create a PermMap that will permute coordinate values in the same way as
+ the current Frame's axes have been permuted. */
+ map = astPermMap( naxes, invperm, naxes, perm, NULL, "", status );
+
+/* Modify the Frame's relationship to the rest of the Frames in the
+ FrameSet so that the correct coordinate values remain associated
+ with the permuted axes. */
+ astRemapFrame( this, AST__CURRENT, map );
+
+/* Annul the PermMap and free the inverse permutation array. */
+ map = astAnnul( map );
+ }
+ invperm = astFree( invperm );
+}
+
+static AstFrame *PickAxes( AstFrame *this_frame, int naxes, const int axes[],
+ AstMapping **map, int *status ) {
+/*
+* Name:
+* PickAxes
+
+* Purpose:
+* Create a new Frame by picking axes from a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstFrame *PickAxes( AstFrame *this, int naxes, const int axes[],
+* AstMapping **map, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astPickAxes protected
+* method inherited from the Frame class).
+
+* Description:
+* This function creates a new Frame whose axes are copies of axes
+* picked from the current Frame of an existing FrameSet. Other
+* Frame attributes are also copied from this current Frame to the
+* new Frame. Zero or more of the original axes may be picked in
+* any order, but each can be used only once. Additional axes (with
+* default characteristics) may be included in the new Frame if
+* required.
+*
+* Optionally, a Mapping that converts between the original Frame's
+* axes and those of the new Frame may also be returned.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* naxes
+* The number of axes required in the new Frame.
+* axes
+* Pointer to an array of int with naxes elements. This should
+* contain (zero based) axis indices specifying the axes which
+* are to be included in the new Frame, in the order
+* required. Each axis index may occur only once.
+*
+* If additional (default) axes are also to be included, the
+* corresponding elements of this array should be set to -1.
+* map
+* Address of a location to receive a pointer to a new
+* Mapping. This will be a PermMap (or a UnitMap as a special
+* case) that describes the axis permutation that has taken
+* place between the current Frame of the FrameSet and the new
+* Frame. The forward transformation will convert from the
+* original FrameSet's axes to the new one's, and vice versa.
+*
+* If this Mapping is not required, a NULL value may be supplied
+* for this parameter.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the new Frame.
+
+* Notes:
+* - The class of object returned may differ from that of the
+* original current Frame, depending on which axes are
+* selected. For example, if a single axis is picked from a
+* SkyFrame (which always has two axes), the resulting Frame cannot
+* be a valid SkyFrame, so will revert to the parent class (Frame)
+* instead.
+* - The new Frame contains a deep copy of all the data selected
+* from the original current Frame. Modifying the new Frame will
+* therefore not affect the FrameSet or the Frames it contains.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrame *frame; /* Pointer to Frame to be returned */
+ AstFrameSet *this; /* Pointer to FrameSet structure */
+
+/* Initialise the returned pointers. */
+ if ( map ) *map = NULL;
+ frame = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return frame;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Check that a valid set of axes is being selected . */
+ astValidateAxisSelection( this, naxes, axes, "astPickAxes" );
+
+/* Obtain a pointer to the FrameSet's current Frame and use its
+ astPickAxes method to obtain the required new Frame and
+ Mapping. Annul the current Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ frame = astPickAxes( fr, naxes, axes, map );
+ fr = astAnnul( fr );
+
+/* If an error occurred, annul the Mapping pointer (if requested) and
+ the new Frame pointer. */
+ if ( !astOK ) {
+ if ( map ) *map = astAnnul( *map );
+ frame = astAnnul( frame );
+ }
+
+/* Return the pointer to the new Frame. */
+ return frame;
+}
+
+static void 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 "frameset.h"
+* void PrimaryFrame( AstFrame *this, int axis1, AstFrame **frame,
+* int *axis2, int *status )
+
+* Class Membership:
+* FrameSet 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 axis of the current Frame of
+* a FrameSet, when this current Frame may be a compound Frame
+* composed of more than one simpler one.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* axis1
+* An axis index (zero-based) identifying the axis of the
+* FrameSet's current Frame 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 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: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Initialise the returned values. */
+ *frame = NULL;
+ *axis2 = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index supplied. */
+ (void) astValidateAxis( this, axis1, 1, "astPrimaryFrame" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke its
+ astPrimaryFrame method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astPrimaryFrame( fr, axis1, frame, axis2 );
+ fr = astAnnul( fr );
+
+/* If an error occurred, annul the returned object and clear the
+ returned axis value. */
+ if ( !astOK ) {
+ *frame = astAnnul( *frame );
+ *axis2 = 0;
+ }
+}
+
+static double Rate( AstMapping *this_mapping, double *at, int ax1, int ax2, int *status ){
+/*
+* Name:
+* Rate
+
+* Purpose:
+* Calculate the rate of change of a Mapping output.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* result = Rate( AstMapping *this, double *at, int ax1, int ax2, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astRate method
+* inherited from the Frame class).
+
+* This function evaluates the rate of change of a specified output of
+* the supplied Mapping with respect to a specified input, at a
+* specified input position.
+*
+* The result is estimated by interpolating the function using a
+* fourth order polynomial in the neighbourhood of the specified
+* position. The size of the neighbourhood used is chosen to minimise
+* the RMS residual per unit length between the interpolating
+* polynomial and the supplied Mapping function.
+
+* Parameters:
+* this
+* Pointer to the Mapping to be applied.
+* at
+* The address of an array holding the axis values at the position
+* at which the rate of change is to be evaluated. The number of
+* elements in this array should equal the number of inputs to the
+* Mapping.
+* ax1
+* The index of the Mapping output for which the rate of change is to
+* be found (output numbering starts at 0 for the first output).
+* ax2
+* The index of the Mapping input which is to be varied in order to
+* find the rate of change (input numbering starts at 0 for the first
+* input).
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* astRate()
+* The rate of change of Mapping output "ax1" with respect to input
+* "ax2", evaluated at "at", or AST__BAD if the value cannot be
+* calculated.
+
+* 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: */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ AstMapping *map; /* Pointer to the base->current Mapping */
+ double result; /* Returned rate of change */
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_mapping;
+
+/* Obtain the Mapping between the base and current Frames in the
+ FrameSet (note this takes account of whether the FrameSet has been
+ inverted). */
+ map = astGetMapping( this, AST__BASE, AST__CURRENT );
+
+/* Invoke the astRate method on the Mapping. */
+ result = astRate( map, at, ax1, ax2 );
+
+/* Annul the Mapping pointer. */
+ map = astAnnul( map );
+
+/* Return a pointer to the output PointSet. */
+ return result;
+}
+
+static void RecordIntegrity( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* RecordIntegrity
+
+* Purpose:
+* Record the current integrity state of a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void RecordIntegrity( AstFrameSet *this, int *status )
+
+* Class Membership:
+* FrameSet member function.
+
+* Description:
+* This function makes a record of the current integrity state of a
+* FrameSet by taking a copy of its current Frame (it stores a
+* pointer to this copy in a static variable). If the current Frame
+* is subsequently modified, the RestoreIntegrity function can then
+* attempt to restore the FrameSet's integrity to this recorded
+* state by appropriately remapping its current Frame.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+*-
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstFrame *current; /* Pointer to current Frame */
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* Initialise the record of the FrameSet's integrity. */
+ integrity_frame = NULL;
+ integrity_lost = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet's current Frame. */
+ current = astGetFrame( this, AST__CURRENT );
+
+/* Make a copy of this Frame, storing its pointer. */
+ integrity_frame = astCopy( current );
+
+/* Annul the current Frame pointer. */
+ current = astAnnul( current );
+}
+
+static void RemapFrame( AstFrameSet *this, int iframe, AstMapping *map, int *status ) {
+/*
+*++
+* Name:
+c astRemapFrame
+f AST_REMAPFRAME
+
+* Purpose:
+* Modify a Frame's relationship to other Frames in a FrameSet.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frameset.h"
+c void astRemapFrame( AstFrameSet *this, int iframe, AstMapping *map )
+f CALL AST_REMAPFRAME( THIS, IFRAME, MAP, STATUS )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+c This function modifies the relationship (i.e. Mapping) between a
+f This routine modifies the relationship (i.e. Mapping) between a
+* specified Frame in a FrameSet and the other Frames in that
+* FrameSet.
+*
+* Typically, this might be required if the FrameSet has been used
+* to calibrate (say) an image, and that image is re-binned. The
+* Frame describing the image will then have undergone a coordinate
+* transformation, and this should be communicated to the associated
+c FrameSet using this function.
+f FrameSet using this routine.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the FrameSet.
+c iframe
+f IFRAME = INTEGER (Given)
+* The index within the FrameSet of the Frame to be modified.
+* This value should lie in the range from 1 to the number of
+* Frames in the FrameSet (as given by its Nframe attribute).
+c map
+f MAP = INTEGER (Given)
+* Pointer to a Mapping whose forward transformation converts
+* coordinate values from the original coordinate system
+* described by the Frame to the new one, and whose inverse
+* transformation converts in the opposite direction.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - A value of AST__BASE or AST__CURRENT may be given for the
+c "iframe" parameter to specify the base Frame or the current
+f IFRAME argument to specify the base Frame or the current
+* Frame respectively.
+* - The relationship between the selected Frame and any other
+c Frame within the FrameSet will be modified by this function,
+f Frame within the FrameSet will be modified by this routine,
+* but the relationship between all other Frames in the FrameSet
+* remains unchanged.
+* - The number of input coordinate values accepted by the Mapping
+* (its Nin attribute) and the number of output coordinate values
+* generated (its Nout attribute) must be equal and must match the
+* number of axes in the Frame being modified.
+* - If a simple change of axis order is required, then the
+c astPermAxes function may provide a more straightforward method
+f AST_PERMAXES routine may provide a more straightforward method
+* of making the required changes to the FrameSet.
+c - This function cannot be used to change the number of Frame
+f - This routine cannot be used to change the number of Frame
+* axes. To achieve this, a new Frame must be added to the FrameSet
+c (astAddFrame) and the original one removed if necessary
+c (astRemoveFrame).
+f (AST_ADDFRAME) and the original one removed if necessary
+f (AST_REMOVEFRAME).
+* - Any variant Mappings associated with the remapped Frame (except
+* for the current variant) will be lost as a consequence of calling this
+* method (see attribute "Variant").
+*--
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to Frame */
+ int icur; /* Index of original current Frame */
+ int naxes; /* Number of Frame axes */
+ int nin; /* Number of Mapping input coordinates */
+ int nout; /* Number of Mapping output coordinates */
+ int varfrm; /* The index of the variants frame */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Validate and translate the Frame index supplied. */
+ iframe = astValidateFrameIndex( this, iframe, "astRemapFrame" );
+
+/* Variant Mappings from a source node to a destination node are stored
+ within the Frame object associated with the destination node. But
+ remapping a Frame causes the Frame to be dissociated from its original
+ node, and associated with a new node, leaving the original node
+ without any Frame in which to store its variant mappings. So we are
+ forced to remove the variant Mappings if the Frame is remapped. We do
+ this by clearing the Variant attribute before the Frame is remapped.
+ This will leave the current variant as the sole Mapping between the
+ original source and destination nodes. However, if the Frame being
+ remapped is just a mirror for another Frame, then we do not need to
+ do this since the Frame being mirrored is not itself being remapped
+ and so can retain its variant mappings. So we temporarily prevent the
+ remapped Frame from acting as a mirror before we clear the Variant
+ attribute. */
+ icur = astGetCurrent( this );
+ astSetCurrent( this, iframe );
+
+ varfrm = this->varfrm[ iframe - 1 ];
+ this->varfrm[ iframe - 1 ] = 0;
+
+ astClearVariant( this );
+
+ this->varfrm[ iframe - 1 ] = varfrm;
+ astSetCurrent( this, icur );
+
+/* Obtain the number of input and output coordinates per point for the
+ Mapping supplied. */
+ nin = astGetNin( map );
+ nout = astGetNout( map );
+
+/* Obtain a pointer to the specified Frame and determine how many axes
+ it has. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, iframe );
+ naxes = astGetNaxes( fr );
+ fr = astAnnul( fr );
+
+/* Check that the number of input coordinates matches the number of
+ Frame axes and report an error if necessary. */
+ if ( astOK ) {
+ if ( nin != naxes ) {
+ astError( AST__NCPIN, "astRemapFrame(%s): Bad number of %s input "
+ "coordinate values (%d).", status, astGetClass( this ),
+ astGetClass( map ), nin );
+ astError( AST__NCPIN, "The %s given should accept %d coordinate "
+ "value%s for each input point.", status, astGetClass( map ), naxes,
+ ( naxes == 1 ) ? "" : "s" );
+
+/* Similarly, check that the number of output coordinates matches the
+ number of Frame axes. */
+ } else if ( nout != naxes ) {
+ astError( AST__NCPIN, "astRemapFrame(%s): Bad number of %s output "
+ "coordinate values (%d).", status, astGetClass( this ),
+ astGetClass( map ), nout );
+ astError( AST__NCPIN, "The %s given should generate %d "
+ "coordinate value%s for each output point.", status,
+ astGetClass( map ), naxes, ( naxes == 1 ) ? "" : "s" );
+ }
+ }
+
+/* If there is more than one Frame present in the FrameSet, extend the
+ FrameSet arrays to hold a new node. */
+ if ( astOK && ( this->nframe > 1 ) ) {
+ this->map = astGrow( this->map, this->nnode, sizeof( AstMapping * ) );
+ this->link = astGrow( this->link, this->nnode, sizeof( int ) );
+ this->invert = astGrow( this->invert, this->nnode, sizeof( int ) );
+
+/* Clone and store a pointer to the Mapping. */
+ if ( astOK ) {
+ this->map[ this->nnode - 1 ] = astClone( map );
+
+/* Add a new "link" element showing that the new node is derived from
+ that of the old Frame and store the current value of the Invert
+ attribute for the Mapping. */
+ this->link[ this->nnode - 1 ] = this->node[ iframe - 1 ];
+ this->invert[ this->nnode - 1 ] = astGetInvert( map );
+
+/* Increment the node count and associate the modified Frame with the
+ new node. */
+ if ( astOK ) {
+ this->nnode++;
+ this->node[ iframe - 1 ] = this->nnode - 1;
+
+/* Tidy the resulting set of nodes, because the node originally
+ referenced by the Frame may no longer be needed. This also
+ simplifies any compound Mapping which may result if this node is
+ removed. */
+ TidyNodes( this, status );
+ }
+ }
+ }
+}
+
+static void RemoveFrame( AstFrameSet *this, int iframe, int *status ) {
+/*
+*++
+* Name:
+c astRemoveFrame
+f AST_REMOVEFRAME
+
+* Purpose:
+* Remove a Frame from a FrameSet.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frameset.h"
+c void astRemoveFrame( AstFrameSet *this, int iframe )
+f CALL AST_REMOVEFRAME( THIS, IFRAME, STATUS )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+c This function removes a Frame from a FrameSet. All other Frames
+f This routine removes a Frame from a FrameSet. All other Frames
+* in the FrameSet have their indices re-numbered from one (if
+* necessary), but are otherwise unchanged.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the FrameSet.
+c iframe
+f IFRAME = INTEGER (Given)
+* The index within the FrameSet of the Frame to be removed.
+* This value should lie in the range from 1 to the number of
+* Frames in the FrameSet (as given by its Nframe attribute).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - Removing a Frame from a FrameSet does not affect the
+* relationship between other Frames in the FrameSet, even if they
+* originally depended on the Frame being removed.
+* - The number of Frames in a FrameSet cannot be reduced to zero.
+* An error will result if an attempt is made to remove the only
+* remaining Frame.
+* - A value of AST__BASE or AST__CURRENT may be given for the
+c "iframe" parameter to specify the base Frame or the current
+f IFRAME argument to specify the base Frame or the current
+* Frame respectively.
+* - If a FrameSet's base or current Frame is removed, the Base or
+* Current attribute (respectively) of the FrameSet will have its
+* value cleared, so that another Frame will then assume its role
+* by default.
+* - If any other Frame is removed, the base and current Frames
+* will remain the same. To ensure this, the Base and/or Current
+* attributes of the FrameSet will be changed, if necessary, to
+* reflect any change in the indices of these Frames.
+*--
+*/
+
+/* Local Variables: */
+ int ifr; /* Loop counter for Frames */
+ int ii; /* Base/current Frame index */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Validate and translate the Frame index supplied. */
+ iframe = astValidateFrameIndex( this, iframe, "astRemoveFrame" );
+ if ( astOK ) {
+
+/* Reject any attempt to remove the final Frame from the FrameSet. */
+ if ( this->nframe == 1 ) {
+ astError( AST__REMIN, "astRemoveFrame(%s): Invalid attempt to "
+ "remove the only Frame in a %s.", status, astGetClass( this ),
+ astGetClass( this ) );
+
+/* If OK, annul the pointer to the selected Frame. */
+ } else {
+ this->frame[ iframe - 1 ] = astAnnul( this->frame[ iframe - 1 ] );
+
+/* Ensure that the variant Mappings in the Frame being removed are not
+ mirrored by any other Frames in the FrameSet. */
+ RemoveMirrors( this, iframe, status );
+
+/* Any Frames that are mirroring variants in Frames higher than the
+ removed Frame need to have their mirror frame indices decremented. */
+ for ( ifr = 1; ifr <= this->nframe; ifr++ ) {
+ if( this->varfrm[ ifr - 1 ] > iframe ) this->varfrm[ ifr - 1 ]--;
+ }
+
+/* Loop to move all subsequent Frame pointers down in the FrameSet's
+ "frame" array to close the resulting gap. Also move the associated
+ "node" and "varfrm" array contents in the same way. */
+ for ( ifr = iframe; ifr < this->nframe; ifr++ ) {
+ this->frame[ ifr - 1 ] = this->frame[ ifr ];
+ this->node[ ifr - 1 ] = this->node[ ifr ];
+ this->varfrm[ ifr - 1 ] = this->varfrm[ ifr ];
+ }
+ this->frame[ this->nframe - 1 ] = NULL;
+ this->node[ this->nframe - 1 ] = -1;
+ this->varfrm[ this->nframe - 1 ] = 0;
+
+/* Decrement the Frame count. */
+ this->nframe--;
+
+/* Tidy the nodes in the FrameSet. */
+ TidyNodes( this, status );
+
+/* If the Base attribute is set and the removed Frame was the base
+ Frame, then clear the attribute value so that a new base Frame will
+ be selected by default. */
+ if ( astTestBase( this ) ) {
+ ii = astGetBase( this );
+ if ( iframe == ii ) {
+ astClearBase( this );
+
+/* If the index of the removed Frame is smaller than the base Frame
+ index, then decrement the Base attribute so that the same base
+ Frame will be used in future. */
+ } else if ( iframe < ii ) {
+ astSetBase( this, ii - 1 );
+ }
+ }
+
+/* Repeat the above procedure for the current Frame. */
+ if ( astTestCurrent( this ) ) {
+ ii = astGetCurrent( this );
+ if ( iframe == ii ) {
+ astClearCurrent( this );
+ } else if ( iframe < ii ) {
+ astSetCurrent( this, ii - 1 );
+ }
+ }
+ }
+ }
+}
+
+static void RemoveMirrors( AstFrameSet *this, int iframe, int *status ) {
+/*
+* Name:
+* RemoveMirrors
+
+* Purpose:
+* Ensure no other Frames act as mirrors for a specified Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void RemoveMirrors( AstFrameSet *this, int iframe, int *status )
+
+* Class Membership:
+* Private function.
+
+* Description:
+* This function searchs the FrameSet for Frames that are currently
+* acting as mirrors for the variant Mappings in the Frame with index
+* "iframe", and disables mirroring in any found Frames. It should be
+* used when "iframe" has its variant Mappings removed.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* iframe
+* One-based index of a Frame that has had its variant Mappings
+* removed.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ int *frmlist;
+ int ifr;
+ int nfrm;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Iniitalise a list to hold the indices of the FRames that mirror
+ "iframe". */
+ nfrm = 0;
+ frmlist = NULL;
+
+/* Check each Frame in the FrameSet. */
+ for( ifr = 1; ifr <= this->nframe; ifr++ ) {
+
+/* Get the index of the Frame that defines the variant Mappings to use
+ with Frame "ifr". If this is "iframe", then add "ifr" to the list of
+ Frames that need to be "de-mirrored". We cannot "de-mirror" the Frame
+ immediately as doing so may break a chain of mirrors, resulting in the
+ Frames higher up the chain no longer being associated with "iframe". */
+ if( GetVarFrm( this, ifr, status ) == iframe ) {
+ frmlist = astGrow( frmlist, nfrm + 1, sizeof( *frmlist ) );
+ if( astOK ) frmlist[ nfrm++ ] = ifr;
+ }
+ }
+
+/* Loop round all the Frames found above that mirror "iframe". */
+ for( ifr = 0; ifr < nfrm; ifr++ ) {
+
+/* Indicate that the Frame no longer mirrors any other Frame. */
+ this->varfrm[ frmlist[ ifr ] - 1 ] = 0;
+ }
+
+/* Free the list. */
+ frmlist = astFree( frmlist );
+}
+
+static AstMapping *RemoveRegions( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* RemoveRegions
+
+* Purpose:
+* Remove any Regions from a Mapping.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstMapping *RemoveRegions( AstMapping *this, int *status )
+
+* Class Membership:
+* FrameSet method (over-rides the astRemoveRegions method inherited
+* from the Mapping class).
+
+* Description:
+* This function searches the supplied Mapping (which may be a
+* compound Mapping such as a FrameSet) 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 FrameSet), then it is replaced with an equivalent UnitMap
+* in the returned Mapping.
+*
+* The implementation provided by the FrameSet class invokes the
+* astRemoveRegions method on all the component Frames and Mappings,
+* and joins the results together into a new FrameSet.
+
+* Parameters:
+* this
+* Pointer to the original Region.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to the modified mapping.
+
+* Notes:
+* - A NULL pointer value will be returned if this function is
+* invoked with the AST error status set, or if it should fail for
+* any reason.
+*/
+
+/* Local Variables: */
+ AstFrame **newfrms; /* Array of new Frames */
+ AstFrameSet *new; /* Pointer to new FrameSet */
+ AstFrameSet *this; /* Pointer to FrameSet structure */
+ AstMapping **newmaps; /* Array of new Mappings */
+ AstMapping *result; /* Result pointer to return */
+ int changed; /* Has any mapping been changed? */
+ int i; /* Loop count */
+ int nax; /* Number of Frame axes */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the FrameSet. */
+ this = (AstFrameSet *) this_mapping;
+
+/* Allocate arrays to hold the modified Mapping and Frame pointers. */
+ newmaps = astMalloc( sizeof( AstMapping *)*( this->nnode - 1 ) );
+ newfrms = astMalloc( sizeof( AstFrame *)*( this->nframe ) );
+ if( astOK ) {
+
+/* Invoke the astRemoveRegions method on all the component Mappings. */
+ changed = 0;
+ for( i = 0; i < this->nnode - 1; i++ ) {
+ newmaps[ i ] = astRemoveRegions( this->map[ i ] );
+
+/* Note if any Mapping was changed. */
+ if( newmaps[ i ] != this->map[ i ] ) {
+ changed = 1;
+
+/* The implementation of the astRemoveRegions method provided by the
+ Region class returns a Frame rather than a UnitMap. But we need
+ Mappings here, not Frames. So if the new Mapping is a Frame, replace
+ it with an equivalent UnitMap. */
+ if( astIsAFrame( newmaps[ i ] ) ) {
+ nax = astGetNin( newmaps[ i ] );
+ (void) astAnnul( newmaps[ i ] );
+ newmaps[ i ] = (AstMapping *) astUnitMap( nax, " ", status );
+ }
+ }
+ }
+
+/* Invoke the astRemoveRegions method on all the component Frames. */
+ for( i = 0; i < this->nframe; i++ ) {
+ newfrms[ i ] = astRemoveRegions( this->frame[ i ] );
+
+/* Note if any Frame was changed. */
+ if( newfrms[ i ] != this->frame[ i ] ) changed = 1;
+ }
+
+/* If no component was modified, just return a clone of the supplied
+ pointer. */
+ if( ! changed ) {
+ result = astClone( this );
+
+/* Otherwise, we need to create a new FrameSet to return. We take a deep
+ copy of the supplied FrameSet and then modify the Mappings and Frames
+ so that we retain any extra information in the supplied FrameSet. */
+ } else {
+ new = astCopy( this );
+
+ for( i = 0; i < this->nnode - 1; i++ ) {
+ (void) astAnnul( new->map[ i ] );
+ new->map[ i ] = astClone( newmaps[ i ] );
+ }
+
+ for( i = 0; i < this->nframe; i++ ) {
+ (void) astAnnul( new->frame[ i ] );
+ new->frame[ i ] = astClone( newfrms[ i ] );
+ }
+
+ result = (AstMapping *) new;
+ }
+
+/* Free resources. */
+ for( i = 0; i < this->nnode - 1; i++ ) {
+ newmaps[ i ] = astAnnul( newmaps[ i ] );
+ }
+
+ for( i = 0; i < this->nframe; i++ ) {
+ newfrms[ i ] = astAnnul( newfrms[ i ] );
+ }
+
+ }
+
+ newfrms = astFree( newfrms );
+ newmaps = astFree( newmaps );
+
+/* Annul the returned Mapping if an error has occurred. */
+ if( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static void ReportPoints( AstMapping *this_mapping, int forward,
+ AstPointSet *in_points, AstPointSet *out_points, int *status ) {
+/*
+* Name:
+* ReportPoints
+
+* Purpose:
+* Report the effect of transforming a set of points using a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "mapping.h"
+* void ReportPoints( AstMapping *this, int forward,
+* AstPointSet *in_points, AstPointSet *out_points, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astReportPoints
+* method inherited from the Frame class).
+
+* Description:
+* This function reports the coordinates of a set of points before
+* and after being transformed by a FrameSet, by writing them to
+* standard output.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* forward
+* A non-zero value indicates that the FrameSet's forward
+* coordinate transformation has been applied, while a zero
+* value indicates the inverse transformation.
+* in_points
+* Pointer to a PointSet which is associated with the
+* coordinates of a set of points before the FrameSet was
+* applied.
+* out_points
+* Pointer to a PointSet which is associated with the
+* coordinates of the same set of points after the FrameSet has
+* been applied.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstFrame *base_frame; /* Pointer to current Frame */
+ AstFrame *current_frame; /* Pointer to base Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double **ptr_in; /* Pointer to array of input data pointers */
+ double **ptr_out; /* Pointer to array of output data pointers */
+ int coord; /* Loop counter for coordinates */
+ int ncoord_in; /* Number of input coordinates per point */
+ int ncoord_out; /* Number of output coordinates per point */
+ int npoint; /* Number of points to report */
+ int npoint_in; /* Number of input points */
+ int npoint_out; /* Number of output points */
+ int point; /* Loop counter for points */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_mapping;
+
+/* Obtain the numbers of points and coordinates associated with each
+ PointSet. */
+ npoint_in = astGetNpoint( in_points );
+ npoint_out = astGetNpoint( out_points );
+ ncoord_in = astGetNcoord( in_points );
+ ncoord_out = astGetNcoord( out_points );
+
+/* Obtain the pointers that give access to the coordinate data
+ associated with each PointSet. */
+ ptr_in = astGetPoints( in_points );
+ ptr_out = astGetPoints( out_points );
+
+/* In the event that both PointSets don't contain equal numbers of
+ points (this shouldn't actually happen), simply use the minimum
+ number. */
+ npoint = ( npoint_in < npoint_out ) ? npoint_in : npoint_out;
+
+/* Obtain pointers to the FrameSet's base and current Frames. */
+ base_frame = astGetFrame( this, AST__BASE );
+ current_frame = astGetFrame( this, AST__CURRENT );
+
+/* Loop to report the effect of the transformation on each point in
+ turn. */
+ if ( astOK ) {
+ for ( point = 0; point < npoint; point++ ) {
+
+/* Report the input coordinates (in parentheses and separated by
+ commas). Format each value for display using the appropriate
+ Frame's astFormat method. */
+ printf( "(" );
+ for ( coord = 0; coord < ncoord_in; coord++ ) {
+ printf( "%s%s", coord ? ", " : "",
+ astFormat( forward ? base_frame : current_frame,
+ coord, ptr_in[ coord ][ point ] ) );
+ }
+
+/* Similarly report the output coordinates, this time formatting
+ values using the other Frame's astFormat method. */
+ printf( ") --> (" );
+ for ( coord = 0; coord < ncoord_out; coord++ ) {
+ printf( "%s%s", coord ? ", " : "",
+ astFormat( forward ? current_frame : base_frame,
+ coord, ptr_out[ coord ][ point ] ) );
+ }
+ printf( ")\n" );
+ }
+ }
+
+/* Annul the Frame pointers. */
+ base_frame = astAnnul( base_frame );
+ current_frame = astAnnul( current_frame );
+}
+
+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 "frameset.h"
+* void Resolve( AstFrame *this, const double point1[],
+* const double point2[], const double point3[],
+* double point4[], double *d1, double *d2, int *status );
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astResolve
+* method inherited from the Frame class).
+
+* Description:
+* This function resolves a vector into two perpendicular components.
+* The vector from point 1 to point 2 is used as the basis vector.
+* The vector from point 1 to point 3 is resolved into components
+* parallel and perpendicular to this basis vector. The lengths of the
+* two components are returned, together with the position of closest
+* aproach of the basis vector to point 3.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* point1
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). This marks the start of the basis vector,
+* and of the vector to be resolved.
+* point2
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). This marks the end of the basis vector.
+* point3
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). This marks the end of the vector to be
+* resolved.
+* point4
+* An array of double, with one element for each Frame axis
+* in which the coordinates of the point of closest approach of the
+* basis vector to point 3 will be returned.
+* d1
+* The address of a location at which to return the distance from
+* point 1 to point 4 (that is, the length of the component parallel
+* to the basis vector). Positive values are in the same sense as
+* movement from point 1 to point 2.
+* d2
+* The address of a location at which to return the distance from
+* point 4 to point 3 (that is, the length of the component
+* perpendicular to the basis vector). The value is always positive.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - Each vector used in this function is the path of
+* shortest distance between two points, as defined by the
+* astDistance function.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value, or if the required
+* output values are undefined.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astResolve method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astResolve( fr, point1, point2, point3, point4, d1, d2 );
+ fr = astAnnul( fr );
+
+}
+
+static AstPointSet *ResolvePoints( AstFrame *this_frame, const double point1[],
+ const double point2[], AstPointSet *in,
+ AstPointSet *out, int *status ) {
+/*
+* Name:
+* ResolvePoints
+
+* Purpose:
+* Resolve a set of vectors into orthogonal components
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstPointSet *astResolvePoints( AstFrame *this, const double point1[],
+* const double point2[], AstPointSet *in,
+* AstPointSet *out )
+
+* Class Membership:
+* FrameSet member function (over-rides the astResolvePoints method
+* inherited from the Frame class).
+
+* Description:
+* This function takes a Frame and a set of vectors encapsulated
+* in a PointSet, and resolves each one into two orthogonal components,
+* returning these two components in another PointSet.
+*
+* This is exactly the same as the public astResolve method, except
+* that this method allows many vectors to be processed in a single call,
+* thus reducing the computational cost of overheads of many
+* individual calls to astResolve.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* point1
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). This marks the start of the basis vector,
+* and of the vectors to be resolved.
+* point2
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). This marks the end of the basis vector.
+* in
+* Pointer to the PointSet holding the ends of the vectors to be
+* resolved.
+* out
+* Pointer to a PointSet which will hold the length of the two
+* resolved components. A NULL value may also be given, in which
+* case a new PointSet will be created by this function.
+
+* Returned Value:
+* Pointer to the output (possibly new) PointSet. The first axis will
+* hold the lengths of the vector components parallel to the basis vector.
+* These values will be signed (positive values are in the same sense as
+* movement from point 1 to point 2. The second axis will hold the lengths
+* of the vector components perpendicular to the basis vector. These
+* values will always be positive.
+
+* Notes:
+* - The number of coordinate values per point in the input
+* PointSet must match the number of axes in the supplied Frame.
+* - If an output PointSet is supplied, it must have space for
+* sufficient number of points and 2 coordinate values per point.
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstPointSet *result; /* Pointer to output PointSet */
+ AstFrameSet *this; /* Pointer to FrameSet structure */
+ AstFrame *fr; /* Pointer to current Frame */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astResolvePoints method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astResolvePoints( this, point1, point2, in, out );
+ fr = astAnnul( fr );
+
+/* Return a pointer to the output PointSet. */
+ return result;
+
+}
+
+static void RestoreIntegrity( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* RestoreIntegrity
+
+* Purpose:
+* Restore a previous integrity state for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void RestoreIntegrity( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet member function.
+
+* Description:
+* This function restores a FrameSet to a previous integrity state,
+* as recorded (in static variables) by a previous invocation of
+* the RecordIntegrity function. It does this by appropriately
+* remapping the FrameSet's current Frame, if this appears
+* necessary.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Notes:
+* - The previous record of the FrameSet's integrity state (as
+* recorded by RecordIntegrity) is deleted by this function, even
+* if it is invoked with the global error status set.
+* - An error will result if the previous integrity state cannot be
+* restored.
+*-
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstFrame *current; /* Pointer to current Frame */
+ AstFrameSet *cvt; /* Pointer to conversion FrameSet */
+ AstMapping *map; /* Pointer to conversion Mapping */
+ int flags; /* Flags associated with current frame */
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* Check that a previous record of the FrameSet's integrity state has
+ been made. Do not modify the FrameSet if it appears that the
+ previous integrity state has not been lost (i.e. that the current
+ Frame has not been modified), nor if there is only one Frame
+ present. Check the global error status. */
+ if ( integrity_frame && integrity_lost && ( astGetNframe( this ) > 1 ) &&
+ astOK ) {
+
+/* Obtain a pointer to the current Frame. */
+ current = astGetFrame( this, AST__CURRENT );
+
+/* Since we need to obtain a conversion between the recorded copy of
+ this Frame and the current one, we must match their Domain
+ attributes (otherwise conversion cannot be performed). Do this by
+ changing the recorded copy as necessary. */
+ if ( astTestDomain( current ) ) {
+ astSetDomain( integrity_frame, astGetDomain( current ) );
+ } else {
+ astClearDomain( integrity_frame );
+ }
+
+/* Temporarily set both Frames AST__INTFLAG flag to indicate that the
+ following call to astConvert is part of the process of restoring a
+ FrameSet's integrity. Some classes of Frame (e.g. DSBSpecFrames) may
+ choose to return a different Mapping in this case. */
+ astSetFrameFlags( integrity_frame, astGetFrameFlags( integrity_frame )
+ | AST__INTFLAG );
+ flags = astGetFrameFlags( current );
+ astSetFrameFlags( current, flags | AST__INTFLAG );
+
+/* Obtain the required conversion FrameSet, restore the original frame
+ flags and annul the current Frame pointer. */
+ cvt = astConvert( integrity_frame, current, "" );
+ astSetFrameFlags( current, flags );
+ current = astAnnul( current );
+
+/* If no conversion could be found, then the FrameSet's integrity
+ state cannot be restored, so report an error. */
+ if ( !cvt ) {
+ if( astOK ) {
+ astError( AST__ILOST, "%s(%s): Cannot maintain %s integrity.", status,
+ integrity_method, astGetClass( this ),
+ astGetClass( this ) );
+ }
+
+/* Otherwise, obtain a pointer to the conversion Mapping. */
+ } else {
+ map = astGetMapping( cvt, AST__BASE, AST__CURRENT );
+
+/* If the Mapping is not a UnitMap (i.e. a null Mapping), then use it
+ to remap the FrameSet's current Frame. */
+ if ( strcmp( astGetClass( map ), "UnitMap" ) ) {
+ astRemapFrame( this, AST__CURRENT, map );
+ }
+
+/* Annul the conversion Mapping and Frameset pointers. */
+ map = astAnnul( map );
+ cvt = astAnnul( cvt );
+ }
+ }
+
+/* Delete the recorded integrity information by annulling the original
+ copy of the current Frame (thus deleting it) and resetting the
+ associated modification flag. */
+ if ( integrity_frame ) integrity_frame = astAnnul( integrity_frame );
+ integrity_lost = 0;
+}
+
+static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
+/*
+* Name:
+* SetAttrib
+
+* Purpose:
+* Set an attribute value for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void SetAttrib( AstObject *this, const char *setting, int *status )
+
+* Class Membership:
+* FrameSet member function (extends the astSetAttrib method
+* inherited from the Frame class).
+
+* Description:
+* This function assigns an attribute value for a FrameSet, 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 FrameSet.
+* setting
+* Pointer to a null terminated string specifying the new
+* attribute value.
+* status
+* Pointer to the inherited status variable.
+
+* Attributes:
+* The set of attribute values is not fixed and is determined by
+* the current Frame. In addition, the FrameSet class defines the
+* following attributes:
+*
+* Base (integer)
+* Current (integer)
+
+* Notes:
+* - This protected method is intended to be invoked by the Object
+* astSet method and makes additional attributes accessible to it.
+* - All attribute settings passed to this function are simply
+* passed on to the corresponding method for the FrameSet's current
+* Frame.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to a Frame within the FrameSet */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ const char *dom; /* Pointer to Domain string */
+ int base; /* Base attribute value */
+ int base_off; /* Offset of Base value string */
+ int current; /* Current attribute value */
+ int current_off; /* Offset of Current value string */
+ int id; /* Offset of ID string */
+ int invert; /* Invert attribute value */
+ int len; /* Length of setting string */
+ int nc; /* Number of characters read by astSscanf */
+ int nfrm; /* Number of Frames in FrameSet */
+ int report; /* Report attribute value */
+ int variant; /* Offset of Variant string */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_object);
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* Obtain the length of the setting string. */
+ len = strlen( setting );
+
+/* Test for each recognised attribute in turn, using "astSscanf" to parse the
+ setting string and extract the attribute value (or an offset to it in the
+ case of string values). In each case, use the value set in "nc" to check
+ that the entire string was matched. Once a value has been obtained, use the
+ appropriate method to set it. */
+
+/* We first handle attributes that apply to the FrameSet as a whole
+ (rather than to the current Frame). */
+
+/* Base. */
+/* ----- */
+/* Read as an integer. */
+ if ( nc = 0,
+ ( 1 == astSscanf( setting, "base= %d %n", &base, &nc ) )
+ && ( nc >= len ) ) {
+ astSetBase( this, base );
+
+/* Also allow a string. */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "base= %n%*s %n", &base_off, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Check for "AST__CURRENT" or "Current". */
+ if ( astChrMatch( "AST__CURRENT", setting + base_off ) ||
+ astChrMatch( "Current", setting + base_off ) ) {
+ astSetBase( this, AST__CURRENT );
+
+/* Check for "AST__BASE" or "Base" (possible, although not very
+ useful). */
+ } else if ( astChrMatch( "AST__BASE", setting + base_off ) ||
+ astChrMatch( "Base", setting + base_off ) ) {
+
+/* If the FrameSet contains a Frame with the given Domain name, make it
+ the base Frame. */
+ } else {
+ nfrm = astGetNframe( this );
+ for( base = 1; base <= nfrm; base++ ) {
+ fr = astGetFrame( this, base );
+ dom = astGetDomain( fr );
+ fr = astAnnul( fr );
+ if( astChrMatch( dom, setting + base_off ) ) break;
+ }
+
+ if( base <= nfrm ) {
+ astSetBase( this, base );
+
+/* Report an error if the value wasn't recognised. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid index value for "
+ "Base Frame \"%s\".", status,
+ astGetClass( this ), setting + base_off );
+ }
+ }
+
+/* Current. */
+/* -------- */
+/* Since this determines the choice of current Frame, we must restore
+ the integrity state of the FrameSet before changing this attribute
+ and record the new integrity state afterwards. */
+
+/* Read as an integer. */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "current= %d %n", &current, &nc ) )
+ && ( nc >= len ) ) {
+ RestoreIntegrity( this, status );
+ astSetCurrent( this, current );
+ RecordIntegrity( this, status );
+
+/* Also allow a string. */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "current= %n%*s %n",
+ &current_off, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Check for "AST__BASE" or "Base". */
+ if ( astChrMatch( "AST__BASE", setting + current_off ) ||
+ astChrMatch( "Base", setting + current_off ) ) {
+ RestoreIntegrity( this, status );
+ astSetCurrent( this, AST__BASE );
+ RecordIntegrity( this, status );
+
+/* Check for "AST__CURRENT" or "Current" (possible, although not very
+ useful). */
+ } else if ( astChrMatch( "AST__CURRENT", setting + current_off ) ||
+ astChrMatch( "Current", setting + current_off ) ) {
+
+/* If the FrameSet contains a Frame with the given Domain name, make it
+ the current Frame. */
+ } else {
+ nfrm = astGetNframe( this );
+ for( current = 1; current <= nfrm; current++ ) {
+ fr = astGetFrame( this, current );
+ dom = astGetDomain( fr );
+ fr = astAnnul( fr );
+ if( astChrMatch( dom, setting + current_off ) ) break;
+ }
+
+ if( current <= nfrm ) {
+ RestoreIntegrity( this, status );
+ astSetCurrent( this, current );
+ RecordIntegrity( this, status );
+
+/* Report an error if the value wasn't recognised. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid index value for "
+ "Current Frame \"%s\".", status,
+ astGetClass( this ), setting + current_off );
+ }
+ }
+
+/* ID. */
+/* --- */
+ } else if ( nc = 0, ( 0 == astSscanf( setting, "id=%n%*[^\n]%n", &id, &nc ) )
+ && ( nc >= len ) ) {
+ astSetID( this, setting + id );
+
+/* Ident. */
+/* ------ */
+ } else if ( nc = 0, ( 0 == astSscanf( setting, "ident=%n%*[^\n]%n", &id, &nc ) )
+ && ( nc >= len ) ) {
+ astSetIdent( this, setting + id );
+
+/* Invert. */
+/* ------- */
+/* Since this affects the choice of current Frame, we must restore the
+ integrity state of the FrameSet before changing this attribute and
+ record the new integrity state afterwards. */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "invert= %d %n", &invert, &nc ) )
+ && ( nc >= len ) ) {
+ RestoreIntegrity( this, status );
+ astSetInvert( this, invert );
+ RecordIntegrity( this, status );
+
+/* Report. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "report= %d %n", &report, &nc ) )
+ && ( nc >= len ) ) {
+ astSetReport( this, report );
+
+/* Variant. */
+/* -------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "variant=%n%*[^\n]%n", &variant, &nc ) )
+ && ( nc >= len ) ) {
+ astSetVariant( this, setting + variant );
+
+/* Define a macro to see if the setting string matches any of the
+ read-only attributes of this class. */
+#define MATCH(attrib) \
+ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \
+ ( nc >= len ) )
+
+/* If the attribute was not recognised, use this macro to report an error
+ if a read-only attribute has been specified. */
+ } else if ( MATCH( "allvariants" ) ||
+ MATCH( "class" ) ||
+ MATCH( "nframe" ) ||
+ MATCH( "nin" ) ||
+ MATCH( "nobject" ) ||
+ MATCH( "nout" ) ||
+ MATCH( "refcount" ) ||
+ MATCH( "tranforward" ) ||
+ MATCH( "traninverse" ) ) {
+ astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status,
+ setting, astGetClass( this ) );
+ astError( AST__NOWRT, "This is a read-only attribute." , status);
+
+/* Pass unrecognised settings on to the FrameSet's current Frame for
+ further interpretation. */
+ } else {
+
+/* Force a copy to be made of the current Frame, if needed, to make it
+ independent of other Frames within the FrameSet. */
+ (void) ForceCopy( this, AST__CURRENT, status );
+
+/* Obtain a pointer to the current Frame and invoke its astSetAttrib
+ method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astSetAttrib( fr, setting );
+ fr = astAnnul( fr );
+
+/* Note that the current Frame has been modified. */
+ integrity_lost = 1;
+ }
+
+/* Undefine macros local to this function. */
+#undef MATCH
+}
+
+static void SetAxis( AstFrame *this_frame, int axis, AstAxis *newaxis, int *status ) {
+/*
+* Name:
+* SetAxis
+
+* Purpose:
+* Set a new Axis for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void SetAxis( AstFrame *this, int axis, AstAxis *newaxis, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astSetAxis method
+* inherited from the Frame class).
+
+* Description:
+* This function allows a new Axis object to be associated with one
+* of the axes of the current Frame in a FrameSet, replacing the
+* previous one. Each Axis object contains a description of the
+* quantity represented along one of the Frame's axes, so this
+* function allows this description to be exchanged for another
+* one.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* axis
+* The index (zero-based) of the axis whose associated Axis
+* object is to be replaced.
+* newaxis
+* Pointer to the new Axis object.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index supplied. */
+ (void) astValidateAxis( this, axis, 1, "astSetAxis" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astSetAxis method to assign the new Axis object. Annul the
+ Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astSetAxis( fr, axis, newaxis );
+ fr = astAnnul( fr );
+}
+
+static void SetBase( AstFrameSet *this, int iframe, int *status ) {
+/*
+*+
+* Name:
+* astSetBase
+
+* Purpose:
+* Set a value for the Base attribute of a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* void astSetBase( AstFrameSet *this, int iframe )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function sets a value for the Base attribute of a FrameSet. This
+* value is an index that identifies the base Frame for the FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* iframe
+* Value to be set for the Base attribute.
+
+* Notes:
+* - A value of AST__BASE or AST__CURRENT may be given for the
+* "iframe" parameter to identify the base Frame or the current
+* Frame respectively.
+*-
+*/
+
+/* Local Variables: */
+ int invert; /* FrameSet is inverted? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Validate and translate the Frame index supplied. */
+ iframe = astValidateFrameIndex( this, iframe, "astSetBase" );
+
+/* Determine if the FrameSet has been inverted. */
+ invert = astGetInvert( this );
+
+/* If it has not been inverted, set the base Frame index, otherwise
+ set the current Frame index instead. */
+ if ( astOK ) *( invert ? &this->current : &this->base ) = iframe;
+}
+
+static void SetCurrent( AstFrameSet *this, int iframe, int *status ) {
+/*
+*+
+* Name:
+* astSetCurrent
+
+* Purpose:
+* Set a value for the Current attribute of a FrameSet.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astSetCurrent( AstFrameSet *this, int iframe )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function sets a value for the Current attribute of a
+* FrameSet. This attribute is an index that identifies the current
+* Frame for the FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* iframe
+* Value to be set for the Current attribute.
+
+* Notes:
+* - A value of AST__BASE or AST__CURRENT may be given for the
+* "iframe" parameter to identify the base Frame or the current
+* Frame respectively.
+*-
+*/
+
+/* Local Variables: */
+ int invert; /* FrameSet is inverted? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Validate and translate the Frame index supplied. */
+ iframe = astValidateFrameIndex( this, iframe, "astSetCurrent" );
+
+/* Determine if the FrameSet has been inverted. */
+ invert = astGetInvert( this );
+
+/* If it has not been inverted, set the current frame index, otherwise
+ set the base Frame index instead. */
+ if ( astOK ) *( invert ? &this->base : &this->current ) = iframe;
+}
+
+static void SetVariant( AstFrameSet *this, const char *variant, int *status ) {
+/*
+*+
+* Name:
+* astSetVariant
+
+* Purpose:
+* Set a value for the Variant attribute of a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* void astSetVariant( AstFrameSet *this, const char *variant )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function sets a value for the Variant attribute of a FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* variant
+* Value to be set for the Variant attribute.
+
+* Notes:
+* - An error will be reported if the supplied variant name cannot be
+* found in the Variants FrameSet associated with the current Frame.
+
+*-
+*/
+
+/* Local Variables: */
+ AstCmpMap *map6;
+ AstCmpMap *map5;
+ AstCmpMap *map4;
+ AstFrame *frm;
+ AstFrame *vfrm;
+ AstFrameSet *tfs;
+ AstFrameSet *vfs;
+ AstMapping *map0;
+ AstMapping *map2;
+ AstMapping *map3;
+ AstMapping *map1;
+ char *myvar;
+ const char *dom;
+ int icur;
+ int ifrm;
+ int inode;
+ int inv0;
+ int inv;
+ int nfrm;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a copy of the supplied string and clean it. */
+ myvar = astStore( NULL, variant, strlen( variant ) + 1 );
+ astRemoveLeadingBlanks( myvar );
+ astChrCase( NULL, myvar, 1, 0 );
+ if( astOK ) {
+ myvar[ astChrLen( myvar ) ] = 0;
+
+/* Get the one-based index of the Frame that defines the available
+ variant Mappings. */
+ icur = GetVarFrm( this, astGetCurrent( this ), status );
+
+/* Get the variants FrameSet from the Frame selected above. */
+ frm = astGetFrame( this, icur );
+ vfs = astGetFrameVariants( frm );
+
+/* If there is no variants FrameSet in the Frame, the only allowed value
+ for "Variant" is the Domain name of the current Frame. */
+ if( ! vfs ) {
+ dom = astGetDomain( this );
+ if( astOK && strcmp( myvar, dom ) ) {
+ astError( AST__ATTIN, "astSetVariant(%s): Unknown Frame "
+ "variant '%s' requested.", status, astGetClass( this ),
+ myvar );
+ }
+
+/* If there is a variants FrameSet in the Frame... */
+ } else {
+
+/* Find the index of the Frame in the Variants FrameSet that has a Domain
+ equal to myvar. */
+ nfrm = astGetNframe( vfs );
+ for( ifrm = 0; ifrm < nfrm; ifrm++ ) {
+ vfrm = astGetFrame( vfs, ifrm + 1 );
+ dom = astGetDomain( vfrm );
+ vfrm = astAnnul( vfrm );
+ if( !astOK || !strcmp( myvar, dom ) ) break;
+ }
+
+/* Report an error if no such Frame found. */
+ if( ifrm == nfrm && astOK ) {
+ astError( AST__ATTIN, "astSetVariant(%s): Unknown Frame "
+ "variant '%s' requested - available variants are "
+ "'%s'.", status, astGetClass(this), myvar,
+ astGetAllVariants(this) );
+
+/* Otherwise, get a Mapping from the current Frame in "this" to the
+ currently selected Variant Frame. We cannot assume that they are the
+ same as attributes of the current Frame (e.g. System) may have been
+ changed since the variant was added. If the required Frame is already
+ the current Frame, there is nothing more to do since the required
+ variant is already selected. */
+ } else if( ifrm + 1 != astGetCurrent( vfs ) ){
+ vfrm = astGetFrame( vfs, AST__CURRENT );
+ dom = astGetDomain( frm );
+ if( dom ) dom = astStore( NULL, dom, strlen( dom ) + 1 );
+ astSetDomain( frm, astGetDomain( vfrm ) );
+ tfs = astConvert( frm, vfrm, "" );
+ astSetDomain( frm, dom );
+ if( tfs ) {
+ map1 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
+ tfs = astAnnul( tfs );
+ vfrm = astAnnul( vfrm );
+
+/* Get the Mapping from the original Variant Frame to the requested variant
+ Frame. */
+ map2 = astGetMapping( vfs, AST__CURRENT, ifrm + 1 );
+
+/* Get a Mapping from the new variant Frame to the current Frame in "this". */
+ vfrm = astGetFrame( vfs, ifrm + 1 );
+ astSetDomain( frm, astGetDomain( vfrm ) );
+ tfs = astConvert( vfrm, frm, "" );
+ astSetDomain( frm, dom );
+ if( tfs ) {
+ map3 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
+ tfs = astAnnul( tfs );
+
+/* Concatentate the three Mappings, to get the Mapping from the old
+ variant Frame to the new variant Frame. */
+ map4 = astCmpMap( map1, map2, 1, " ", status );
+ map5 = astCmpMap( map4, map3, 1, " ", status );
+
+/* Now we modify the Mapping in the FrameSet. First get the index of the node
+ with which the Frame is associated. */
+ inode = this->node[ icur - 1 ];
+
+/* Get the Mapping that generates the node values, and its Invert flag. */
+ map0 = this->map[ inode - 1 ];
+ inv0 = this->invert[ inode - 1 ];
+
+/* Temporarily reset the invert flag in the Mapping to account for any
+ changes made to the Mapping via other pointers. */
+ inv = astGetInvert( map0 );
+ astSetInvert( map0, inv0 );
+
+/* Concatentate with "map5" to get the Mapping form the the parent node
+ to the new variant of the current node. */
+ map6 = astCmpMap( map0, map5, 1, " ", status );
+
+/* Simplify it and use it to replace the Mapping in the FrameSet structure. */
+ this->map[ inode - 1 ] = astSimplify( map6 );
+ this->invert[ inode - 1 ] = astGetInvert( this->map[ inode - 1 ] );
+
+/* Re-instate the original Invert flag and free the old Mapping pointer. */
+ astSetInvert( map0, inv );
+ map0 = astAnnul( map0 );
+
+/* Make the variant Frame the current Frame within the Variants FrameSet. */
+ astSetCurrent( vfs, ifrm + 1 );
+
+/* Free resources. */
+ map6 = astAnnul( map6 );
+ map5 = astAnnul( map5 );
+ map4 = astAnnul( map4 );
+ map3 = astAnnul( map3 );
+
+/* Report an error if a Mapping cannot be found from the new variant Frame
+ to the current Frame in "this". */
+ } else if( astOK ) {
+ astError( AST__INTER, "astSetVariant(%s): Cannot convert "
+ "from a %s with Domain '%s' to a %s with Domain "
+ "'%s' (internal programming error).", status,
+ astGetClass( this ), astGetClass( vfrm ),
+ astGetDomain( vfrm ), astGetClass( frm ),
+ astGetDomain( frm ) );
+ }
+
+/* Free resources. */
+ map2 = astAnnul( map2 );
+ map1 = astAnnul( map1 );
+
+/* Report an error if a Mapping cannot be found from the current Frame in
+ "this" to the current Variant Frame. */
+ } else if( astOK ) {
+ astError( AST__INTER, "astSetVariant(%s): Cannot convert "
+ "from a %s with Domain '%s' to a %s with Domain "
+ "'%s' (internal programming error).", status,
+ astGetClass( this ), astGetClass( frm ),
+ astGetDomain( frm ), astGetClass( vfrm ),
+ astGetDomain( vfrm ) );
+ }
+
+/* Free resources. */
+ vfrm = astAnnul( vfrm );
+ dom = astFree( (void *) dom );
+ }
+
+/* Annul the pointer to the Variants FrameSet. */
+ vfs = astAnnul( vfs );
+ }
+
+/* Annul the pointer to the current Frame in "this". */
+ frm = astAnnul( frm );
+ }
+
+/* Free the memory holding the cleaned variant name. */
+ myvar = astFree( myvar );
+}
+
+static AstMapping *Simplify( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* Simplify
+
+* Purpose:
+* Simplify the Mappings in a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstMapping *Simplify( AstMapping *this, int *status )
+
+* Class Membership:
+* FrameSet method (over-rides the astSimplify method inherited
+* from the Frame class).
+
+* Description:
+* This function simplifies the Mappings in a FrameSet to eliminate
+* redundant computational steps, or to merge separate steps which
+* can be performed more efficiently in a single operation.
+
+* Parameters:
+* this
+* Pointer to the original FrameSet.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A new pointer to the (possibly simplified) FrameSet. If
+* simplification was not possible, this will be a cloned pointer
+* to the original FrameSet.
+
+* 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: */
+ AstFrameSet *new; /* Pointer to new (simpler?) FrameSet */
+ AstFrameSet *this; /* Pointer to original FrameSet structure */
+ AstMapping *map; /* Pointer to Mapping */
+ AstMapping *result; /* Result pointer to return */
+ AstMapping *tmp; /* Temporary Mapping pointer */
+ int inode; /* Loop counter for FrameSet nodes */
+ int inv; /* Mapping Invert attribute value */
+ int invert; /* Invert flag value */
+ int set; /* Invert attribute set? */
+ int simpler; /* Simplification achieved? */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_mapping;
+
+/* Make a copy of the FrameSet, since we may alter it (this is a deep
+ copy, which is a minor limitation of the current implementation). */
+ new = astCopy( this );
+
+/* Loop to examine each of the Mappings between the Frames in the
+ copy. */
+ simpler = 0;
+ for ( inode = 1; astOK && ( inode < new->nnode ); inode++ ) {
+
+/* Obtain the Mapping pointer and associated invert flag. */
+ map = new->map[ inode - 1 ];
+ invert = new->invert[ inode - 1 ];
+
+/* Determine if the Mapping's Invert attribute is set, and obtain its
+ value. */
+ set = astTestInvert( map );
+ inv = astGetInvert( map );
+
+/* If necessary, set the required value for the Invert attribute. */
+ if ( inv != invert ) astSetInvert( map, invert );
+
+/* Simplify the Mapping. */
+ tmp = astSimplify( map );
+
+/* If necessary, restore the original state of the Mapping's Invert
+ attribute. */
+ if ( inv != invert ) {
+ if ( set ) {
+ astSetInvert( map, inv );
+ } else {
+ astClearInvert( map );
+ }
+ }
+
+/* Test if simplification was performed. */
+ if ( astOK ) {
+ if ( tmp != map ) {
+
+/* If so, annul the original Mapping pointer and substitute the new
+ one. Also set a new invert flag to accompany it. */
+ (void) astAnnul( new->map[ inode - 1 ] );
+ new->map[ inode - 1 ] = astClone( tmp );
+ new->invert[ inode - 1 ] = astGetInvert( tmp );
+
+/* Note if any Mapping within the FrameSet is simplified. */
+ simpler = 1;
+ }
+ }
+
+/* Annul the pointer to the simplified Mapping. */
+ tmp = astAnnul( tmp );
+ }
+
+/* If simplification was possible, clone a pointer to the new
+ FrameSet. Otherwise clone a pointer to the original one. */
+ if ( astOK ) result = astClone( simpler ? new : this );
+
+/* Annul the new FrameSet pointer. */
+ new = astAnnul( new );
+
+/* If an error occurred, annul the returned pointer. */
+ if ( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static int Span( AstFrameSet *this, AstFrame **frames, int inode1, int inode2,
+ int avoid, AstMapping **map, int *forward, int *status ) {
+/*
+* Name:
+* Span
+
+* Purpose:
+* Find a path between two nodes in a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int Span( AstFrameSet *this, AstFrame **frames, int inode1, int inode2,
+* int avoid, AstMapping **map, int *forward, int *status )
+
+* Class Membership:
+* FrameSet member function.
+
+* Description:
+* This function searches a FrameSet to identify a path between two
+* specified nodes. It returns an array of pointers to each Mapping
+* in the path, along with direction information, so that an
+* overall Mapping between the two nodes can be constructed.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* frames
+* Pointer to an array of Frame pointers, indexed by node index.
+* Nodes which have no associated Frame will have a NULL pointer
+* stored in this array.
+* inode1
+* Zero based index of the starting node.
+* inode2
+* Zero based index of the ending node.
+* avoid
+* Zero based index which identifies a node which is to be
+* avoided (i.e. the initial step in the path should not be via
+* this node). This value is required because the function
+* invokes itself recursively; it provides a mechanism to
+* prevent searches proceeding back down paths that have already
+* been searched. External callers should provide a value of -1,
+* which indicates that all possible paths should initially be
+* explored.
+* map
+* Pointer to the start of an array that will be filled with a
+* series of pointers to Mappings which must be applied in turn
+* in order to transform between the two Frames. External
+* callers should ensure that this array contains at least as many
+* elements as there are Mappings and Frames in the FrameSet (one less
+* than the number of nodes plus the number of Frames).
+*
+* Note that the pointers are simply copies of addresses from
+* the FrameSet's "map" array. They are not cloned, so should
+* not be annulled by the caller.
+* forward
+* Pointer to the start of an array of int that will be filled
+* with boolean flags (0 or 1) to indicate whether the forward
+* (as opposed to the inverse) transformation should be used for
+* each Mapping returned in order to effect the transformation
+* between the starting and ending nodes. This array should be the
+* same size as the "map" array.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The function returns one more than the number of Mappings
+* required to perform the transformation, or zero if it was not
+* possible to find a path between the two nodes.
+
+* Notes:
+* - If a node has an associated Frame, the Frame usually represents a
+* UnitMap and so can be ignored. The exception is if the Frame is
+* actually a Region (or a CmpFrame containing a Region), in which case
+* it represents a Mapping which returns bad values if the input position
+* is outside the region. This form of Mapping should not be ignored, and
+* so the returned list of Mappings includes the effect of any Frames
+* along the path which are not equivalent to a UnitMap. This
+* equivalence is determined by invoking the astSimplify method on the
+* Frame.
+* - 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.
+* - On the assumption that the FrameSet has been consistently
+* constructed, there should be exactly one path between any pair
+* of its nodes. It should not, therefore, ever fail to find a
+* path except when invoked recursively to explore a subset of the
+* FrameSet's nodes (this should not be visible to an external
+* caller). Failure to find a path does not in itself result in an
+* error condition.
+*/
+
+/* Local Variables: */
+ AstFrame *frame; /* Pointer to Frame associated with inode1 */
+ int fwd; /* Forward Mapping identified? */
+ int inode; /* Loop counter for nodes */
+ int inv; /* Inverse Mapping identified? */
+ int invert; /* Original Mapping Invert value */
+ int nextra; /* No. of extra Mappings to add to path */
+ int result; /* Count of mappings (to be returned) */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* See if the two nodes are the same. */
+ result = ( inode1 == inode2 );
+
+/* If so, we need to consider the Mapping represented by any Frame
+ associated with the node. Most classes of Frames are equivalent to a
+ UnitMap and so can be ignored. But some (e.g. the Region class) are not
+ equivalent to a UnitMap and so needs to be included in the returned
+ Mapping list. */
+ if( result ) {
+ result = 1;
+
+/* If inode1 is associated with a Frame, which is not equivalent to a
+ UnitMap, add the Frame as the first Mapping into the returned list. The
+ "forward" value is irrelevant since the forward and inverse transformations
+ of Frames are the same. */
+ frame = frames[ inode1 ];
+ if( frame ) {
+ if( !astIsUnitFrame( frame ) ) {
+ result++;
+ *map = (AstMapping *) frame;
+ *forward = 1;
+ }
+ }
+
+/* If the nodes are different, we now attempt to find the next step in
+ the path between them. Loop through all available nodes looking for
+ the next one to transform to (i.e. one that is directly related by
+ a Mapping to our starting node). */
+ } else {
+ for ( inode = 0; inode < this->nnode; inode++ ) {
+
+/* Do not consider node "avoid". This prevents us re-tracing our steps
+ backwards when this function is invoked recursively. */
+ if ( inode != avoid ) {
+
+/* Test if inode is derived from inode1 (if so, the Mapping associated
+ with inode will convert from inode1 to inode when applied in the
+ forward direction). */
+ fwd = ( inode > 0 ) && ( this->link[ inode - 1 ] == inode1 );
+
+/* Test if inode1 is derived from inode (if so, the Mapping associated
+ with inode1 will convert from inode1 to inode when applied in the
+ inverse direction). */
+ inv = ( inode1 > 0 ) && ( this->link[ inode1 - 1 ] == inode );
+
+/* If the nodes are directly related, we try to find a path from inode to
+ inode2 without going back through inode1. */
+ if ( fwd || inv ) {
+
+/* If node1 is associated with a Frame, we need to include the Frame
+ as a Mapping in the returned list unless the Frame is equivalent to a
+ UnitMap. Note the number of slots to be reserved for node1 when we call
+ Span recursively below. */
+ nextra = 1;
+ frame = frames[ inode1 ];
+ if( frame && !astIsUnitFrame( frame ) ) nextra = 2;
+
+/* Invoke this function recursively to try and find a path from inode
+ to inode2 without going back through inode1. If this is possible, a
+ non-zero result will be returned. Store the returned Mappings and
+ direction information in the arrays supplied, but leave extra space to
+ insert information about the Mapping between nodes inode1 and inode. */
+ result = Span( this, frames, inode, inode2, inode1,
+ map + nextra, forward + nextra, status );
+
+/* If a path was found, increment the Mapping count to account for the
+ one that transforms between nodes inode1 and inode and insert
+ information for this Mapping into the output arrays. */
+ if ( result ) {
+ result++;
+ nextra--;
+ map[ nextra ] = this->map[ ( fwd ? inode : inode1 ) - 1 ];
+ forward[ nextra ] = fwd;
+
+/* Obtain the original value of the Invert attribute for the Mapping
+ between nodes inode1 and inode (recorded when the Mapping was first
+ added to the FrameSet). Test if this value has now changed. If so,
+ some external code has inverted the Mapping via another pointer, so
+ invert the returned direction information to compensate for
+ this. */
+ invert = this->invert[ ( fwd ? inode : inode1 ) - 1 ];
+ if ( invert != astGetInvert( map[ nextra ] ) ) {
+ forward[ nextra ] = !forward[ nextra ];
+ }
+
+/* If inode1 is associated with a non-unit Frame Mapping, add the Frame
+ Mapping in as the first Mapping in the returned list. The "forward" value
+ is irrelevant since the forward and inverse transformations of Frames
+ are the same. */
+ if( nextra ) {
+ result++;
+ *map = (AstMapping *) frame;
+ *forward = 1;
+ }
+
+/* Quit searching once a path has been found. */
+ break;
+ }
+ }
+ }
+ }
+ }
+
+/* Return the result, which is one more than the number of mappings
+ found (i.e. steps in the path), or zero if no path was found (this
+ should only occur when invoked recursively to explore an
+ unsuccessful sub-path). */
+ return result;
+}
+
+static int SubFrame( AstFrame *this_frame, AstFrame *template,
+ int result_naxes,
+ const int *target_axes, const int *template_axes,
+ AstMapping **map, AstFrame **result, int *status ) {
+/*
+* Name:
+* SubFrame
+
+* Purpose:
+* Select axes from a FrameSet and convert to the new coordinate system.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.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:
+* FrameSet member function (over-rides the protected astSubFrame
+* method inherited from the Frame class).
+
+* Description:
+* This function selects a requested sub-set (or super-set) of the
+* axes from the current Frame of a "target" FrameSet and creates a
+* new Frame with copies of the selected axes assembled in the
+* requested order. It then optionally overlays the attributes of a
+* "template" Frame on to the result. It returns both the resulting
+* Frame and a Mapping that describes how to convert between the
+* coordinate systems described by the current Frame of the target
+* FrameSet and the result Frame. If necessary, this Mapping takes
+* account of any differences in the Frames' attributes due to the
+* influence of the template.
+
+* Parameters:
+* target
+* Pointer to the target FrameSet, from whose current Frame the
+* axes are to be selected.
+* template
+* Pointer to the template Frame, from which new attributes for
+* the result Frame are to be obtained. Optionally, this may be
+* NULL, in which case no overlaying of template attributes will
+* be performed.
+* result_naxes
+* Number of axes to be selected from the target FrameSet. This
+* number may be greater than or less than the number of axes in
+* the FrameSet's current Frame (or equal).
+* target_axes
+* Pointer to an array of int with result_naxes elements, giving
+* a list of the (zero-based) axis indices of the axes to be
+* selected from the current Frame of the target FrameSet. 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 FrameSet, but will be assigned
+* default attributes instead.
+* template_axes
+* Pointer to an array of int with result_naxes elements. This
+* should contain a list of the template axes (given as
+* zero-based axis indices) with which the axes of the result
+* Frame are to be associated. This array determines which axes
+* are used when overlaying axis-dependent attributes of the
+* template on to the result. If any element of this array is
+* set to -1, the corresponding result axis will not receive any
+* template attributes.
+*
+* If the template argument is given as NULL, this array is not
+* used and a NULL pointer may also be supplied here.
+* map
+* Address of a location to receive a pointer to the returned
+* Mapping. The forward transformation of this Mapping will
+* describe how to convert coordinates from the coordinate
+* system described by the current Frame of the target FrameSet
+* to that described by the result Frame. The inverse
+* transformation will convert in the opposite direction.
+* result
+* Address of a location to receive a pointer to the result Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A non-zero value is returned if coordinate conversion is
+* possible between the current Frame of the target FrameSet and
+* the result Frame. Otherwise zero is returned and *map and
+* *result are returned as NULL (but this will not in itself result
+* in an error condition). In general, coordinate conversion should
+* always be possible if no template Frame is supplied but may not
+* always be possible otherwise.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to FrameSet's current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int match; /* Result to be returned */
+
+/* Initialise. */
+ *map = NULL;
+ *result = NULL;
+ match = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return match;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame. */
+ fr = astGetFrame( this, AST__CURRENT );
+
+/* Invoke the astSubFrame method for this Frame. */
+ match = astSubFrame( fr, template, result_naxes, target_axes, template_axes,
+ map, result );
+
+/* Annul the Frame pointer. */
+ fr = astAnnul( fr );
+
+/* If an error occurred, clean up by annulling any returned objects and clear
+ the returned result. */
+ if ( !astOK ) {
+ *map = astAnnul( *map );
+ *result = astAnnul( *result );
+ match = 0;
+ }
+
+/* Return the result. */
+ return match;
+}
+
+static AstSystemType SystemCode( AstFrame *this_frame, const char *system, int *status ) {
+/*
+* Name:
+* SystemCode
+
+* Purpose:
+* Convert a string into a coordinate system type code.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstSystemType SystemCode( AstFrame *this, const char *system, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astSystemCode
+* method inherited from the Frame class).
+
+* Description:
+* This function converts a string used for the external description of
+* a coordinate system into a Frame coordinate system type code (System
+* attribute value). It is the inverse of the astSystemString function.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* system
+* Pointer to a constant null-terminated string containing the
+* external description of the coordinate system.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The System type code.
+
+* Notes:
+* - A value of AST__BADSYSTEM is returned if the coordinate system
+* description was not recognised. This does not produce an error.
+* - A value of AST__BADSYSTEM is also returned if this function
+* is invoked with the global error status set or if it should fail
+* for any reason.
+*/
+
+/* Local Variables: */
+ AstSystemType result; /* Result value to return */
+ AstFrame *fr; /* Pointer to FrameSet's current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Initialise. */
+ result = AST__BADSYSTEM;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astSystemCode method for this Frame. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astSystemCode( fr, system );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = AST__BADSYSTEM;
+
+/* Return the result. */
+ return result;
+}
+
+static const char *SystemString( AstFrame *this_frame, AstSystemType system, int *status ) {
+/*
+* Name:
+* SystemString
+
+* Purpose:
+* Convert a coordinate system type code into a string.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* const char *SystemString( AstFrame *this, AstSystemType system, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astSystemString
+* method inherited from the Frame class).
+
+* Description:
+* This function converts a Frame coordinate system type code
+* (System attribute value) into a string suitable for use as an
+* external representation of the coordinate system type.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* system
+* The coordinate system type code.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to a constant null-terminated string containing the
+* textual equivalent of the type code supplied.
+
+* Notes:
+* - A NULL pointer value is returned if the coordinate system
+* code was not recognised. This does not produce an error.
+* - A NULL pointer value is also returned if this function is
+* invoked with the global error status set or if it should fail
+* for any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to FrameSet's current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ const char *result; /* Pointer value to return */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astSystemString method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astSystemString( fr, system );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result pointer. */
+ return result;
+
+}
+
+static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* TestAttrib
+
+* Purpose:
+* Test if a specified attribute value is set for a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int TestAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* FrameSet 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 FrameSet's attributes.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* attrib
+* Pointer to a null terminated string specifying the attribute
+* name. This should be in lower case with no surrounding white
+* space.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* One if a value has been set, otherwise zero.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* Check the attribute name and test the appropriate attribute. */
+
+/* We first handle attributes that apply to the FrameSet as a whole
+ (rather than to the current Frame). */
+
+/* Base. */
+/* ----- */
+ if ( !strcmp( attrib, "base" ) ) {
+ result = astTestBase( this );
+
+/* Current. */
+/* -------- */
+ } else if ( !strcmp( attrib, "current" ) ) {
+ result = astTestCurrent( this );
+
+/* ID. */
+/* --- */
+ } else if ( !strcmp( attrib, "id" ) ) {
+ result = astTestID( this );
+
+/* Ident. */
+/* ------ */
+ } else if ( !strcmp( attrib, "ident" ) ) {
+ result = astTestIdent( this );
+
+/* Invert. */
+/* ------- */
+ } else if ( !strcmp( attrib, "invert" ) ) {
+ result = astTestInvert( this );
+
+/* Report. */
+/* ------- */
+ } else if ( !strcmp( attrib, "report" ) ) {
+ result = astTestReport( this );
+
+/* Variant. */
+/* -------- */
+ } else if ( !strcmp( attrib, "variant" ) ) {
+ result = astTestVariant( this );
+
+/* If the name is not recognised, test if it matches any of the
+ read-only attributes of this class. If it does, then return
+ zero. */
+ } else if ( !strcmp( attrib, "allvariants" ) ||
+ !strcmp( attrib, "class" ) ||
+ !strcmp( attrib, "nframe" ) ||
+ !strcmp( attrib, "nin" ) ||
+ !strcmp( attrib, "nobject" ) ||
+ !strcmp( attrib, "nout" ) ||
+ !strcmp( attrib, "refcount" ) ||
+ !strcmp( attrib, "tranforward" ) ||
+ !strcmp( attrib, "traninverse" ) ) {
+ result = 0;
+
+/* Pass unrecognised attributes on to the FrameSet's current Frame for
+ further interpretation. */
+ } else {
+
+/* Obtain a pointer to the current Frame and invoke its astTestAttrib
+ method. Annul the Frame pointer afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astTestAttrib( fr, attrib );
+ fr = astAnnul( fr );
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result, */
+ return result;
+}
+
+static int TestBase( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astTestBase
+
+* Purpose:
+* Determine if a value has been set for the Base attribute of a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astTestBase( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns a boolean result to indicate if a value
+* has been set for the Base attribute of a FrameSet. This
+* attribute is an index that identifies the base Frame in the
+* FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* Zero or 1, depending on whether a value has been set.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ int invert; /* FrameSet is inverted? */
+ int result; /* Value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Determine if the FrameSet has been inverted. */
+ invert = astGetInvert( this );
+
+/* If it has not been inverted, test the base Frame index, otherwise
+ test the index of the current Frame instead. */
+ if ( astOK ) {
+ if ( !invert ) {
+ result = ( this->base != -INT_MAX );
+ } else {
+ result = ( this->current != -INT_MAX );
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int TestCurrent( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astTestCurrent
+
+* Purpose:
+* Test if a value has been set for the Current attribute of a FrameSet.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astTestCurrent( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns a boolean result to indicate whether a
+* value has been set for the Current attribute of a FrameSet.
+* This attribute is an index that identifies the current Frame in
+* a FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* Zero or 1, depending on whether a value has been set.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ int invert; /* FrameSet is inverted? */
+ int result; /* Value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Determine if the FrameSet has been inverted. */
+ invert = astGetInvert( this );
+
+/* If it has not been inverted, test the current Frame index,
+ otherwise test the index of the base Frame instead. */
+ if ( astOK ) {
+ if ( !invert ) {
+ result = ( this->current != -INT_MAX );
+ } else {
+ result = ( this->base != -INT_MAX );
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int TestVariant( AstFrameSet *this, int *status ) {
+/*
+*+
+* Name:
+* astTestVariant
+
+* Purpose:
+* Determine if a value has been set for the Variant attribute of a FrameSet.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astTestVariant( AstFrameSet *this )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns a boolean result to indicate if a value
+* has been set for the Variant attribute of a FrameSet.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+
+* Returned Value:
+* Zero or 1, depending on whether a value has been set.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstFrame *frm;
+ AstFrameSet *vfs;
+ int result;
+ int icur;
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get the one-based index of the Frame to use. */
+ icur = GetVarFrm( this, astGetCurrent( this ), status );
+
+/* Get a pointer to the Variants FrameSet in the current Frame. */
+ frm = astGetFrame( this, icur );
+ vfs = astGetFrameVariants( frm );
+
+/* If it is null, return zero, otherwise 1. */
+ result = vfs ? 1 : 0;
+
+/* Annul pointers. */
+ if( vfs ) vfs = astAnnul( vfs );
+ frm = astAnnul( frm );
+
+/* Return the result. */
+ return result;
+}
+
+static void TidyNodes( AstFrameSet *this, int *status ) {
+/*
+* Name:
+* TidyNodes
+
+* Purpose:
+* Tidy the nodes in a FrameSet.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void TidyNodes( AstFrameSet *this, int *status )
+
+* Class Membership:
+* FrameSet member function.
+
+* Description:
+* This function tidies the nodes in a FrameSet, removing any that
+* are unnecessary or represent dead-ends. It should be used after
+* any changes have been made to a FrameSet that may have reduced
+* the number of references to any of its nodes (either by Frames
+* or by other nodes).
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstMapping *newmap; /* Pointer to simplified Mapping */
+ AstMapping *tmpmap; /* Pointer to new compound Mapping */
+ int ifr; /* Loop counter for Frames */
+ int inode; /* Loop counter for nodes */
+ int last_link[ 2 ]; /* Last nodes to reference via "link" array */
+ int link_ref; /* Number of "link" array references */
+ int needed; /* Node still required? */
+ int next; /* Node which references the removed one */
+ int remove; /* Node to be removed */
+ int suspect; /* Loop counter for testing nodes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Loop to search for unnecessary nodes until no more are found. */
+ needed = 0;
+ while ( !needed ) {
+
+/* Inspect each node (including node zero, which does not actually
+ have a Mapping associated with it) to see how many times it is
+ referenced. */
+ for ( suspect = 0; suspect < this->nnode; suspect++ ) {
+ link_ref = 0;
+
+/* Test for at least one reference from within the "node" array which
+ associates Frames with particular nodes. */
+ for ( ifr = 1; ifr <= this->nframe; ifr++ ) {
+ if ( ( needed = ( this->node[ ifr - 1 ] == suspect ) ) ) break;
+ }
+
+/* If no references were found above, look for references in the
+ "link" array that inter-connects all the nodes. */
+ if ( !needed ) {
+ for ( inode = 1; inode < this->nnode; inode ++ ) {
+ if ( this->link[ inode - 1 ] == suspect ) {
+
+/* Node zero must be retained if it has more than two links
+ referencing it, while other nodes only require more than one. */
+ if ( ( needed = ( link_ref >= ( suspect ? 1 : 2 ) ) ) ) break;
+
+/* Remember (up to) the first two nodes which reference the current one. */
+ last_link[ link_ref++ ] = inode;
+ }
+ }
+ }
+
+/* If there were insufficient references to retain this node, we must
+ now decide why it should be removed. */
+ if ( !needed ) {
+
+/* If there is no Frame associated with a node and there are less than
+ two links to it (for node zero), or less then one link (for other
+ nodes), then the there is no route to anything else via this node.
+ It is a dead-end. */
+ if ( link_ref < ( suspect ? 1 : 2 ) ) {
+
+/* To tidy up, we remove the affected node or, for node zero, the
+ remaining one that references it. Annul the Mapping associated with
+ the node being removed. */
+ remove = suspect ? suspect : last_link[ 0 ];
+ this->map[ remove - 1 ] = astAnnul( this->map[ remove - 1 ] );
+
+/* If an unnecessary node is not a dead-end, then it is a redundant
+ node which simply joins two Mappings. */
+ } else {
+
+/* To tidy up, we remove the affected node or, for node zero, the
+ first one that references it. */
+ remove = suspect ? suspect : last_link[ 0 ];
+
+/* We then produce a compound Mapping which spans the gap by
+ concatenating the Mappings associated with the node being removed
+ and the remaining one which references it. For node zero, the first
+ of these Mappings must be inverted because there are no out-going
+ Mappings from node zero. */
+ next = suspect ? last_link[ 0 ] : last_link[ 1 ];
+ tmpmap = CombineMaps( this->map[ remove - 1 ],
+ this->invert[ remove - 1 ] != !suspect,
+ this->map[ next - 1 ],
+ this->invert[ next - 1 ], 1, status );
+
+/* Simplify this compound Mapping. */
+ newmap = astSimplify( tmpmap );
+ tmpmap = astAnnul( tmpmap );
+
+/* Annul the individual Mapping pointers. */
+ this->map[ remove - 1 ] = astAnnul( this->map[ remove - 1 ] );
+ this->map[ next - 1 ] = astAnnul( this->map[ next - 1 ] );
+
+/* Install the new compound Mapping and its Invert flag. */
+ this->map[ next - 1 ] = newmap;
+ this->invert[ next - 1 ] = astGetInvert( newmap );
+
+/* Transfer the "link" value from the removed node to the one which
+ takes its place. */
+ this->link[ next - 1 ] = this->link[ remove - 1 ];
+ }
+
+/* Loop to move all subsequent node data down in the "map", "invert"
+ and "link" arrays to close the gap where a node has been
+ removed. */
+ for ( inode = remove; inode < this->nnode - 1; inode ++ ) {
+ this->map [ inode - 1 ] = this->map[ inode ];
+ this->link [ inode - 1 ] = this->link[ inode ];
+ this->invert[ inode - 1 ] = this->invert[ inode ];
+ }
+ this->map[ this->nnode - 2 ] = NULL;
+ this->link[ this->nnode - 2 ] = -1;
+ this->invert[ this->nnode - 2 ] = -1;
+
+/* Decrement the node count. */
+ this->nnode--;
+
+/* Loop to adjust each entry in the "node" array for the change in
+ node numbering, re-directing references to the removed node towards
+ the new node zero. */
+ for ( ifr = 1; ifr <= this->nframe; ifr++ ) {
+ if ( this->node[ ifr - 1 ] > remove ) {
+ this->node[ ifr - 1 ]--;
+ } else if ( this->node[ ifr - 1 ] == remove ) {
+ this->node[ ifr - 1 ] = 0;
+ }
+ }
+
+/* Similarly adjust each entry in the "link" array. */
+ for ( inode = 1; inode < this->nnode; inode++ ) {
+ if ( this->link[ inode - 1 ] > remove ) {
+ this->link[ inode - 1 ]--;
+ } else if ( this->link[ inode - 1 ] == remove ) {
+ this->link[ inode - 1 ] = 0;
+ }
+ }
+
+/* Once a node has been removed, other nodes (perhaps already tested)
+ may no longer be needed, so quit the testing loop and start testing
+ again with node zero. The process terminates when no more
+ unnecessary nodes can be found. */
+ break;
+ }
+ }
+ }
+}
+
+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 "frameset.h"
+* AstPointSet *Transform( AstMapping *this, AstPointSet *in,
+* int forward, AstPointSet *out, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the astTransform method
+* inherited from the Frame class).
+
+* Description:
+* This function takes a FrameSet and a set of points encapsulated
+* in a PointSet, and applies either the forward or inverse
+* coordinate transformation (if defined by the FrameSet) to the
+* points. The forward transformation converts between the
+* FrameSet's base Frame and its current Frame, while the inverse
+* transformation converts in the opposite direction.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* 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:
+* - An error will result if the FrameSet supplied does not define
+* the requested coordinate transformation (either forward or
+* inverse).
+* - The number of coordinate values per point in the input
+* PointSet must match the number of input coordinates for the
+* FrameSet being applied (or number of output coordinates if the
+* inverse transformation is requested). This will be equal to the
+* number of axes in the FrameSet's base Frame (or the current
+* Frame for the inverse transformation).
+* - If an output PointSet is supplied, it must have space for
+* sufficient number of points and coordinate values per point to
+* accommodate the result (e.g. the number of FrameSet output
+* coordinates, or number of input coordinates if the inverse
+* transformation is requested). Any excess space will be ignored.
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ AstMapping *map; /* Pointer to the base->current Mapping */
+ AstPointSet *result; /* Pointer value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_mapping;
+
+/* Obtain the Mapping between the base and current Frames in the
+ FrameSet (note this takes account of whether the FrameSet has been
+ inverted). */
+ map = astGetMapping( this, AST__BASE, AST__CURRENT );
+
+/* 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 FrameSet axis.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int Unformat( AstFrame *this, int axis, const char *string,
+* double *value, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the public astUnformat
+* method inherited from the Frame class).
+
+* Description:
+* This function reads a formatted coordinate value for a FrameSet
+* 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 FrameSet.
+* axis
+* The number of the FrameSet 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: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ double coord; /* Coordinate value read */
+ int nc; /* Number of characters read */
+
+/* Initialise. */
+ nc = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return nc;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astUnformat" );
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astUnformat method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ nc = astUnformat( fr, axis, string, &coord );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the number of characters read. */
+ if ( !astOK ) {
+ nc = 0;
+
+/* Otherwise, if characters were read, return the coordinate value. */
+ } else if ( nc ) {
+ *value = coord;
+ }
+
+/* Return the number of characters read. */
+ return nc;
+}
+
+static int ValidateAxis( AstFrame *this_frame, int axis, int fwd,
+ const char *method, int *status ) {
+/*
+* Name:
+* ValidateAxis
+
+* Purpose:
+* Validate and permute a FrameSet's axis index.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int ValidateAxis( AstFrame *this, int axis, int fwd, const char *method,
+* int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected
+* astValidateAxis method inherited from the Frame class).
+
+* Description:
+* This function checks the validity of an index (zero-based) which
+* is to be used to address one of the coordinate axes of the
+* current Frame in a FrameSet. If the index is valid, it is
+* permuted using the axis permutation array associated with the
+* FrameSet's current Frame and the (zero-based) permuted axis
+* index is returned. This gives the index the axis had when the
+* Frame was first created. If the axis index supplied is not
+* valid, an error is reported and the global error status is set.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* axis
+* The axis index (zero-based) to be checked. To be valid, it
+* must lie between zero and (naxes-1) inclusive, where "naxes"
+* is the number of coordinate axes associated with the
+* FrameSet's current Frame.
+* fwd
+* If non-zero, the suppplied axis index is assumed to be an
+* "external" axis index, and the corresponding "internal" axis index
+* is returned as the function value. Otherwise, the suppplied axis
+* index is assumed to be an "internal" axis index, and the
+* corresponding "external" axis index is returned as the function
+* value.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate an axis index. This method name is used solely
+* for constructing error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The permuted axis index - either "internal" or "external" as
+* specified by "fwd".
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ int naxes; /* Number of FrameSet axes */
+ int result; /* Permuted axis index */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Determine the number of FrameSet axes. */
+ naxes = astGetNaxes( this );
+ if ( astOK ) {
+
+/* If the FrameSet has no axes, report an error (convert to 1-based
+ axis numbering for the benefit of the public interface). */
+ if ( naxes == 0 ) {
+ astError( AST__AXIIN, "%s(%s): Invalid attempt to use an axis index "
+ "(%d) for a %s which has no axes.", status, method,
+ astGetClass( this ), axis + 1, astGetClass( this ) );
+
+/* Otherwise, check the axis index for validity and report an error if
+ it is not valid (again, convert to 1-based axis numbering). */
+ } else if ( ( axis < 0 ) || ( axis >= naxes ) ) {
+ astError( AST__AXIIN, "%s(%s): Axis index (%d) invalid - it should "
+ "be in the range 1 to %d.", status, method, astGetClass( this ),
+ axis + 1, naxes );
+
+/* If the axis index was valid, obtain a pointer to the FrameSet's
+ current Frame and invoke this Frame's astValidateAxis method to
+ obtain the permuted axis index. Annul the Frame pointer
+ afterwards. */
+ } else {
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astValidateAxis( fr, axis, fwd, "astValidateAxis" );
+ fr = astAnnul( fr );
+ }
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static void ValidateAxisSelection( AstFrame *this_frame, int naxes,
+ const int *axes, const char *method, int *status ) {
+/*
+* Name:
+* ValidateAxisSelection
+
+* Purpose:
+* Check that a set of axes selected from a Frame is valid.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void ValidateAxisSelection( AstFrame *this, int naxes,
+* const int *axes, const char *method, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astValidateAxisSelection
+* method inherited from the Frame class).
+
+* Description:
+* This function checks the validity of an array of (zero-based)
+* axis indices that specify a set of axes to be selected from a
+* Frame. To be valid, no axis should be selected more than
+* once. In assessing this, any axis indices that do not refer to
+* valid Frame axes (e.g. are set to -1) are ignored.
+*
+* If the axis selection is valid, this function returns without further
+* action. Otherwise, an error is reported and the global error status is
+* set.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* naxes
+* The number of axes to be selected (may be zero).
+* axes
+* Pointer to an array of int with naxes elements that contains the
+* (zero based) axis indices to be checked.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate an axis selection. This method name is used
+* solely for constructing error messages.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstFrame *fr; /* Pointer to current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke this
+ Frame's astValidateAxisSelection method. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ astValidateAxisSelection( fr, naxes, axes, method );
+ fr = astAnnul( fr );
+
+}
+
+static int ValidateFrameIndex( AstFrameSet *this, int iframe,
+ const char *method, int *status ) {
+/*
+*+
+* Name:
+* astValidateFrameIndex
+
+* Purpose:
+* Validate a FrameSet Frame index number.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astValidateFrameIndex( AstFrameSet *this, int iframe,
+* const char *method )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function checks a (one-based) FrameSet Frame index for
+* validity. If it is not valid, an error is reported. Otherwise,
+* the function returns the Frame index value, having translated
+* the special values AST__CURRENT and AST__BASE into valid Frame
+* indices if necessary.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* iframe
+* The Frame index. To be valid this should lie in the range 1
+* to the number of Frames in the FrameSet. In addition, the
+* values AST__CURRENT and AST__BASE may be given to indicate
+* the "current" and "base" Frames. These values will be
+* translated into the acceptable range.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate a Frame index. This method name is used solely
+* for constructing error messages.
+
+* Returned Value:
+* The validated (one-based) Frame index.
+
+* 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
+* (e.g. if the Frame index is invalid).
+*-
+*/
+
+/* Local Variables: */
+ int nframe; /* Number of Frames */
+ int result; /* Returned index value */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Check if the base or current Frame was specified and retrieve the
+ required Frame index from the FrameSet. */
+ if ( iframe == AST__BASE ) {
+ result = astGetBase( this );
+ } else if ( iframe == AST__CURRENT ) {
+ result = astGetCurrent( this );
+
+/* Otherwise, determine how many Frames there are in the FrameSet. */
+ } else {
+ nframe = astGetNframe( this );
+ if ( astOK ) {
+
+/* Check that the supplied index is within range and report an error
+ if it is not. */
+ if ( ( iframe < 1 ) || ( iframe > nframe ) ) {
+ astError( AST__FRMIN, "%s(%s): Invalid Frame index (%d) given.", status,
+ method, astGetClass( this ), iframe );
+ astError( AST__FRMIN, "This value should be in the range 1 to "
+ "%d (or AST__CURRENT or AST__BASE).", status, nframe );
+
+/* If OK, return the validated index value. */
+ } else {
+ result = iframe;
+ }
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int ValidateSystem( AstFrame *this_frame, AstSystemType system, const char *method, int *status ) {
+/*
+* Name:
+* ValidateSystem
+
+* Purpose:
+* Validate a value for a Frame's System attribute.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* int ValidateSystem( AstFrame *this, AstSystemType system,
+* const char *method, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astValidateSystem
+* method inherited from the Frame class).
+
+* Description:
+* This function checks the validity of the supplied system value.
+* If the value is valid, it is returned unchanged. Otherwise, an
+* error is reported and a value of AST__BADSYSTEM is returned.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* system
+* The system value to be checked.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate an axis index. This method name is used solely
+* for constructing error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The validated system value.
+
+* Notes:
+* - A value of AST_BADSYSTEM will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ AstSystemType result; /* Validated system value */
+ AstFrame *fr; /* Pointer to FrameSet's current Frame */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+
+/* Initialise. */
+ result = AST__BADSYSTEM;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_frame;
+
+/* Obtain a pointer to the FrameSet's current Frame and invoke the
+ astValidateSystem method for this Frame. Annul the Frame pointer
+ afterwards. */
+ fr = astGetFrame( this, AST__CURRENT );
+ result = astValidateSystem( this, system, method );
+ fr = astAnnul( fr );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = AST__BADSYSTEM;
+
+/* Return the result. */
+ return result;
+}
+
+static void VSet( AstObject *this_object, const char *settings,
+ char **text, va_list args, int *status ) {
+/*
+* Name:
+* VSet
+
+* Purpose:
+* Set values for a FrameSet's attributes.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frameset.h"
+* void VSet( AstObject *this, const char *settings, char **text,
+* va_list args, int *status )
+
+* Class Membership:
+* FrameSet member function (over-rides the protected astVSet
+* method inherited from the Object class).
+
+* Description:
+* This function assigns a set of attribute values for a FrameSet,
+* the attributes and their values being specified by means of a
+* string containing a comma-separated list of the form:
+*
+* "attribute1 = value1, attribute2 = value2, ... "
+*
+* Here, "attribute" specifies an attribute name and the value to
+* the right of each "=" sign should be a suitable textual
+* representation of the value to be assigned to that
+* attribute. This will be interpreted according to the attribute's
+* data type.
+*
+* The string supplied may also contain "printf"-style format
+* specifiers identified by a "%" sign in the usual way. If
+* present, these will be substituted by values supplied as
+* optional arguments (as a va_list variable argument list), using
+* the normal "printf" rules, before the string is used.
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* settings
+* Pointer to a null-terminated string containing a
+* comma-separated list of attribute settings.
+* text
+* Pointer to a location at which to return a pointer to dynamic
+* memory holding a copy of the expanded setting string. This memory
+* should be freed using astFree when no longer needed. If a NULL
+* pointer is supplied, no string is created.
+* args
+* The variable argument list which contains values to be
+* substituted for any "printf"-style format specifiers that
+* appear in the "settings" string.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - This function preserves the integrity of the FrameSet (if
+* possible) by appropriately remapping its current Frame to take
+* account of its changed attribute values.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstFrame *save_frame; /* Saved pointer to integrity Frame */
+ AstFrameSet *this; /* Pointer to FrameSet structure */
+ char *fulltext; /* Pointer to expanded text string */
+ const char *save_method; /* Saved pointer to method name */
+ int len; /* Length of settings string */
+ int ok; /* Status OK? */
+ int save_lost; /* Saved integrity modified flag */
+
+/* Initialise */
+ if( text ) *text = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_object);
+
+/* Obtain the length of the "settings" string and test it is not
+ zero. If it is, there is nothing more to do. */
+ len = (int) strlen( settings );
+ if ( len != 0 ) {
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* This function may be invoked recursively (because astConvert,
+ below, constructs a FrameSet and may require that its attributes be
+ set). To allow this, we first save any existing FrameSet integrity
+ information in local variables. */
+ save_frame = integrity_frame;
+ save_lost = integrity_lost;
+ save_method = integrity_method;
+
+/* Set the name of the method being used (for use in error
+ messages). */
+ integrity_method = "astSet";
+
+/* Record the initial integrity state of the FrameSet. */
+ RecordIntegrity( this, status );
+
+/* Invoke the parent astVSet method to set the FrameSet's attribute
+ values and note if this succeeds. */
+ (*parent_vset)( this_object, settings, &fulltext, args, status );
+ ok = astOK;
+
+/* Restore the FrameSet's integrity. */
+ RestoreIntegrity( this, status );
+
+/* If integrity could not be restored, then add contextual error
+ information. */
+ if ( !astOK && ok ) {
+
+/* Display the message. */
+ astError( astStatus, "Unable to accommodate the attribute setting "
+ "\"%s\".", status, fulltext );
+ }
+
+/* Restore any saved FrameSet integrity information. */
+ integrity_frame = save_frame;
+ integrity_lost = save_lost;
+ integrity_method = save_method;
+
+/* If the full text of the setting string is not needed, free it.
+ Otherwise return it. */
+ if( text ) {
+ *text = fulltext;
+ } else {
+ fulltext = astFree( fulltext );
+ }
+ }
+}
+
+/* FrameSet Attributes. */
+/* -------------------- */
+/*
+*att++
+* Name:
+* AllVariants
+
+* Purpose:
+* A list of the variant Mappings associated with the current Frame.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String, read-only.
+
+* Description:
+* This attribute gives a space separated list of the names of all the
+* variant Mappings associated with the current Frame (see attribute
+* "Variant"). If the current Frame has no variant Mappings, then the
+* list will hold a single entry equal to the Domain name of the
+* current Frame.
+
+* Applicability:
+* FrameSet
+* All FrameSets have this attribute.
+*att--
+*/
+
+/*
+*att++
+* Name:
+* Base
+
+* Purpose:
+* FrameSet base Frame index.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer.
+
+* Description:
+* This attribute gives the index of the Frame which is to be
+* regarded as the "base" Frame within a FrameSet. The default is
+* the first Frame added to the FrameSet when it is created (this
+* Frame always has an index of 1).
+*
+* When setting a new value for this attribute, a string may be
+* supplied instead of an integer index. In this case a search
+* is made within the FrameSet for a Frame that has its Domain
+* attribute value equal to the supplied string (the comparison is
+* case-insensitive). If found, the Frame is made the base Frame.
+* Otherwise an error is reported.
+
+* Applicability:
+* FrameSet
+* All FrameSets have this attribute.
+
+* Notes:
+* - Inverting a FrameSet (inverting the boolean sense of its
+c Invert attribute, with the astInvert function for example) will
+f Invert attribute, with the AST_INVERT routine for example) will
+* interchange the values of its Base and Current attributes.
+*att--
+*/
+
+/*
+*att++
+* Name:
+* Current
+
+* Purpose:
+* FrameSet current Frame index.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer.
+
+* Description:
+* This attribute gives the index of the Frame which is to be
+* regarded as the "current" Frame within a FrameSet. The default
+* is the most recent Frame added to the FrameSet (this Frame
+* always has an index equal to the FrameSet's Nframe attribute).
+*
+* When setting a new value for this attribute, a string may be
+* supplied instead of an integer index. In this case a search
+* is made within the FrameSet for a Frame that has its Domain
+* attribute value equal to the supplied string (the comparison is
+* case-insensitive). If found, the Frame is made the current Frame.
+* Otherwise an error is reported.
+
+* Applicability:
+* FrameSet
+* All FrameSets have this attribute.
+
+* Notes:
+* - Inverting a FrameSet (inverting the boolean sense of its
+c Invert attribute, with the astInvert function for example) will
+f Invert attribute, with the AST_INVERT routine for example) will
+* interchange the values of its Base and Current attributes.
+*att--
+*/
+
+/*
+*att++
+* Name:
+* Nframe
+
+* Purpose:
+* Number of Frames in a FrameSet.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer, read-only.
+
+* Description:
+* This attribute gives the number of Frames in a FrameSet. This
+* value will change as Frames are added or removed, but will
+* always be at least one.
+
+* Applicability:
+* FrameSet
+* All FrameSets have this attribute.
+*att--
+*/
+
+/*
+*att++
+* Name:
+* Variant
+
+* Purpose:
+* Indicates which variant of the current Frame is to be used.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute can be used to change the Mapping that connects the
+* current Frame to the other Frames in the FrameSet. By default, each
+* Frame in a FrameSet is connected to the other Frames by a single
+* Mapping that can only be changed by using the
+c astRemapFrame
+f AST_REMAPFRAME
+* method. However, it is also possible to associate multiple Mappings
+* with a Frame, each Mapping having an identifying name. If this is
+* done, the "Variant" attribute can be set to indicate the name of
+* the Mapping that is to be used with the current Frame.
+*
+* A possible (if unlikely) use-case is to create a FrameSet that can
+* be used to describe the WCS of an image formed by co-adding images
+* of two different parts of the sky. In such an image, each pixel contains
+* flux from two points on the sky.and so the WCS for the image should
+* ideally contain one pixel Frame and two SkyFrames - one describing
+* each of the two co-added images. There is nothing to prevent a
+* FrameSet containing two explicit SkyFrames, but the problem then arises
+* of how to distinguish between them. The two primary characteristics of
+* a Frame that distinguishes it from other Frames are its class and its
+* Domain attribute value. The class of a Frame cannot be changed, but we
+* could in principle use two different Domain values to distinguish the
+* two SkyFrames. However, in practice it is not uncommon for application
+* software to assume that SkyFrames will have the default Domain value
+* of "SKY". That is, instead of searching for Frames that have a class
+* of "SkyFrame", such software searches for Frames that have a Domain
+* of "SKY". To alleviate this problem, it is possible to add a single
+* SkyFrame to the FrameSet, but specifying two alternate Mappings to
+* use with the SkyFrame. Setting the "Variant" attribute to the name
+* of one or the other of these alternate Mappings will cause the
+* SkyFrame to be remapped within the FrameSet so that it uses the
+* specified Mapping. The same facility can be used with any class of
+* Frame, not just SkyFrames.
+*
+* To use this facility, the Frame should first be added to the
+* FrameSet in the usual manner using the
+c astAddFrame method. By default, the Mapping supplied to astAddFrame
+f AST_ADDFRAME method. By default, the Mapping supplied to AST_ADDVARIANT
+* is assigned a name equal to the Domain name of the Frame. To assign a
+* different name to it, the
+c astAddVariant
+f AST_ADDVARIANT
+* method should then be called specifying the required name and a NULL
+* Mapping. The
+c astAddVariant
+f AST_ADDVARIANT
+* method should then be called repeatedly to add each required extra
+* Mapping to the current Frame, supplying a unique name for each one.
+*
+* Each Frame in a FrameSet can have its own set of variant Mappings.
+* To control the Mappings in use with a specific Frame, you need first
+* to make it the current Frame in the FrameSet.
+*
+* The
+c astMirrorVariants function
+f AST_MIRRORVARIANTS routine
+* allows the effects of variant Mappings associated with a nominated
+* Frame to be propagated to other Frames in the FrameSet.
+*
+* Once this has been done, setting a new value for the "Variant"
+* attribute of a FrameSet will cause the current Frame in the
+* FrameSet to be remapped to use the specified variant Mapping. An
+* error will be reported if the current Frame has no variant Mapping
+* with the supplied name.
+*
+* Getting the value of the "Variant" attribute will return the name
+* of the variant Mapping currently in use with the current Frame. If
+* the Frame has no variant Mappings, the value will default to the
+* Domain name of the current Frame.
+*
+* Clearing the "Variant" attribute will have the effect of removing
+* all variant Mappings (except for the currently selected Mapping) from
+* the current Frame.
+*
+* Testing the "Variant" attribute will return
+c a non-zero value
+f .TRUE.
+* if the current Frame contains any variant Mappings, and
+c zero
+f .FALSE.
+* otherwise.
+*
+* A complete list of the names associated with all the available
+* variant Mappings in the current Frame can be obtained from the
+* AllVariants attribute.
+*
+* If a Frame with variant Mappings is remapped using the
+c astRemapFrame
+f AST_REMAPFRAME
+* method, the currently selected variant Mapping is used by
+c astRemapFrame
+f AST_REMAPFRAME
+* and the other variant Mappings are removed from the Frame.
+
+* Applicability:
+* FrameSet
+* All FrameSets have this attribute.
+*att--
+*/
+
+/* Access to attributes of the current Frame. */
+/* ------------------------------------------ */
+/* Use the macros defined at the start of this file to implement
+ private member functions that give access to the attributes of the
+ current Frame of a FrameSet and its axes. These functions over-ride
+ the attribute access methods inherited from the Frame class. */
+
+/* Clear, Get, Set and Test axis-independent Frame attributes. */
+MAKE_CLEAR(Digits)
+MAKE_CLEAR(Domain)
+MAKE_CLEAR(MatchEnd)
+MAKE_CLEAR(MaxAxes)
+MAKE_CLEAR(MinAxes)
+MAKE_CLEAR(Permute)
+MAKE_CLEAR(PreserveAxes)
+MAKE_CLEAR(Title)
+
+MAKE_GET(Digits,int)
+MAKE_GET(Domain,const char *)
+MAKE_GET(MatchEnd,int)
+MAKE_GET(MaxAxes,int)
+MAKE_GET(MinAxes,int)
+MAKE_GET(Permute,int)
+MAKE_GET(PreserveAxes,int)
+MAKE_GET(Title,const char *)
+MAKE_SET(Digits,int)
+MAKE_SET(Domain,const char *)
+MAKE_SET(MatchEnd,int)
+MAKE_SET(MaxAxes,int)
+MAKE_SET(MinAxes,int)
+MAKE_SET(Permute,int)
+MAKE_SET(PreserveAxes,int)
+MAKE_SET(Title,const char *)
+MAKE_TEST(Digits)
+MAKE_TEST(Domain)
+MAKE_TEST(MatchEnd)
+MAKE_TEST(MaxAxes)
+MAKE_TEST(MinAxes)
+MAKE_TEST(Permute)
+MAKE_TEST(PreserveAxes)
+MAKE_TEST(Title)
+
+MAKE_GET(ActiveUnit,int)
+MAKE_SET(ActiveUnit,int)
+MAKE_TEST(ActiveUnit)
+
+MAKE_GET(System,AstSystemType)
+MAKE_SET(System,AstSystemType)
+MAKE_TEST(System)
+MAKE_CLEAR(System)
+
+MAKE_GET(AlignSystem,AstSystemType)
+MAKE_SET(AlignSystem,AstSystemType)
+MAKE_TEST(AlignSystem)
+MAKE_CLEAR(AlignSystem)
+
+MAKE_GET(Epoch,double)
+MAKE_SET(Epoch,double)
+MAKE_TEST(Epoch)
+MAKE_CLEAR(Epoch)
+
+MAKE_GET(Dtai,double)
+MAKE_SET(Dtai,double)
+MAKE_TEST(Dtai)
+MAKE_CLEAR(Dtai)
+
+MAKE_GET(Dut1,double)
+MAKE_SET(Dut1,double)
+MAKE_TEST(Dut1)
+MAKE_CLEAR(Dut1)
+
+MAKE_GET(ObsLon,double)
+MAKE_SET(ObsLon,double)
+MAKE_TEST(ObsLon)
+MAKE_CLEAR(ObsLon)
+
+MAKE_GET(ObsLat,double)
+MAKE_SET(ObsLat,double)
+MAKE_TEST(ObsLat)
+MAKE_CLEAR(ObsLat)
+
+MAKE_GET(ObsAlt,double)
+MAKE_SET(ObsAlt,double)
+MAKE_TEST(ObsAlt)
+MAKE_CLEAR(ObsAlt)
+
+/* Clear, Get, Set and Test axis-dependent Frame attributes. */
+MAKE_CLEAR_AXIS(Direction)
+MAKE_CLEAR_AXIS(Format)
+MAKE_CLEAR_AXIS(Label)
+MAKE_CLEAR_AXIS(Symbol)
+MAKE_CLEAR_AXIS(Unit)
+MAKE_GET_AXIS(Direction,int)
+MAKE_GET_AXIS(Format,const char *)
+MAKE_GET_AXIS(Label,const char *)
+MAKE_GET_AXIS(Symbol,const char *)
+MAKE_GET_AXIS(Unit,const char *)
+MAKE_SET_AXIS(Direction,int)
+MAKE_SET_AXIS(Format,const char *)
+MAKE_SET_AXIS(Label,const char *)
+MAKE_SET_AXIS(Symbol,const char *)
+MAKE_SET_AXIS(Unit,const char *)
+MAKE_TEST_AXIS(Direction)
+MAKE_TEST_AXIS(Format)
+MAKE_TEST_AXIS(Label)
+MAKE_TEST_AXIS(Symbol)
+MAKE_TEST_AXIS(Unit)
+
+MAKE_GET_AXIS(Bottom,double)
+MAKE_SET_AXIS(Bottom,double)
+MAKE_TEST_AXIS(Bottom)
+MAKE_CLEAR_AXIS(Bottom)
+
+MAKE_GET_AXIS(Top,double)
+MAKE_SET_AXIS(Top,double)
+MAKE_TEST_AXIS(Top)
+MAKE_CLEAR_AXIS(Top)
+
+/* Copy constructor. */
+/* ----------------- */
+static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
+/*
+* Name:
+* Copy
+
+* Purpose:
+* Copy constructor for FrameSet objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Copy( const AstObject *objin, AstObject *objout, int *status )
+
+* Description:
+* This function implements the copy constructor for FrameSet 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: */
+ AstFrameSet *in; /* Pointer to input FrameSet */
+ AstFrameSet *out; /* Pointer to output FrameSet */
+ int iframe; /* Loop counter for Frames */
+ int inode; /* Loop counter for nodes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain pointers to the input and output FrameSets. */
+ in = (AstFrameSet *) objin;
+ out = (AstFrameSet *) objout;
+
+/* For safety, first clear any references to the input memory from
+ the output FrameSet. */
+ out->frame = NULL;
+ out->varfrm = NULL;
+ out->node = NULL;
+ out->map = NULL;
+ out->link = NULL;
+ out->invert = NULL;
+
+/* Allocate memory in the output FrameSet to store the Frame and node
+ information and copy scalar information across. */
+ out->frame = astMalloc( sizeof( AstFrame * ) * (size_t) in->nframe );
+ out->varfrm = astStore( NULL, in->varfrm, sizeof( int ) *
+ (size_t) in->nframe );
+ out->node = astStore( NULL, in->node, sizeof( int ) *
+ (size_t) in->nframe );
+ out->map = astMalloc( sizeof( AstMapping * ) * (size_t) ( in->nnode - 1 ) );
+ out->link = astStore( NULL, in->link, sizeof( int ) *
+ (size_t) ( in->nnode - 1 ) );
+ out->invert = astStore( NULL, in->invert, sizeof( int ) *
+ (size_t) ( in->nnode - 1 ) );
+
+/* If OK, make copies of each input Frame and Mapping and store the
+ resulting pointers in the output FrameSet. */
+ if ( astOK ) {
+ for ( iframe = 0; iframe < in->nframe; iframe++ ) {
+ out->frame[ iframe ] = astCopy( in->frame[ iframe ] );
+ }
+ for ( inode = 0; inode < in->nnode - 1; inode++ ) {
+ out->map[ inode ] = astCopy( in->map[ inode ] );
+ }
+
+/* If an error occurred while copying any of these objects, clean up
+ by looping through the arrays of pointers again and annulling them
+ all. */
+ if ( !astOK ) {
+ for ( iframe = 0; iframe < in->nframe; iframe++ ) {
+ out->frame[ iframe ] = astAnnul( out->frame[ iframe ] );
+ }
+ for ( inode = 0; inode < in->nnode - 1; inode++ ) {
+ out->map[ inode ] = astAnnul( out->map[ inode ] );
+ }
+ }
+ }
+
+/* If an error occurred, clean up by freeing all memory allocated above. */
+ if ( !astOK ) {
+ out->frame = astFree( out->frame );
+ out->varfrm = astFree( out->varfrm );
+ out->node = astFree( out->node );
+ out->map = astFree( out->map );
+ out->link = astFree( out->link );
+ out->invert = astFree( out->invert );
+ }
+}
+
+/* Destructor. */
+/* ----------- */
+static void Delete( AstObject *obj, int *status ) {
+/*
+* Name:
+* Delete
+
+* Purpose:
+* Destructor for FrameSet objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Delete( AstObject *obj, int *status )
+
+* Description:
+* This function implements the destructor for FrameSet 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: */
+ AstFrameSet *this; /* Pointer to FrameSet */
+ int iframe; /* Loop counter for Frames */
+ int inode; /* Loop counter for nodes */
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) obj;
+
+/* Annul all Frame pointers and clear the node numbers associated with
+ them. */
+ for ( iframe = 0; iframe < this->nframe; iframe++ ) {
+ this->frame[ iframe ] = astAnnul( this->frame[ iframe ] );
+ this->node[ iframe ] = 0;
+ }
+
+/* Annul all Mapping pointers and clear the links between pairs of
+ nodes and the associated Mapping Invert information. */
+ for ( inode = 0; inode < this->nnode - 1; inode++ ) {
+ this->map[ inode ] = astAnnul( this->map[ inode ] );
+ this->link[ inode ] = 0;
+ this->invert[ inode ] = 0;
+ }
+
+/* Free all allocated memory. */
+ this->frame = astFree( this->frame );
+ this->varfrm = astFree( this->varfrm );
+ this->node = astFree( this->node );
+ this->map = astFree( this->map );
+ this->link = astFree( this->link );
+ this->invert = astFree( this->invert );
+}
+
+/* Dump function. */
+/* -------------- */
+static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
+/*
+* Name:
+* Dump
+
+* Purpose:
+* Dump function for FrameSet 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 FrameSet class to an output Channel.
+
+* Parameters:
+* this
+* Pointer to the FrameSet 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: */
+ AstFrameSet *this; /* Pointer to the FrameSet structure */
+ char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment string */
+ char key[ KEY_LEN + 1 ]; /* Buffer for keyword string */
+ int ifr; /* Loop counter for Frames */
+ int inode; /* Loop counter for nodes */
+ int invert; /* Invert attribute value */
+ int ival; /* Integer value */
+ int set; /* Attribute value set? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the FrameSet structure. */
+ this = (AstFrameSet *) this_object;
+
+/* Determine if the FrameSet is inverted. This is required so that the
+ effects of inversion can be un-done to obtain information about the
+ "true" Base and Current Frames. (The values written are "internal"
+ values that are not affected by the Invert setting.) */
+ invert = astGetInvert( this );
+
+/* Write out values representing the instance variables for the
+ FrameSet 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. */
+
+/* Nframe. */
+/* ------- */
+ set = ( this->nframe != 0 );
+ ival = set ? this->nframe : astGetNframe( this );
+ astWriteInt( channel, "Nframe", set, 1, ival,
+ "Number of Frames in FrameSet" );
+
+/* Base. */
+/* ----- */
+ set = ( this->base != -INT_MAX );
+ ival = set ? this->base : ( !invert ? astGetBase( this ) :
+ astGetCurrent( this ) );
+ astWriteInt( channel, "Base", set, 1, ival, "Index of base Frame" );
+
+/* Current. */
+/* -------- */
+ set = ( this->current != -INT_MAX );
+ ival = set ? this->current : ( !invert ? astGetCurrent( this ) :
+ astGetBase( this ) );
+ astWriteInt( channel, "Currnt", set, 1, ival, "Index of current Frame" );
+
+/* Number of nodes. */
+/* ---------------- */
+ ival = this->nnode;
+ set = ( ival != this->nframe );
+ astWriteInt( channel, "Nnode", set, 0, ival,
+ "Number of nodes in FrameSet" );
+
+/* Node index for each Frame. */
+/* -------------------------- */
+/* There is a node value for each Frame in the FrameSet. */
+ for ( ifr = 1; ifr <= this->nframe; ifr++ ) {
+
+/* Convert node numbering to start at 1 for the external
+ representation. Regard a node number as "set" if it differs from
+ the Frame number. */
+ ival = this->node[ ifr - 1 ] + 1;
+ set = ( ival != ifr );
+
+/* Create a suitable keyword and comment. */
+ (void) sprintf( key, "Nod%d", ifr );
+ (void) sprintf( comment,
+ "Frame %d is associated with node %d", ifr, ival );
+
+/* Write out the value. */
+ astWriteInt( channel, key, set, 0, ival, comment );
+ }
+
+/* Index of variants Frame for each Frame. */
+/* --------------------------------------- */
+ for ( ifr = 1; ifr <= this->nframe; ifr++ ) {
+
+/* Retain the one-based Frame index values in varfrm. Regard a number as
+ "set" if it is greater than zero. */
+ ival = this->varfrm[ ifr - 1 ];
+ set = ( ival > 0 );
+
+/* Create a suitable keyword and comment. */
+ (void) sprintf( key, "VFr%d", ifr );
+ (void) sprintf( comment,
+ "Frame %d inherits variants from Frame %d", ifr, ival );
+
+/* Write out the value. */
+ astWriteInt( channel, key, set, 0, ival, comment );
+ }
+
+/* Links between nodes. */
+/* -------------------- */
+/* Each node in the FrameSet (except the first) has a link to another
+ node from which it is derived. */
+ for ( inode = 1; inode < this->nnode; inode++ ) {
+
+/* Convert node numbering to start at 1 (as above). */
+ ival = this->link[ inode - 1 ] + 1;
+ (void) sprintf( key, "Lnk%d", inode + 1 );
+ (void) sprintf( comment,
+ "Node %d is derived from node %d", inode + 1, ival );
+ astWriteInt( channel, key, 1, 0, ival, comment );
+
+/* Inversion flags. */
+/* ---------------- */
+/* Each node with a link has a value which the Invert attribute of the
+ associated Mapping should have when the transformation from the
+ parent node to the node in question is required. */
+ ival = this->invert[ inode - 1 ];
+
+/* Regard the value as set only if the Mapping's inverse
+ transformation is required. */
+ set = ( ival != 0 );
+ (void) sprintf( key, "Inv%d", inode + 1 );
+ astWriteInt( channel, key, set, 0, ival,
+ ival ? "The inverse mapping is used" :
+ "The forward mapping is used" );
+ }
+
+/* Frame objects. */
+/* -------------- */
+/* Output an Object description for each Frame in the FrameSet. */
+ for ( ifr = 1; ifr <= this->nframe; ifr++ ) {
+ (void) sprintf( key, "Frm%d", ifr );
+ (void) sprintf( comment, "Frame number %d", ifr );
+ astWriteObject( channel, key, 1, 1, this->frame[ ifr - 1 ],
+ comment );
+ }
+
+/* Mapping objects. */
+/* ---------------- */
+/* Output an Object description for each Mapping in the FrameSet. */
+ for ( inode = 1; inode < this->nnode; inode++ ) {
+ (void) sprintf( key, "Map%d", inode + 1 );
+ (void) sprintf( comment, "Mapping between nodes %d and %d",
+ this->link[ inode - 1 ] + 1, inode + 1 );
+ astWriteObject( channel, key, 1, 1, this->map[ inode - 1 ], comment );
+ }
+
+/* Undefine macros local to this function. */
+#undef COMMENT_LEN
+#undef KEY_LEN
+}
+
+/* Standard class functions. */
+/* ========================= */
+/* Implement the astIsAFrameSet and astCheckFrameSet functions using
+ the macros defined for this purpose in the "object.h" header
+ file. */
+astMAKE_ISA(FrameSet,Frame)
+astMAKE_CHECK(FrameSet)
+
+AstFrameSet *astFrameSet_( void *frame_void, const char *options, int *status, ...) {
+/*
+*+
+* Name:
+* astFrameSet
+
+* Purpose:
+* Create a FrameSet.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstFrameSet *astFrameSet( AstFrame *frame, const char *options, int *status, ... )
+
+* Class Membership:
+* FrameSet constructor.
+
+* Description:
+* This function creates a new FrameSet and optionally initialises
+* its attributes.
+
+* Parameters:
+* frame
+* Pointer to the initial Frame. If this is not a FrameSet, the
+* new FrameSet will be initialised to contain this Frame alone.
+*
+* If it is a FrameSet, the new FrameSet will be initialised to
+* contain the same Frames (and Mappings) and to have the same
+* attribute values as the one supplied. This is similar to
+* making a copy, except that the Frames (and Mappings)
+* contained in the original FrameSet are not themselves copied,
+* but are shared by both FrameSets.
+* options
+* Pointer to a null terminated string containing an optional
+* comma-separated list of attribute assignments to be used for
+* initialising the new FrameSet. The syntax used is the same as
+* for the astSet method and may include "printf" format
+* specifiers identified by "%" symbols in the normal way.
+* status
+* Pointer to the inherited status variable.
+* ...
+* If the "options" string contains "%" format specifiers, then
+* an optional list of arguments may follow it in order to
+* supply values to be substituted for these specifiers. The
+* rules for supplying these are identical to those for the
+* astSet method (and for the C "printf" function).
+
+* Returned Value:
+* A pointer to the new FrameSet.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+
+* Implementation Notes:
+* - This function implements the basic FrameSet constructor which
+* is available via the protected interface to the FrameSet class.
+* A public interface is provided by the astFrameSetId_ function.
+* - Because this function has a variable argument list, it is
+* invoked by a macro that evaluates to a function pointer (not a
+* function invocation) and no checking or casting of arguments is
+* performed before the function is invoked. Because of this, the
+* "frame" parameter is of type (void *) and is converted and
+* validated within the function itself.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstFrame *frame; /* Pointer to Frame structure */
+ AstFrameSet *new; /* Pointer to new FrameSet */
+ va_list args; /* Variable argument list */
+
+/* Initialise. */
+ new = NULL;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Check the global status. */
+ if ( !astOK ) return new;
+
+/* Obtain and validate a pointer to the Frame structure provided. */
+ frame = astCheckFrame( frame_void );
+ if ( astOK ) {
+
+/* Initialise the FrameSet, allocating memory and initialising the
+ virtual function table as well if necessary. */
+ new = astInitFrameSet( NULL, sizeof( AstFrameSet ), !class_init,
+ &class_vtab, "FrameSet", frame );
+
+/* If successful, note that the virtual function table has been
+ initialised. */
+ if ( astOK ) {
+ class_init = 1;
+
+/* Obtain the variable argument list and pass it along with the
+ options string to the astVSet method to initialise the new
+ FrameSet'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 FrameSet. */
+ return new;
+}
+
+AstFrameSet *astInitFrameSet_( void *mem, size_t size, int init,
+ AstFrameSetVtab *vtab, const char *name,
+ AstFrame *frame, int *status ) {
+/*
+*+
+* Name:
+* astInitFrameSet
+
+* Purpose:
+* Initialise a FrameSet.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstFrameSet *astInitFrameSet( void *mem, size_t size, int init,
+* AstFrameSetVtab *vtab, const char *name,
+* AstFrame *frame )
+
+* Class Membership:
+* FrameSet initialiser.
+
+* Description:
+* This function is provided for use by class implementations to
+* initialise a new FrameSet object. It allocates memory (if
+* necessary) to accommodate the FrameSet plus any additional data
+* associated with the derived class. It then initialises a
+* FrameSet 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 FrameSet at the start of the memory passed
+* via the "vtab" parameter.
+
+* Parameters:
+* mem
+* A pointer to the memory in which the FrameSet is to be
+* created. This must be of sufficient size to accommodate the
+* FrameSet data (sizeof(FrameSet)) 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 FrameSet (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 FrameSet structure, so a valid value must be
+* supplied even if not required for allocating memory.
+* init
+* A logical flag indicating if the FrameSet'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 FrameSet.
+* name
+* Pointer to a constant null-terminated character string which
+* contains the name of the class to which the new object
+* belongs (it is this pointer value that will subsequently be
+* returned by the astGetClass method).
+* frame
+* Pointer to the initial Frame (or FrameSet).
+
+* Returned Value:
+* A pointer to the new FrameSet.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ AstFrameSet *new; /* Pointer to new FrameSet */
+ AstFrameSet *old; /* Pointer to original FrameSet */
+ int iframe; /* Loop counter for Frames */
+ int inode; /* Loop counter for nodes */
+
+/* Check the global status. */
+ if ( !astOK ) return NULL;
+
+/* If necessary, initialise the virtual function table. */
+ if ( init ) astInitFrameSetVtab( vtab, name );
+
+/* Initialise a Frame structure (the parent class) as the first
+ component within the FrameSet structure, allocating memory if
+ necessary. Give this Frame zero axes, as all axis information for
+ the FrameSet will be derived from the Frames it contains. */
+ new = (AstFrameSet *) astInitFrame( mem, size, 0,
+ (AstFrameVtab *) vtab, name, 0 );
+
+ if ( astOK ) {
+
+/* Initialise the FrameSet data. */
+/* ----------------------------- */
+
+/* Normal Frame supplied. */
+/* ---------------------- */
+/* Check that the Frame supplied is not a FrameSet (initialising using
+ a FrameSet is a special case which is handled below). If not, we
+ initialise the new FrameSet to refer to a single Frame. */
+ if ( !astIsAFrameSet( frame ) && astOK ) {
+
+/* Allocate memory for the arrays of Frame information. */
+ new->frame = astMalloc( sizeof( AstFrame * ) );
+ new->node = astMalloc( sizeof( int ) );
+ new->varfrm = astMalloc( sizeof( int ) );
+
+/* The node arrays are not required until at least two Frames are
+ present. */
+ new->map = NULL;
+ new->link = NULL;
+ new->invert = NULL;
+
+/* If OK, initialise these arrays, thus adding the Frame to the
+ FrameSet. */
+ if ( astOK ) {
+ new->frame[ 0 ] = astClone( frame );
+ new->node[ 0 ] = 0;
+ new->varfrm[ 0 ] = 0;
+ new->nframe = 1;
+ new->nnode = 1;
+
+/* Initialise the FrameSet attributes to their undefined states. */
+ new->base = -INT_MAX;
+ new->current = -INT_MAX;
+ }
+
+/* FrameSet supplied. */
+/* ------------------ */
+/* If a FrameSet was supplied, we will initialise the new FrameSet to
+ refer to the same Frame and Mapping information (this is similar to
+ making a copy, except that we clone all the pointers, instead of
+ copying the Objects they refer to). */
+ } else if ( astOK ) {
+
+/* Obtain a pointer to the original FrameSet structure. */
+ old = (AstFrameSet *) frame;
+
+/* Allocate memory in the new FrameSet to store the Frame and node
+ information and copy any scalar information across. */
+ new->frame = astMalloc( sizeof( AstFrame * ) * (size_t) old->nframe );
+ new->node = astStore( NULL, old->node,
+ sizeof( int ) * (size_t) old->nframe );
+ new->varfrm = astStore( NULL, old->varfrm,
+ sizeof( int ) * (size_t) old->nframe );
+ new->map = astMalloc( sizeof( AstMapping * ) *
+ (size_t) ( old->nnode - 1 ) );
+ new->link = astStore( NULL, old->link,
+ sizeof( int ) * (size_t) ( old->nnode - 1 ) );
+ new->invert = astStore( NULL, old->invert,
+ sizeof( int ) * (size_t) ( old->nnode - 1 ) );
+
+/* If OK, clone the pointer to each Frame and Mapping referenced by
+ the original FrameSet and store the resulting pointers in the new
+ FrameSet. */
+ if ( astOK ) {
+ for ( iframe = 0; iframe < old->nframe; iframe++ ) {
+ new->frame[ iframe ] = astClone( old->frame[ iframe ] );
+ }
+ for ( inode = 0; inode < old->nnode - 1; inode++ ) {
+ new->map[ inode ] = astClone( old->map[ inode ] );
+ }
+
+/* If an error occurred while cloning any of these pointers, clean up
+ by looping through the arrays of cloned pointers again and
+ annulling them all. */
+ if ( !astOK ) {
+ for ( iframe = 0; iframe < old->nframe; iframe++ ) {
+ new->frame[ iframe ] = astAnnul( new->frame[ iframe ] );
+ }
+ for ( inode = 0; inode < old->nnode - 1; inode++ ) {
+ new->map[ inode ] = astAnnul( new->map[ inode ] );
+ }
+ }
+ }
+
+/* If an error occurred, clean up by freeing all memory allocated
+ above. */
+ if ( !astOK ) {
+ new->frame = astFree( new->frame );
+ new->node = astFree( new->node );
+ new->varfrm = astFree( new->varfrm );
+ new->map = astFree( new->map );
+ new->link = astFree( new->link );
+ new->invert = astFree( new->invert );
+ }
+
+/* Copy the Frame and node counts across. */
+ new->nframe = old->nframe;
+ new->nnode = old->nnode;
+
+/* Copy the other FrameSet attributes across. */
+ new->base = old->base;
+ new->current = old->current;
+
+/* Transfer any other inherited attribute values that relate to the
+ FrameSet itself (rather than the enclosed Frames). */
+ if ( astTestInvert( old ) ) astSetInvert( new, astGetInvert( old ) );
+ }
+
+/* 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;
+
+/* Undefine macros local to this function. */
+#undef TRANSFER
+}
+
+AstFrameSet *astLoadFrameSet_( void *mem, size_t size,
+ AstFrameSetVtab *vtab, const char *name,
+ AstChannel *channel, int *status ) {
+/*
+*+
+* Name:
+* astLoadFrameSet
+
+* Purpose:
+* Load a FrameSet.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frameset.h"
+* AstFrameSet *astLoadFrameSet( void *mem, size_t size,
+* AstFrameSetVtab *vtab, const char *name,
+* AstChannel *channel )
+
+* Class Membership:
+* FrameSet loader.
+
+* Description:
+* This function is provided to load a new FrameSet 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
+* FrameSet structure in this memory, using data read from the
+* input Channel.
+
+* Parameters:
+* mem
+* A pointer to the memory into which the FrameSet is to be
+* loaded. This must be of sufficient size to accommodate the
+* FrameSet data (sizeof(FrameSet)) 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 FrameSet (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 FrameSet 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(AstFrameSet) is used instead.
+* vtab
+* Pointer to the start of the virtual function table to be
+* associated with the new FrameSet. If this is NULL, a pointer
+* to the (static) virtual function table for the FrameSet 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 "FrameSet" is used instead.
+
+* Returned Value:
+* A pointer to the new FrameSet.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Constants: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+#define KEY_LEN 50 /* Maximum length of a keyword */
+
+/* Local Variables: */
+ AstFrameSet *new; /* Pointer to the new FrameSet */
+ char key[ KEY_LEN + 1 ]; /* Buffer for keyword string */
+ int ifr; /* Get a pointer to the thread specific global data structure. */
+
+/* Loop counter for Frames */
+ int inode; /* Loop counter for nodes */
+
+ 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 FrameSet. In this case the
+ FrameSet belongs to this class, so supply appropriate values to be
+ passed to the parent class loader (and its parent, etc.). */
+ if ( !vtab ) {
+ size = sizeof( AstFrameSet );
+ vtab = &class_vtab;
+ name = "FrameSet";
+
+/* If required, initialise the virtual function table for this class. */
+ if ( !class_init ) {
+ astInitFrameSetVtab( 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 FrameSet. */
+ 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, "FrameSet" );
+
+/* 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. */
+
+/* Nframe. */
+/* ------- */
+ new->nframe = astReadInt( channel, "nframe", 1 );
+ if ( new->nframe < 0 ) new->nframe = 1;
+
+/* Number of nodes. */
+/* ---------------- */
+ new->nnode = astReadInt( channel, "nnode", new->nframe );
+ if ( new->nnode < 1 ) new->nnode = 1;
+
+/* Allocate memory to hold Frame and node information. */
+ new->frame = astMalloc( sizeof( AstFrame *) * (size_t) new->nframe );
+ new->node = astMalloc( sizeof( int ) * (size_t) new->nframe );
+ new->varfrm = astMalloc( sizeof( int ) * (size_t) new->nframe );
+ new->link = astMalloc( sizeof( int ) * (size_t) ( new->nnode - 1 ) );
+ new->invert = astMalloc( sizeof( int ) * (size_t) ( new->nnode - 1 ) );
+ new->map = astMalloc( sizeof( AstMapping * ) *
+ (size_t) ( new->nnode - 1 ) );
+
+/* If an error occurs, ensure that all allocated memory is freed. */
+ if ( !astOK ) {
+ new->frame = astFree( new->frame );
+ new->node = astFree( new->node );
+ new->varfrm = astFree( new->varfrm );
+ new->link = astFree( new->link );
+ new->invert = astFree( new->invert );
+ new->map = astFree( new->map );
+
+/* Otherwise, initialise the arrays which will hold Object pointers. */
+ } else {
+ for ( ifr = 1; ifr <= new->nframe; ifr++ ) {
+ new->frame[ ifr - 1 ] = NULL;
+ }
+ for ( inode = 1; inode < new->nnode; inode++ ) {
+ new->map[ inode - 1 ] = NULL;
+ }
+
+/* Read Frame data... */
+ for ( ifr = 1; ifr <= new->nframe; ifr++ ) {
+
+/* Frame objects. */
+/* -------------- */
+/* Create the required keyword and then read the Frame. */
+ (void) sprintf( key, "frm%d", ifr );
+ new->frame[ ifr - 1 ] = astReadObject( channel, key, NULL );
+
+/* Node index for each Frame. */
+/* -------------------------- */
+ (void) sprintf( key, "nod%d", ifr );
+ new->node[ ifr - 1 ] = astReadInt( channel, key, ifr ) - 1;
+
+/* Index of variants Frame. */
+/* ------------------------ */
+ (void) sprintf( key, "vfr%d", ifr );
+ new->varfrm[ ifr - 1 ] = astReadInt( channel, key, 0 );
+ }
+
+/* Read node data... */
+ for ( inode = 1; inode < new->nnode; inode++ ) {
+
+/* Links between nodes. */
+/* -------------------- */
+ (void) sprintf( key, "lnk%d", inode + 1 );
+ new->link[ inode - 1 ] = astReadInt( channel, key, 0 ) - 1;
+
+/* Inversion flags. */
+/* ---------------- */
+ (void) sprintf( key, "inv%d", inode + 1 );
+ new->invert[ inode - 1 ] = astReadInt( channel, key, 0 );
+
+/* Mapping objects. */
+/* ---------------- */
+ (void) sprintf( key, "map%d", inode + 1 );
+ new->map[ inode - 1 ] = astReadObject( channel, key, NULL );
+ }
+
+/* Read remaining data... */
+
+/* Base. */
+/* ----- */
+ new->base = astReadInt( channel, "base", -INT_MAX );
+ if ( new->base < 1 ) new->base = -INT_MAX;
+
+/* Current. */
+/* -------- */
+ new->current = astReadInt( channel, "currnt", -INT_MAX );
+ if ( new->base < 1 ) new->base = -INT_MAX;
+ }
+
+/* If an error occurred, clean up by deleting the new FrameSet. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return the new FrameSet pointer. */
+ return new;
+
+/* Undefine macros local to this function. */
+#undef KEY_LEN
+}
+
+/* Virtual function interfaces. */
+/* ============================ */
+/* These provide the external interface to the virtual functions defined by
+ this class. Each simply checks the global error status and then locates and
+ executes the appropriate member function, using the function pointer stored
+ in the object's virtual function table (this pointer is located using the
+ astMEMBER macro defined in "object.h").
+
+ Note that the member function may not be the one defined here, as it may
+ have been over-ridden by a derived class. However, it should still have the
+ same interface. */
+void astAddFrame_( AstFrameSet *this, int iframe, AstMapping *map,
+ AstFrame *frame, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,AddFrame))( this, iframe, map, frame, status );
+}
+void astClearBase_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,ClearBase))( this, status );
+}
+void astClearCurrent_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,ClearCurrent))( this, status );
+}
+void astClearVariant_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,ClearVariant))( this, status );
+}
+int astGetBase_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,FrameSet,GetBase))( this, status );
+}
+int astGetCurrent_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,FrameSet,GetCurrent))( this, status );
+}
+const char *astGetVariant_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,FrameSet,GetVariant))( this, status );
+}
+AstFrame *astGetFrame_( AstFrameSet *this, int iframe, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,FrameSet,GetFrame))( this, iframe, status );
+}
+AstMapping *astGetMapping_( AstFrameSet *this, int iframe1, int iframe2, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,FrameSet,GetMapping))( this, iframe1, iframe2, status );
+}
+int astGetNframe_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,FrameSet,GetNframe))( this, status );
+}
+void astRemapFrame_( AstFrameSet *this, int iframe, AstMapping *map, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,RemapFrame))( this, iframe, map, status );
+}
+void astAddVariant_( AstFrameSet *this, AstMapping *map, const char *name, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,AddVariant))( this, map, name, status );
+}
+void astMirrorVariants_( AstFrameSet *this, int iframe, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,MirrorVariants))( this, iframe, status );
+}
+void astRemoveFrame_( AstFrameSet *this, int iframe, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,RemoveFrame))( this, iframe, status );
+}
+void astSetBase_( AstFrameSet *this, int ibase, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,SetBase))( this, ibase, status );
+}
+void astSetCurrent_( AstFrameSet *this, int icurrent, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,SetCurrent))( this, icurrent, status );
+}
+void astSetVariant_( AstFrameSet *this, const char *variant, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,FrameSet,SetVariant))( this, variant, status );
+}
+int astTestBase_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,FrameSet,TestBase))( this, status );
+}
+int astTestCurrent_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,FrameSet,TestCurrent))( this, status );
+}
+int astTestVariant_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,FrameSet,TestVariant))( this, status );
+}
+int astValidateFrameIndex_( AstFrameSet *this, int iframe,
+ const char *method, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,FrameSet,ValidateFrameIndex))( this, iframe,
+ method, status );
+}
+const char *astGetAllVariants_( AstFrameSet *this, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,FrameSet,GetAllVariants))( this, status );
+}
+int astGetNode_( AstFrameSet *this, int inode, int *nnodes,
+ int *iframe, AstMapping **map, int *parent,
+ int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,FrameSet,GetNode))( this, inode, nnodes,
+ iframe, map, parent, status );
+}
+
+/* Special public interface functions. */
+/* =================================== */
+/* These provide the public interface to certain special functions
+ whose public interface cannot be handled using macros (such as
+ astINVOKE) alone. In general, they are named after the
+ corresponding protected version of the function, but with "Id"
+ appended to the name. */
+
+/* Public Interface Function Prototypes. */
+/* ------------------------------------- */
+/* The following functions have public prototypes only (i.e. no
+ protected prototypes), so we must provide local prototypes for use
+ within this module. */
+AstFrameSet *astFrameSetId_( void *, const char *, ... );
+int astGetNodeId_( AstFrameSet *, int, int *, int *, AstMapping **, int *, int *);
+
+/* Special interface function implementations. */
+/* ------------------------------------------- */
+AstFrameSet *astFrameSetId_( void *frame_void, const char *options, ... ) {
+/*
+*++
+* Name:
+c astFrameSet
+f AST_FRAMESET
+
+* Purpose:
+* Create a FrameSet.
+
+* Type:
+* Public function.
+
+* Synopsis:
+c #include "frameset.h"
+c AstFrameSet *astFrameSet( AstFrame *frame, const char *options, ... )
+f RESULT = AST_FRAMESET( FRAME, OPTIONS, STATUS )
+
+* Class Membership:
+* FrameSet constructor.
+
+* Description:
+* This function creates a new FrameSet and optionally initialises
+* its attributes.
+*
+* A FrameSet consists of a set of one or more Frames (which
+* describe coordinate systems), connected together by Mappings
+* (which describe how the coordinate systems are inter-related). A
+* FrameSet makes it possible to obtain a Mapping between any pair
+* of these Frames (i.e. to convert between any of the coordinate
+* systems which it describes). The individual Frames are
+* identified within the FrameSet by an integer index, with Frames
+* being numbered consecutively from one as they are added to the
+* FrameSet.
+*
+* Every FrameSet has a "base" Frame and a "current" Frame (which
+* are allowed to be the same). Any of the Frames may be nominated
+* to hold these positions, and the choice is determined by the
+* values of the FrameSet's Base and Current attributes, which hold
+* the indices of the relevant Frames. By default, the first Frame
+* added to a FrameSet is its base Frame, and the last one added is
+* its current Frame.
+*
+* The base Frame describes the "native" coordinate system of
+* whatever the FrameSet is used to calibrate (e.g. the pixel
+* coordinates of an image) and the current Frame describes the
+* "apparent" coordinate system in which it should be viewed
+* (e.g. displayed, etc.). Any further Frames represent a library
+* of alternative coordinate systems, which may be selected by
+* making them current.
+*
+* When a FrameSet is used in a context that requires a Frame,
+* (e.g. obtaining its Title value, or number of axes), the current
+* Frame is used. A FrameSet may therefore be used in place of its
+* current Frame in most situations.
+*
+* When a FrameSet is used in a context that requires a Mapping,
+* the Mapping used is the one between its base Frame and its
+* current Frame. Thus, a FrameSet may be used to convert "native"
+* coordinates into "apparent" ones, and vice versa. Like any
+c Mapping, a FrameSet may also be inverted (see astInvert), which
+f Mapping, a FrameSet may also be inverted (see AST_INVERT), which
+* has the effect of interchanging its base and current Frames and
+* hence of reversing the Mapping between them.
+*
+* Regions may be added into a FrameSet (since a Region is a type of
+* Frame), either explicitly or as components within CmpFrames. In this
+* case the Mapping between a pair of Frames within a FrameSet will
+* include the effects of the clipping produced by any Regions included
+* in the path between the Frames.
+
+* Parameters:
+c frame
+f FRAME = INTEGER (Given)
+* Pointer to the first Frame to be inserted into the
+* FrameSet. This initially becomes both the base and the
+* current Frame. (Further Frames may be added using the
+c astAddFrame function.)
+f AST_ADDFRAME routine.)
+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 FrameSet. The syntax used is identical to
+c that for the astSet function and may include "printf" format
+c specifiers identified by "%" symbols in the normal way.
+c If no initialisation is required, a zero-length string may be
+c supplied.
+f A character string containing an optional comma-separated
+f list of attribute assignments to be used for initialising the
+f new FrameSet. The syntax used is identical to that for the
+f AST_SET routine. If no initialisation is required, a blank
+f value may be supplied.
+c ...
+c If the "options" string contains "%" format specifiers, then
+c an optional list of additional arguments may follow it in
+c order to supply values to be substituted for these
+c specifiers. The rules for supplying these are identical to
+c those for the astSet function (and for the C "printf"
+c function).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astFrameSet()
+f AST_FRAMESET
+* A pointer to the new FrameSet.
+
+* Notes:
+c - If a pointer to an existing FrameSet is given for the "frame"
+c parameter, then the new FrameSet will (as a special case) be
+f - If a pointer to an existing FrameSet is given for the FRAME
+f argument, then the new FrameSet will (as a special case) be
+* initialised to contain the same Frames and Mappings, and to have
+* the same attribute values, as the one supplied. This process is
+c similar to making a copy of a FrameSet (see astCopy), except
+f similar to making a copy of a FrameSet (see AST_COPY), except
+* that the Frames and Mappings contained in the original are not
+* themselves copied, but are shared by both FrameSets.
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+*--
+
+* Implementation Notes:
+* - This function implements the external (public) interface to
+* the astFrameSet constructor function. It returns an ID value
+* (instead of a true C pointer) to external users, and must be
+* provided because astFrameSet_ has a variable argument list which
+* cannot be encapsulated in a macro (where this conversion would
+* otherwise occur).
+* - Because no checking or casting of arguments is performed
+* before the function is invoked, the "frame" parameter is of type
+* (void *) and is converted from an ID value to a pointer and
+* validated within the function itself.
+* - The variable argument list also prevents this function from
+* invoking astFrameSet_ directly, so it must be a
+* re-implementation of it in all respects, except for the
+* conversions between IDs and pointers on input/output of Objects.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstFrame *frame; /* Pointer to Frame structure */
+ AstFrameSet *new; /* Pointer to new FrameSet */
+ va_list args; /* Variable argument list */
+
+ int *status;
+
+/* Initialise. */
+ new = NULL;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Pointer to inherited status value */
+
+/* Get a pointer to the inherited status value. */
+ status = astGetStatusPtr;
+
+/* Check the global status. */
+ if ( !astOK ) return new;
+
+/* Obtain the Frame pointer from the ID supplied and validate the
+ pointer to ensure it identifies a valid Frame. */
+ frame = astVerifyFrame( astMakePointer( frame_void ) );
+ if ( astOK ) {
+
+/* Initialise the FrameSet, allocating memory and initialising the
+ virtual function table as well if necessary. */
+ new = astInitFrameSet( NULL, sizeof( AstFrameSet ), !class_init,
+ &class_vtab, "FrameSet", frame );
+
+/* If successful, note that the virtual function table has been
+ initialised. */
+ if ( astOK ) {
+ class_init = 1;
+
+/* Obtain the variable argument list and pass it along with the
+ options string to the astVSet method to initialise the new
+ FrameSet'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 FrameSet. */
+ return astMakeId( new );
+}
+
+int astGetNodeId_( AstFrameSet *this, int inode, int *nnodes,
+ int *iframe, AstMapping **map, int *parent,
+ int *status ) {
+/*
+*+
+* Name:
+* astGetNode
+
+* Purpose:
+* Get information about a single node in a FrameSet tree.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frameset.h"
+* int astGetNode( AstFrameSet *this, int inode, int *nnodes,
+* int *iframe, AstMapping **map, int *parent )
+
+* Class Membership:
+* FrameSet method.
+
+* Description:
+* This function returns information about a specified node in a
+* FrameSet. It is documented as protected, because it should not
+* be used in general purpose software since it depends on the internal
+* details of the FrameSet class. However, it is in fact public so that
+* it can be used in external software that needs to know about the
+* internal structure of a FrameSet (for instance, a graphical FrameSet
+* visualisation system).
+
+* Parameters:
+* this
+* Pointer to the FrameSet.
+* inode
+* The zero-based index of the required node.
+* nnodes
+* Address of an int returned holding the number of nodes defined
+* in the FrameSet.
+* frame
+* Address of a Frame pointer returned holding a pointer to a deep
+* copy of the Frame, if any, associated with the node. NULL
+* is returned if the node has no Frame.
+* map
+* Address of a Mapping pointer returned holding a pointer to a
+* deep copy of the Mapping, if any, from the parent node to the
+* requested node. NULL is returned if the node has no parent.
+* parent
+* Address of an int returned holding the zero-based index of the
+* node from which the requested node is derived. -1 is returned if
+* the requested node has no parent (i.e. is the root of the tree).
+
+* Returned Value:
+* A non-zero value is returned if the "inode" value is within bounds.
+* Otherwise, zero is returned.
+
+*-
+*/
+
+/* Local Variables: */
+ int result;
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Invoke the normal astGetNode_ function. */
+ result = astGetNode_( this, inode, nnodes, iframe, map, parent, status );
+
+/* Return an ID value for the Mapping. */
+ *map = astMakeId( *map );
+
+/* Return the result. */
+ return result;
+}
+
+