summaryrefslogtreecommitdiffstats
path: root/ast/frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'ast/frame.c')
-rw-r--r--ast/frame.c16067
1 files changed, 16067 insertions, 0 deletions
diff --git a/ast/frame.c b/ast/frame.c
new file mode 100644
index 0000000..bd70cdd
--- /dev/null
+++ b/ast/frame.c
@@ -0,0 +1,16067 @@
+/*
+*class++
+* Name:
+* Frame
+
+* Purpose:
+* Coordinate system description.
+
+* Constructor Function:
+c astFrame
+f AST_FRAME
+
+* Description:
+* This class is used to represent coordinate systems. It does this
+* in rather the same way that a frame around a graph describes the
+* coordinate space in which data are plotted. Consequently, a
+* Frame has a Title (string) attribute, which describes the
+* coordinate space, and contains axes which in turn hold
+* information such as Label and Units strings which are used for
+* labelling (e.g.) graphical output. In general, however, the
+* number of axes is not restricted to two.
+*
+* Functions are available for converting Frame coordinate values
+* into a form suitable for display, and also for calculating
+* distances and offsets between positions within the Frame.
+*
+* Frames may also contain knowledge of how to transform to and
+* from related coordinate systems.
+
+* Inheritance:
+* The Frame class inherits from the Mapping class.
+
+* Attributes:
+* In addition to those attributes common to all Mappings, every
+* Frame also has the following attributes (if the Frame has only one
+* axis, the axis specifier can be omited from the following attribute
+* names):
+*
+* - AlignSystem: Coordinate system used to align Frames
+* - Bottom(axis): Lowest axis value to display
+* - Digits/Digits(axis): Number of digits of precision
+* - Direction(axis): Display axis in conventional direction?
+* - Domain: Coordinate system domain
+* - Dtai: Difference between the TAI and UTC timescale
+* - Dut1: Difference between the UT1 and UTC timescale
+* - Epoch: Epoch of observation
+* - Format(axis): Format specification for axis values
+* - InternalUnit(axis): Physical units for unformated axis values
+* - Label(axis): Axis label
+* - MatchEnd: Match trailing axes?
+* - MaxAxes: Maximum number of Frame axes to match
+* - MinAxes: Minimum number of Frame axes to match
+* - Naxes: Number of Frame axes
+* - NormUnit(axis): Normalised physical units for formatted axis values
+* - ObsAlt: Geodetic altitude of observer
+* - ObsLat: Geodetic latitude of observer
+* - ObsLon: Geodetic longitude of observer
+* - Permute: Permute axis order?
+* - PreserveAxes: Preserve axes?
+* - Symbol(axis): Axis symbol
+* - System: Coordinate system used to describe the domain
+* - Title: Frame title
+* - Top(axis): Highest axis value to display
+* - Unit(axis): Physical units for formatted axis values
+
+* Functions:
+c In addition to those functions applicable to all Mappings, the
+c following functions may also be applied to all Frames:
+f In addition to those routines applicable to all Mappings, the
+f following routines may also be applied to all Frames:
+*
+c - astAngle: Calculate the angle subtended by two points at a third point
+c - astAxAngle: Find the angle from an axis, to a line through two points
+c - astAxDistance: Calculate the distance between two axis values
+c - astAxNorm: Normalises an array of axis values
+c - astAxOffset: Calculate an offset along an axis
+c - astConvert: Determine how to convert between two coordinate systems
+c - astDistance: Calculate the distance between two points in a Frame
+c - astFindFrame: Find a coordinate system with specified characteristics
+c - astFormat: Format a coordinate value for a Frame axis
+c - astGetActiveUnit: Determines how the Unit attribute will be used
+c - astIntersect: Find the intersection between two geodesic curves
+c - astMatchAxes: Find any corresponding axes in two Frames
+c - astNorm: Normalise a set of Frame coordinates
+c - astOffset: Calculate an offset along a geodesic curve
+c - astOffset2: Calculate an offset along a geodesic curve in a 2D Frame
+c - astPermAxes: Permute the order of a Frame's axes
+c - astPickAxes: Create a new Frame by picking axes from an existing one
+c - astResolve: Resolve a vector into two orthogonal components
+c - astSetActiveUnit: Specify how the Unit attribute should be used
+c - astUnformat: Read a formatted coordinate value for a Frame axis
+f - AST_ANGLE: Find the angle subtended by two points at a third point
+f - AST_AXANGLE: Find the angle from an axis, to a line through two points
+f - AST_AXDISTANCE: Calculate the distance between two axis values
+f - AST_AXNORM: Normalises an array of axis values
+f - AST_AXOFFSET: Calculate an offset along an axis
+f - AST_CONVERT: Determine how to convert between two coordinate systems
+f - AST_DISTANCE: Calculate the distance between two points in a Frame
+f - AST_FINDFRAME: Find a coordinate system with specified characteristics
+f - AST_FORMAT: Format a coordinate value for a Frame axis
+f - AST_GETACTIVEUNIT: Determines how the Unit attribute will be used
+f - AST_INTERSECT: Find the intersection between two geodesic curves
+f - AST_MATCHAXES: Find any corresponding axes in two Frames
+f - AST_NORM: Normalise a set of Frame coordinates
+f - AST_OFFSET: Calculate an offset along a geodesic curve
+f - AST_OFFSET2: Calculate an offset along a geodesic curve in a 2D Frame
+f - AST_PERMAXES: Permute the order of a Frame's axes
+f - AST_PICKAXES: Create a new Frame by picking axes from an existing one
+f - AST_RESOLVE: Resolve a vector into two orthogonal components
+f - AST_SETACTIVEUNIT: Specify how the Unit attribute should be used
+f - AST_UNFORMAT: Read a formatted coordinate value for a Frame axis
+
+* Notes:
+* - When used as a Mapping, a Frame implements a unit (null)
+* transformation in both the forward and inverse directions
+* (equivalent to a UnitMap). The Nin and Nout attribute values are
+* both equal to the number of Frame axes.
+
+* Copyright:
+* Copyright (C) 1997-2006 Council for the Central Laboratory of the
+* Research Councils
+
+* Licence:
+* This program is free software: you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation, either
+* version 3 of the License, or (at your option) any later
+* version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General
+* License along with this program. If not, see
+* <http://www.gnu.org/licenses/>.
+
+* Authors:
+* RFWS: R.F. Warren-Smith (Starlink)
+* DSB: B.S. Berry (Starlink)
+
+* History:
+* 1-MAR-1996 (RFWS):
+* Original version.
+* 4-JUN-1996 (RFWS):
+* Added the CleanDomain function to fold all Domain strings to
+* upper case and remove white space.
+* 12-JUL-1996 (RFWS):
+* Over-ride the astReportPoints method to provide
+* Frame-specific formatting.
+* 11-SEP-1996 (RFWS):
+* Added astGap (written by DSB).
+* 10-JUN-1997 (RFWS):
+* Re-implemented astConvert and astFindFrame.
+* 1-SEP-1997 (RFWS):
+* Added missing return statement in astAbbrev_.
+* 14-NOV-1997 (RFWS):
+* Fixed wrong amount of memory allocated in ValidateAxisSelection.
+* 20-NOV-1997 (RFWS):
+* Updated astConvert prologue.
+* 22-DEC-1997 (RFWS):
+* Updated astConvert prologue again.
+* 15-FEB-1998 (RFWS):
+* Added astUnformat.
+* 2-MAR-1999 (RFWS);
+* Fixed missing STATUS arguments in examples for AST_FINDFRAME
+* prologue.
+* 18-JUL-1999 (RFWS):
+* Fixed memory leak in ConvertX.
+* 21-JUN-2001 (DSB):
+* Added methods astAngle and astOffset2.
+* 29-AUG-2001 (DSB):
+* Added methods astAxDistance and astAxOffset.
+* 4-SEP-2001 (DSB):
+* Added method astResolve.
+* 9-SEP-2001 (DSB):
+* Added method astBear.
+* 21-SEP-2001 (DSB):
+* Replaced astBear with astAxAngle.
+* 10-OCT-2002 (DSB):
+* Added Top and Bottom.
+* 15-NOV-2002 (DSB):
+* Moved the System and Epoch attributes from the SkyFrame class to
+* this class. Added virtual method astValidateSystem, astSystemString,
+* astSystemCode. Added attribute AlignSystem.
+* 17-DEC-2002 (DSB):
+* Added the GetActiveUnit, TestActiveUnit and SetActiveUnit functions.
+* 8-JAN-2003 (DSB):
+* Changed private InitVtab method to protected astInitFrameVtab
+* method.
+* 15-SEP-2003 (DSB):
+* Allow Frame attribute names to include an axis specifier within
+* GetAttrib, SetAttrib, TestAttrib and ClearAttrib (eg "Domain(1)"
+* is now accepted as equivalent to "Domain").
+* 24-JAN-2004 (DSB):
+* o Added astFields.
+* o Added argument "fmt" to Abbrev.
+* 24-MAR-2004 (DSB):
+* Add protected function astIsUnitFrame.
+* 7-SEP-2004 (DSB):
+* Modified SetUnit to exclude any trailing spaces
+* 8-SEP-2004 (DSB):
+* - Added astResolvePoints.
+* - Override astEqual.
+* 29-NOV-2004 (DSB):
+* - Set/Get/Test/ClearAttrib: Allow axis specifier to be omitted from
+* axis attribute names if the Frame only has one axis.
+* 2-FEB-2005 (DSB):
+* - Avoid using astStore to allocate more storage than is supplied
+* in the "data" pointer. This can cause access violations since
+* astStore will then read beyond the end of the "data" area.
+* 17-FEB-2005 (DSB):
+* - Change use of ActiveUnit flag so that both target and template
+* Frames must have active units in order for the Mapping to take
+* account of differences in units. Previously, the test was based
+* on the template Frame alone.
+* 23-MAR-2005 (DSB):
+* - GetActiveUnit: Always return zero if the Frame contains any
+* SkyAxes.
+* 5-APR-2005 (DSB):
+* Correct error checking in Clear/Get/Set/TestAttrib.
+* 12-MAY-2005 (DSB):
+* Added astNormBox method.
+* 16-JUN-2005 (DSB):
+* Added documentation for the TimeFrame class.
+* 12-AUG-2005 (DSB):
+* Added ObsLat and ObsLon attributes.
+* 1-MAR-2006 (DSB):
+* Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM.
+* 15-MAY-2006 (DSB):
+* Remove unused global variable parent_equal.
+* 26-JUN-2006 (DSB):
+* Document the use of the Direction attribute by the Plot class.
+* 30-JUN-2006 (DSB):
+* Allow astAbbrev to have a null "str1" value.
+* 16-AUG-2006 (DSB):
+* Correct "Class Applicability" to "Applicability".
+* 5-OCT-2006 (DSB):
+* Increase the number of digits used when formating a ObsLon or
+* ObsLat value in GetAttrib.
+* 14-OCT-2006 (DSB):
+* - Add Dut1 attribute
+* 26-JAN-2007 (DSB):
+* Fix bug in NewUnit that causes segvio when changing axis symbols
+* to accomodate changes in units.
+* 17-MAY-2007 (DSB):
+* Added read-only attribute NormUnit.
+* 21-MAY-2007 (DSB):
+* Use rather than ignore the value returned by astTestAxisDigits in
+* TestAttrib.
+* 25-JUN-2007 (DSB):
+* Documentation typos.
+* 26-NOV-2007 (DSB):
+* In Clear/Get/Set/TestAttrib, include any appropriate axis index in
+* the attribute name when attempting to get the attribute value from
+* the primary frame
+* 17-NOV-2008 (DSB):
+* Correct parent class in invocation of astMAKE_ISA.
+* 14-JAN-2009 (DSB):
+* Added astIntersect.
+* 18-MAR-2009 (DSB):
+* Fixed bug in LineCrossing.
+* 18-JUN-2000 (DSB):
+* Added ObsAlt attribute.
+* 28-SEP-2009 (DSB):
+* Added astMatchAxes method.
+* 22-MAR-2011 (DSB):
+* Add astFrameGrid method.
+* 29-APR-2011 (DSB):
+* Prevent astFindFrame from matching a subclass template against a
+* superclass target.
+* 11-APR-2012 (DSB):
+* Change astValidateAxis so that it can permute in either direction.
+* 29-APR-2013 (DSB):
+* Added protected methods astSetFrameVariants and astGetFrameVariants.
+* 1-MAY-2013 (DSB):
+* Override the astDoNotSimplify method to indicate that Frames should
+* always be simplified. This is mainly because the STC class uses the
+* Ident attribute with Frames, and preventing such frames from
+* simplifying (which is what the parent astDoNotSimplify method does)
+* causes the STC tester in the ast_tester directory to fail.
+* 10-FEB-2015 (DSB):
+* When checking attribute settings for attribute names that end with
+* an axis index, stop looking for the axis index when the first equals
+* sign is encountered.
+* 17-APR-2015 (DSB):
+* Added astCentre.
+* 27-APR-2015 (DSB):
+* Added read-only attribute InternalUnit.
+* 26-OCT-2016 (DSB):
+* Added method astAxNorm.
+* 11-JAN-2017 (GSB):
+* Add Dtai attribute.
+*class--
+*/
+
+/* Module Macros. */
+/* ============== */
+/* Set the name of the class we are implementing. This indicates to
+ the header files that define class interfaces that they should make
+ "protected" symbols available. */
+#define astCLASS Frame
+
+/* Define numerical constants for use in this module. */
+#define LABEL_BUFF_LEN 100 /* Max length of default axis Label string */
+#define SYMBOL_BUFF_LEN 50 /* Max length of default axis Symbol string */
+#define TITLE_BUFF_LEN 100 /* Max length of default title string */
+#define GETATTRIB_BUFF_LEN 50 /* Max length of string returned by GetAttrib */
+#define ASTFMTDECIMALYR_BUFF_LEN 50 /* Max length of string returned by GetAttrib */
+#define ASTFORMATID_MAX_STRINGS 50 /* Number of string values buffer by astFormatID*/
+
+
+/* Define the first and last acceptable System values. */
+#define FIRST_SYSTEM AST__CART
+#define LAST_SYSTEM AST__CART
+
+/* Define macros to implement methods for accessing axis attributes. */
+/*
+* Name:
+* MAKE_CLEAR
+
+* Purpose:
+* Implement a method to clear an attribute value for a Frame axis.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frame.h"
+* MAKE_CLEAR(attribute)
+
+* Class Membership:
+* Defined by the Frame class.
+
+* Description:
+* This macro expands to an implementation of a private member function of
+* the form:
+*
+* static void Clear<Attribute>( AstFrame *this, int axis )
+*
+* and an external interface function of the form:
+*
+* void astClear<Attribute>_( AstFrame *this, int axis )
+*
+* which implement a method for clearing an attribute value for a specified
+* axis of a Frame.
+
+* Parameters:
+* attribute
+* The name of the attribute to be cleared, as it appears in the
+* function name (e.g. Label in "astClearLabel").
+
+* Notes:
+* - This macro assumes the existence of a method of the form:
+*
+* void astClearAxis<Attribute>( AstAxis *this )
+*
+* which clears the required attribute for an Axis object.
+* - To avoid problems with some compilers, you should not leave any white
+* space around the macro arguments.
+*/
+
+/* Define the macro. */
+#define MAKE_CLEAR(attribute) \
+\
+/* Private member function. */ \
+/* ------------------------ */ \
+static void Clear##attribute( AstFrame *this, int axis, int *status ) { \
+ AstAxis *ax; /* Pointer to Axis object */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Validate the axis index and obtain a pointer to the required Axis. */ \
+ (void) astValidateAxis( this, axis, 1, "astClear" #attribute ); \
+ ax = astGetAxis( this, axis ); \
+\
+/* Clear the Axis attribute. */ \
+ astClearAxis##attribute( ax ); \
+\
+/* Annul the Axis pointer. */ \
+ ax = astAnnul( ax ); \
+} \
+\
+/* External interface. */ \
+/* ------------------- */ \
+void astClear##attribute##_( AstFrame *this, int axis, int *status ) { \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Invoke the required method via the virtual function table. */ \
+ (**astMEMBER(this,Frame,Clear##attribute))( this, axis, status ); \
+}
+
+/*
+* Name:
+* MAKE_GET
+
+* Purpose:
+* Implement a method to get an attribute value for a Frame axis.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+# #include "frame.h"
+* MAKE_GET(attribute,type,bad_value,default,assign_default)
+
+* Class Membership:
+* Defined by the Frame class.
+
+* Description:
+* This macro expands to an implementation of a private member function of
+* the form:
+*
+* static <Type> Get<Attribute>( AstFrame *this, int axis )
+*
+* and an external interface function of the form:
+*
+* Type astGet<Attribute>_( AstFrame *this, int axis )
+*
+* which implement a method for getting an attribute value for a specified
+* axis of a Frame.
+
+* Parameters:
+* attribute
+* The name of the attribute whose value is to be obtained, as
+* it appears in the function name (e.g. Label in
+* "astGetLabel").
+* type
+* The C type of the attribute.
+* bad_value
+* A constant value to return if the global error status is set, or if
+* the function fails.
+* default
+* A boolean (int) constant that indicates whether a new default value
+* should be returned by the method if the requested attribute has not
+* been set for the axis. If this value is zero, the axis default will
+* be used instead.
+* assign_default
+* An expression that evaluates to the new default value to be assigned.
+* This value is ignored if "default" is zero, but a valid (e.g.
+* constant) value should nevertheless be supplied.
+
+* Notes:
+* - This macro assumes the existence of a method of the form:
+*
+* <Type> astGetAxis<Attribute>( AstAxis *this )
+*
+* which gets the required attribute for an Axis object.
+* - To avoid problems with some compilers, you should not leave any white
+* space around the macro arguments.
+*/
+
+/* Define the macro. */
+#define MAKE_GET(attribute,type,bad_value,default,assign_default) \
+\
+/* Private member function. */ \
+/* ------------------------ */ \
+static type Get##attribute( AstFrame *this, int axis, int *status ) { \
+ AstAxis *ax; /* Pointer to Axis object */ \
+ int digits_set; /* Axis Digits attribute set? */ \
+ int old_axis; /* Original (un-permuted) axis index */ \
+ type result; /* Result to be returned */ \
+\
+/* Initialise. */ \
+ result = (bad_value); \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return result; \
+\
+/* Validate and permute the axis index and obtain a pointer to the required \
+ Axis. */ \
+ old_axis = axis; \
+ axis = astValidateAxis( this, axis, 1, "astGet" #attribute ); \
+ ax = astGetAxis( this, old_axis ); \
+\
+/* Since the Axis is "managed" by the enclosing Frame, we next test if any \
+ Axis attributes which may affect the result are undefined (i.e. have not \
+ been explicitly set). If so, we over-ride them, giving them temporary \
+ values dictated by the Frame. Only the Digits attribute is relevant \
+ here. */ \
+ digits_set = astTestAxisDigits( ax ); \
+ if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) ); \
+\
+/* If the default value is to be over-ridden, test if the Axis attribute has \
+ been set. Then, if required, obtain the attribute value from the Axis. */ \
+ if ( !(default) || astTestAxis##attribute( ax ) ) { \
+ result = astGetAxis##attribute( ax ); \
+\
+/* If required, assign the new default value. */ \
+ } else { \
+ result = (assign_default); \
+ } \
+\
+/* Clear Axis attributes which were temporarily over-ridden above and annul \
+ the Axis pointer. */ \
+ if ( !digits_set ) astClearAxisDigits( ax ); \
+ ax = astAnnul( ax ); \
+\
+/* If an error occurred, clear the result value. */ \
+ if ( !astOK ) result = (bad_value); \
+\
+/* Return the result. */ \
+ return result; \
+} \
+\
+/* External interface. */ \
+/* ------------------- */ \
+type astGet##attribute##_( AstFrame *this, int axis, int *status ) { \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return (bad_value); \
+\
+/* Invoke the required method via the virtual function table. */ \
+ return (**astMEMBER(this,Frame,Get##attribute))( this, axis, status ); \
+}
+
+/*
+* Name:
+* MAKE_SET
+
+* Purpose:
+* Implement a method to set an attribute value for a Frame axis.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frame.h"
+* MAKE_SET(attribute,type)
+
+* Class Membership:
+* Defined by the Frame class.
+
+* Description:
+* This macro expands to an implementation of a private member function of
+* the form:
+*
+* static void Set<Attribute>( AstFrame *this, int axis, <Type> value )
+*
+* and an external interface function of the form:
+*
+* void astSet<Attribute>_( AstFrame *this, int axis, <Type> value )
+*
+* which implement a method for setting an attribute value for a specified
+* axis of a Frame.
+
+* Parameters:
+* attribute
+* The name of the attribute to be set, as it appears in the
+* function name (e.g. Label in "astSetLabel").
+* type
+* The C type of the attribute.
+
+* Notes:
+* - This macro assumes the existence of a method of the form:
+*
+* void astSetAxis<Attribute>( AstAxis *this, <Type> value )
+*
+* which sets the required attribute for an Axis object.
+* - To avoid problems with some compilers, you should not leave any white
+* space around the macro arguments.
+*/
+
+/* Define the macro. */
+#define MAKE_SET(attribute,type) \
+\
+/* Private member function. */ \
+/* ------------------------ */ \
+static void Set##attribute( AstFrame *this, int axis, type value, int *status ) { \
+ AstAxis *ax; /* Pointer to Axis object */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Validate the axis index and obtain a pointer to the required Axis. */ \
+ (void) astValidateAxis( this, axis, 1, "astSet" #attribute ); \
+ ax = astGetAxis( this, axis ); \
+\
+/* Set the Axis attribute value. */ \
+ astSetAxis##attribute( ax, value ); \
+\
+/* Annul the Axis pointer. */ \
+ ax = astAnnul( ax ); \
+} \
+\
+/* External interface. */ \
+/* ------------------- */ \
+void astSet##attribute##_( AstFrame *this, int axis, type value, int *status ) { \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Invoke the required method via the virtual function table. */ \
+ (**astMEMBER(this,Frame,Set##attribute))( this, axis, value, status ); \
+}
+
+/*
+* Name:
+* MAKE_TEST
+
+* Purpose:
+* Implement a method to test if an attribute has been set for a Frame axis.
+
+* Type:
+* Private macro.
+
+* Synopsis:
+* #include "frame.h"
+* MAKE_TEST(attribute)
+
+* Class Membership:
+* Defined by the Frame class.
+
+* Description:
+* This macro expands to an implementation of a private member function of
+* the form:
+*
+* static int Test<Attribute>( AstFrame *this, int axis )
+*
+* and an external interface function of the form:
+*
+* int astTest<Attribute>_( AstFrame *this, int axis )
+*
+* which implement a method for testing if an attribute has been set for a
+* specified axis of a Frame.
+
+* Parameters:
+* attribute
+* The name of the attribute to be tested, as it appears in the
+* function name (e.g. Label in "astTestLabel").
+
+* Notes:
+* - This macro assumes the existence of a method of the form:
+*
+* void astTestAxis<Attribute>( AstAxis *this )
+*
+* which tests the required attribute for an Axis object.
+* - To avoid problems with some compilers, you should not leave any white
+* space around the macro arguments.
+*/
+
+/* Define the macro. */
+#define MAKE_TEST(attribute) \
+\
+/* Private member function. */ \
+/* ------------------------ */ \
+static int Test##attribute( AstFrame *this, int axis, int *status ) { \
+ AstAxis *ax; /* Pointer to Axis object */ \
+ int result; /* Value to be returned */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return 0; \
+\
+/* Validate the axis index and obtain a pointer to the required Axis. */ \
+ (void) astValidateAxis( this, axis, 1, "astTest" #attribute ); \
+ ax = astGetAxis( this, axis ); \
+\
+/* Test if the attribute has been set. */ \
+ result = astTestAxis##attribute( ax ); \
+\
+/* Annul the Axis pointer. */ \
+ ax = astAnnul( ax ); \
+\
+/* If an error occurred, clear the result value. */ \
+ if ( !astOK ) result = 0; \
+\
+/* Return the result. */ \
+ return result; \
+} \
+\
+/* External interface. */ \
+/* ------------------- */ \
+int astTest##attribute##_( AstFrame *this, int axis, int *status ) { \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return 0; \
+\
+/* Invoke the required method via the virtual function table. */ \
+ return (**astMEMBER(this,Frame,Test##attribute))( this, axis, status ); \
+}
+
+/* Header files. */
+/* ============= */
+/* Interface definitions. */
+/* ---------------------- */
+
+#include "globals.h" /* Thread-safe global data access */
+#include "error.h" /* Error reporting facilities */
+#include "memory.h" /* Memory allocation facilities */
+#include "object.h" /* Base Object class */
+#include "mapping.h" /* Coordinate mappings (parent class) */
+#include "pointset.h" /* Sets of points */
+#include "unitmap.h" /* Unit Mapping */
+#include "permmap.h" /* Coordinate permutation Mapping */
+#include "cmpmap.h" /* Compound Mappings */
+#include "axis.h" /* Coordinate Axis */
+#include "skyaxis.h" /* Sky coordinate axes */
+#include "skyframe.h" /* Celestial coordinate frames */
+#include "channel.h" /* I/O channels */
+#include "frame.h" /* Interface definition for this class */
+#include "frameset.h" /* Collections of Frames */
+#include "cmpframe.h" /* Compound Frames */
+#include "pal.h" /* SLALIB library interface */
+#include "unit.h" /* Units identification and mapping */
+#include "globals.h" /* Thread-safe global data access */
+
+/* Error code definitions. */
+/* ----------------------- */
+#include "ast_err.h" /* AST error codes */
+
+/* C header files. */
+/* --------------- */
+#include <ctype.h>
+#include <limits.h>
+#include <math.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 const char *(* parent_getattrib)( AstObject *, const char *, int * );
+static int (* parent_testattrib)( AstObject *, const char *, int * );
+static void (* parent_clearattrib)( AstObject *, const char *, int * );
+static void (* parent_setattrib)( AstObject *, const char *, int * );
+static void (* parent_cleanattribs)( AstObject *, int * );
+static int (* parent_getobjsize)( AstObject *, int * );
+
+#if defined(THREAD_SAFE)
+static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
+#endif
+
+/* Define a variable to hold a SkyFrame which will be used for formatting
+ and unformatting ObsLat and ObsLon values. */
+static AstSkyFrame *skyframe;
+
+/* Define macros for accessing each item of thread specific global data. */
+#ifdef THREAD_SAFE
+
+/* Define how to initialise thread-specific globals. */
+#define GLOBAL_inits \
+ globals->Class_Init = 0; \
+ globals->GetAttrib_Buff[ 0 ] = 0; \
+ globals->AstFormatID_Init = 0; \
+ globals->AstFormatID_Istr = 0; \
+ globals->Label_Buff[ 0 ] = 0; \
+ globals->Symbol_Buff[ 0 ] = 0; \
+ globals->Title_Buff[ 0 ] = 0; \
+ globals->AstFmtDecimalYr_Buff[ 0 ] = 0;
+
+/* Create the function that initialises global data for this module. */
+astMAKE_INITGLOBALS(Frame)
+
+#define class_init astGLOBAL(Frame,Class_Init)
+#define class_vtab astGLOBAL(Frame,Class_Vtab)
+#define getattrib_buff astGLOBAL(Frame,GetAttrib_Buff)
+#define astformatid_strings astGLOBAL(Frame,AstFormatID_Strings)
+#define astformatid_istr astGLOBAL(Frame,AstFormatID_Istr)
+#define astformatid_init astGLOBAL(Frame,AstFormatID_Init)
+#define label_buff astGLOBAL(Frame,Label_Buff)
+#define symbol_buff astGLOBAL(Frame,Symbol_Buff)
+#define title_buff astGLOBAL(Frame,Title_Buff)
+#define astfmtdecimalyr_buff astGLOBAL(Frame,AstFmtDecimalYr_Buff)
+
+
+
+/* If thread safety is not needed, declare and initialise globals at static
+ variables. */
+#else
+
+/* Buffer returned by GetAttrib. */
+static char getattrib_buff[ GETATTRIB_BUFF_LEN + 1 ];
+
+/* Strings returned by astFormatID */
+static char *astformatid_strings[ ASTFORMATID_MAX_STRINGS ];
+
+/* Offset of next string in "AstFormatID_Strings" */
+static int astformatid_istr;
+
+/* "AstFormatID_Strings" array initialised? */
+static int astformatid_init;
+
+/* Default Label string buffer */
+static char label_buff[ LABEL_BUFF_LEN + 1 ];
+
+/* Default Symbol buffer */
+static char symbol_buff[ SYMBOL_BUFF_LEN + 1 ];
+
+/* Default Title string buffer */
+static char title_buff[ TITLE_BUFF_LEN + 1 ];
+
+/* Buffer for result string */
+static char astfmtdecimalyr_buff[ ASTFMTDECIMALYR_BUFF_LEN + 1 ];
+
+
+/* Define the class virtual function table and its initialisation flag
+ as static variables. */
+static AstFrameVtab class_vtab; /* Virtual function table */
+static int class_init = 0; /* Virtual function table initialised? */
+
+#endif
+
+
+/* Prototypes for Private Member Functions. */
+/* ======================================== */
+static AstAxis *GetAxis( AstFrame *, int, int * );
+static AstFrame *PickAxes( AstFrame *, int, const int[], AstMapping **, int * );
+static AstFrameSet *Convert( AstFrame *, AstFrame *, const char *, int * );
+static AstFrameSet *ConvertX( AstFrame *, AstFrame *, const char *, int * );
+static AstFrameSet *FindFrame( AstFrame *, AstFrame *, const char *, int * );
+static void MatchAxes( AstFrame *, AstFrame *, int *, int * );
+static void MatchAxesX( AstFrame *, AstFrame *, int *, int * );
+static AstLineDef *LineDef( AstFrame *, const double[2], const double[2], int * );
+static AstPointSet *FrameGrid( AstFrame *, int, const double *, const double *, int * );
+static AstPointSet *ResolvePoints( AstFrame *, const double [], const double [], AstPointSet *, AstPointSet *, int * );
+static AstPointSet *Transform( AstMapping *, AstPointSet *, int, AstPointSet *, int * );
+static char *CleanDomain( char *, int * );
+static const char *Abbrev( AstFrame *, int, const char *, const char *, const char *, int * );
+static const char *Format( AstFrame *, int, double, int * );
+static const char *GetAttrib( AstObject *, const char *, int * );
+static const char *GetDefaultLabel( int, int * );
+static const char *GetDefaultSymbol( AstFrame *, int, int * );
+static const char *GetDefaultTitle( AstFrame *, int * );
+static const char *GetDomain( AstFrame *, int * );
+static const char *GetFormat( AstFrame *, int, int * );
+static const char *GetInternalUnit( AstFrame *, int, int * );
+static const char *GetLabel( AstFrame *, int, int * );
+static const char *GetNormUnit( AstFrame *, int, int * );
+static const char *GetSymbol( AstFrame *, int, int * );
+static const char *GetTitle( AstFrame *, int * );
+static const char *GetUnit( AstFrame *, int, int * );
+static const int *GetPerm( AstFrame *, int * );
+static double Angle( AstFrame *, const double[], const double[], const double[], int * );
+static double AxAngle( AstFrame *, const double[], const double[], int, int * );
+static double AxDistance( AstFrame *, int, double, double, int * );
+static double AxOffset( AstFrame *, int, double, double, int * );
+static double Distance( AstFrame *, const double[], const double[], int * );
+static double 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 int AxIn( AstFrame *, int, double, double, double, int, int * );
+static int ConsistentMaxAxes( AstFrame *, int, int * );
+static int ConsistentMinAxes( AstFrame *, int, int * );
+static int DefaultMaxAxes( AstFrame *, int * );
+static int DefaultMinAxes( AstFrame *, int * );
+static int DoNotSimplify( AstMapping *, int * );
+static int Equal( AstObject *, AstObject *, int * );
+static int Fields( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * );
+static int GetDigits( AstFrame *, int * );
+static int GetDirection( AstFrame *, int, int * );
+static int GetIsLinear( AstMapping *, int * );
+static int GetIsSimple( AstMapping *, int * );
+static int LineContains( AstFrame *, AstLineDef *, int, double *, int * );
+static int LineCrossing( AstFrame *, AstLineDef *, AstLineDef *, double **, int * );
+static int GetObjSize( AstObject *, int * );
+static void AxNorm( AstFrame *, int, int, int, double *, int * );
+static void CleanAttribs( AstObject *, int * );
+static void LineOffset( AstFrame *, AstLineDef *, double, double, double[2], int * );
+
+static double GetTop( AstFrame *, int, int * );
+static int TestTop( AstFrame *, int, int * );
+static void ClearTop( AstFrame *, int, int * );
+static void SetTop( AstFrame *, int, double, int * );
+
+static double GetBottom( AstFrame *, int, int * );
+static int TestBottom( AstFrame *, int, int * );
+static void ClearBottom( AstFrame *, int, int * );
+static void SetBottom( AstFrame *, int, double, int * );
+
+static AstSystemType GetSystem( AstFrame *, int * );
+static int TestSystem( AstFrame *, int * );
+static void ClearSystem( AstFrame *, int * );
+static void SetSystem( AstFrame *, AstSystemType, int * );
+
+static AstSystemType GetAlignSystem( AstFrame *, int * );
+static int TestAlignSystem( AstFrame *, int * );
+static void ClearAlignSystem( AstFrame *, int * );
+static void SetAlignSystem( AstFrame *, AstSystemType, int * );
+
+static double GetEpoch( AstFrame *, int * );
+static int TestEpoch( AstFrame *, int * );
+static void ClearEpoch( AstFrame *, int * );
+static void SetEpoch( AstFrame *, double, int * );
+
+static double GetObsLat( AstFrame *, int * );
+static int TestObsLat( AstFrame *, int * );
+static void ClearObsLat( AstFrame *, int * );
+static void SetObsLat( AstFrame *, double, int * );
+
+static double GetObsLon( AstFrame *, int * );
+static int TestObsLon( AstFrame *, int * );
+static void ClearObsLon( AstFrame *, int * );
+static void SetObsLon( AstFrame *, double, int * );
+
+static double GetObsAlt( AstFrame *, int * );
+static int TestObsAlt( AstFrame *, int * );
+static void ClearObsAlt( AstFrame *, int * );
+static void SetObsAlt( AstFrame *, double, int * );
+
+static double 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 int GetActiveUnit( AstFrame *, int * );
+static int TestActiveUnit( AstFrame *, int * );
+static void SetActiveUnit( AstFrame *, int, int * );
+
+static AstFrameSet *GetFrameVariants( AstFrame *, int * );
+static void SetFrameVariants( AstFrame *, AstFrameSet *, int * );
+
+static int GetFrameFlags( AstFrame *, int * );
+static int *MapSplit( AstMapping *, int, const int *, AstMapping **, int * );
+static int GetMatchEnd( AstFrame *, int * );
+static int GetMaxAxes( AstFrame *, int * );
+static int GetMinAxes( AstFrame *, int * );
+static int GetNaxes( AstFrame *, int * );
+static int GetNin( AstMapping *, int * );
+static int GetNout( AstMapping *, int * );
+static int GetPermute( AstFrame *, int * );
+static int GetPreserveAxes( AstFrame *, int * );
+static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
+static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
+static int TestAttrib( AstObject *, const char *, int * );
+static int TestDigits( AstFrame *, int * );
+static int TestDirection( AstFrame *, int, int * );
+static int TestDomain( AstFrame *, int * );
+static int TestFormat( AstFrame *, int, int * );
+static int TestLabel( AstFrame *, int, int * );
+static int TestMatchEnd( AstFrame *, int * );
+static int TestMaxAxes( AstFrame *, int * );
+static int TestMinAxes( AstFrame *, int * );
+static int TestPermute( AstFrame *, int * );
+static int TestPreserveAxes( AstFrame *, int * );
+static int TestSymbol( AstFrame *, int, int * );
+static int TestTitle( AstFrame *, int * );
+static int TestUnit( AstFrame *, int, int * );
+static int IsUnitFrame( AstFrame *, int * );
+static int Unformat( AstFrame *, int, const char *, double *, int * );
+static int ValidateAxis( AstFrame *, int, int, const char *, int * );
+static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * );
+static AstSystemType SystemCode( AstFrame *, const char *, int * );
+static const char *SystemString( AstFrame *, AstSystemType, int * );
+static void AddUnderscores( char *, int * );
+static void CheckPerm( AstFrame *, const int *, const char *, int * );
+static void ClearAttrib( AstObject *, const char *, int * );
+static void ClearDigits( AstFrame *, int * );
+static void ClearDirection( AstFrame *, int, int * );
+static void ClearDomain( AstFrame *, int * );
+static void ClearFormat( AstFrame *, int, int * );
+static void ClearLabel( AstFrame *, int, int * );
+static void ClearMatchEnd( AstFrame *, int * );
+static void ClearMaxAxes( AstFrame *, int * );
+static void ClearMinAxes( AstFrame *, int * );
+static void ClearPermute( AstFrame *, int * );
+static void ClearPreserveAxes( AstFrame *, int * );
+static void ClearSymbol( AstFrame *, int, int * );
+static void ClearTitle( AstFrame *, int * );
+static void ClearUnit( AstFrame *, int, int * );
+static void Copy( const AstObject *, AstObject *, int * );
+static void Delete( AstObject *, int * );
+static void Dump( AstObject *, AstChannel *, int * );
+static void Intersect( AstFrame *, const double[2], const double[2], const double[2], const double[2], double[2], int * );
+static void Norm( AstFrame *, double[], int * );
+static void NormBox( AstFrame *, double[], double[], AstMapping *, int * );
+static void Offset( AstFrame *, const double[], const double[], double, double[], int * );
+static void Overlay( AstFrame *, const int *, AstFrame *, int * );
+static void PermAxes( AstFrame *, const int[], int * );
+static void PrimaryFrame( AstFrame *, int, AstFrame **, int *, int * );
+static void ReportPoints( AstMapping *, int, AstPointSet *, AstPointSet *, int * );
+static void Resolve( AstFrame *, const double [], const double [], const double [], double [], double *, double *, int * );
+static void SetAttrib( AstObject *, const char *, int * );
+static void SetAxis( AstFrame *, int, AstAxis *, int * );
+static void SetDigits( AstFrame *, int, int * );
+static void SetDirection( AstFrame *, int, int, int * );
+static void SetDomain( AstFrame *, const char *, int * );
+static void SetFormat( AstFrame *, int, const char *, int * );
+static void SetFrameFlags( AstFrame *, int, int * );
+static void SetLabel( AstFrame *, int, const char *, int * );
+static void SetMatchEnd( AstFrame *, int, int * );
+static void SetMaxAxes( AstFrame *, int, int * );
+static void SetMinAxes( AstFrame *, int, int * );
+static void SetPermute( AstFrame *, int, int * );
+static void SetPreserveAxes( AstFrame *, int, int * );
+static void SetSymbol( AstFrame *, int, const char *, int * );
+static void SetTitle( AstFrame *, const char *, int * );
+static void SetUnit( AstFrame *, int, const char *, int * );
+static void NewUnit( AstAxis *, const char *, const char *, const char *, const char *, int * );
+static void ValidateAxisSelection( AstFrame *, int, const int *, const char *, int * );
+
+#if defined(THREAD_SAFE)
+static int ManageLock( AstObject *, int, int, AstObject **, int * );
+#endif
+
+/* Member functions. */
+/* ================= */
+static const char *Abbrev( AstFrame *this, int axis, const char *fmt,
+ const char *str1, const char *str2, int *status ) {
+/*
+*+
+* Name:
+* astAbbrev
+
+* Purpose:
+* Abbreviate a formatted Frame axis value by skipping leading fields.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* const char *astAbbrev( AstFrame *this, int axis, const char *fmt,
+* const char *str1, const char *str2 )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function compares two Frame axis values that have been
+* formatted (using astFormat) and determines if they have any
+* redundant leading fields (i.e. leading fields in common which
+* can be suppressed when tabulating the values or plotting them on
+* the axis of a graph).
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the Frame axis for which the values have been
+* formatted (axis numbering starts at zero for the first axis).
+* fmt
+* Pointer to a constant null-terminated string containing the
+* format specification used to format the two values.
+* str1
+* Pointer to a constant null-terminated string containing the
+* first formatted value. If this is null, the returned pointer
+* points to the start of the final field in str2.
+* str2
+* Pointer to a constant null-terminated string containing the
+* second formatted value.
+
+* Returned Value:
+* A pointer into the "str2" string which locates the first
+* character in the first field that differs between the two
+* formatted values.
+*
+* If the two values have no leading fields in common, the returned
+* value will point at the start of string "str2". If the two
+* values are equal, it will point at the terminating null at the
+* end of this string.
+
+* Notes:
+* - This function assumes that the format specification used was
+* the same when both values were formatted and that they both
+* apply to the same Frame axis.
+* - A pointer to the start of "str2" will be returned if this
+* function is invoked with the global error status set, or if it
+* should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ const char *result; /* Result pointer to return */
+
+/* Initialise. */
+ result = str2;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate the axis index and obtain a pointer to the required
+ Axis. */
+ (void) astValidateAxis( this, axis, 1, "astAbbrev" );
+ ax = astGetAxis( this, axis );
+
+/* Invoke the Axis astAxisAbbrev method to perform the processing. */
+ result = astAxisAbbrev( ax, fmt, str1, str2 );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = str2;
+
+/* Return the result. */
+ return result;
+}
+
+static void AddUnderscores( char *string, int *status ) {
+/*
+* Name:
+* AddUnderscores
+
+* Purpose:
+* Add underscores to a string in place of white space.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* void AddUnderscores( char *string, int *status )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function changes all white space characters in a string into
+* the underscore character '_'.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* string
+* Pointer to the null terminated string to be processed.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables. */
+ int i; /* Loop counter for characters */
+
+/* Inspect each character in the string. */
+ for ( i = 0; string[ i ]; i++ ) {
+
+/* If it is a white space character, replace it with an underscore. */
+ if ( isspace( string[ i ] ) ) string[ i ] = '_';
+ }
+}
+
+static double Angle( AstFrame *this, const double a[],
+ const double b[], const double c[], int *status ) {
+/*
+*++
+* Name:
+c astAngle
+f AST_ANGLE
+
+* Purpose:
+* Calculate the angle subtended by two points at a third point.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c double astAngle( AstFrame *this, const double a[], const double b[],
+c const double c[] )
+f RESULT = AST_ANGLE( THIS, A, B, C, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function
+f This routine
+* finds the angle at point B between the line joining points A and B,
+* and the line joining points C and B. These lines will in fact be
+* geodesic curves appropriate to the Frame in use. For instance, in
+* SkyFrame, they will be great circles.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c a
+f A( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the first point.
+c b
+f B( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the second point.
+c c
+f C( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the third point.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astAngle
+f AST_ANGLE = DOUBLE PRECISION
+* The angle in radians, from the line AB to the line CB. If the
+* Frame is 2-dimensional, it will be in the range $\pm \pi$,
+* and positive rotation is in the same sense as rotation from
+* the positive direction of axis 2 to the positive direction of
+* axis 1. If the Frame has more than 2 axes, a positive value will
+* always be returned in the range zero to $\pi$.
+
+* Notes:
+* - A value of AST__BAD will also be returned if points A and B are
+* co-incident, or if points B and C are co-incident.
+* - A value of AST__BAD will also be returned if this function is
+c invoked with the AST error status set, or if it should fail for
+f invoked with STATUS set to an error value, or if it should fail for
+* any reason.
+*--
+*/
+
+/* Local Variables: */
+ double *ab; /* Pointer to vector AB */
+ double *cb; /* Pointer to vector CB */
+ double cos; /* cosine of required angle */
+ double anga; /* Angle from +ve Y to the line BA */
+ double angc; /* Angle from +ve Y to the line BC */
+ double result; /* Result value to return */
+ double sla; /* Squared length of vector AB */
+ double slc; /* Squared length of vector CB */
+ double sp; /* Scalar product of AB and CB */
+ int axis; /* Axis index */
+ int naxes; /* Number of Frame axes */
+ int ok; /* Supplied points OK? */
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Assume everything is ok */
+ ok = 1;
+
+/* Obtain the number of Frame axes. */
+ naxes = astGetNaxes( this );
+
+/* Obtain workspace. */
+ ab = (double *) astMalloc( sizeof(double)*naxes );
+ cb = (double *) astMalloc( sizeof(double)*naxes );
+
+/* Check all positions are good, and form the vectors from b to a, and
+ from b to c. Also find the squared length of each vector. */
+ if( astOK ) {
+ sla = 0.0;
+ slc = 0.0;
+ for( axis = 0; axis < naxes; axis++ ) {
+ if( a[ axis ] == AST__BAD || b[ axis ] == AST__BAD ||
+ c[ axis ] == AST__BAD ) {
+ ok = 0;
+ break;
+ } else {
+ ab[ axis ] = a[ axis ] - b[ axis ];
+ cb[ axis ] = c[ axis ] - b[ axis ];
+ sla += ( ab[ axis ] )*( ab[ axis ] );
+ slc += ( cb[ axis ] )*( cb[ axis ] );
+ }
+ }
+
+/* Check that neither of the vectors have zero length. */
+ if( sla == 0 || slc == 0 ) ok = 0;
+
+/* Only proceed if these checks were passed. */
+ if ( ok ) {
+
+/* Deal first with 2-dimensional Frames. */
+ if( naxes == 2 ) {
+
+/* Find the angle from +ve Y to the line BA. */
+ anga = atan2( ab[ 0 ], ab[ 1 ] );
+
+/* Find the angle from +ve Y to the line BC. */
+ angc = atan2( cb[ 0 ], cb[ 1 ] );
+
+/* Find the difference, folded into the range +/- PI. */
+ result = palDrange( angc - anga );
+
+/* Now deal with Frames with more than 2 axes. */
+ } else {
+
+/* Form the scalar product of the two vectors. */
+ sp = 0.0;
+ for( axis = 0; axis < naxes; axis++ ) {
+ sp += ab[ axis ]*cb[ axis ];
+ }
+
+/* Derive the required angle from the normalized scalar product. */
+ cos = sp/sqrt( sla*slc );
+ if( cos > 1.0 ) {
+ cos = 1.0;
+ } else if( cos < -1.0 ) {
+ cos = -1.0;
+ }
+ result =acos( cos );
+ }
+ }
+ }
+
+/* Free the work space. */
+ ab = (double *) astFree( (void *) ab );
+ cb = (double *) astFree( (void *) cb );
+
+/* Return the result. */
+ return result;
+}
+
+static double AxAngle( AstFrame *this, const double a[], const double b[], int axis, int *status ) {
+/*
+*++
+* Name:
+c astAxAngle
+f AST_AXANGLE
+
+* Purpose:
+* Returns the angle from an axis, to a line through two points.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c double astAxAngle( AstFrame *this, const double a[], const double b[], int axis )
+f RESULT = AST_AXANGLE( THIS, A, B, AXIS, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function
+f This routine
+* finds the angle, as seen from point A, between the positive
+* direction of a specified axis, and the geodesic curve joining point
+* A to point B.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c a
+f A( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the first point.
+c b
+f B( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the second point.
+c axis
+f AXIS = INTEGER (Given)
+* The number of the Frame axis from which the angle is to be
+* measured (axis numbering starts at 1 for the first axis).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astAxAngle
+f AST_AXANGLE = DOUBLE PRECISION
+* The angle in radians, from the positive direction of the
+* specified axis, to the line AB. If the Frame is 2-dimensional,
+* it will be in the range [-PI/2,+PI/2], and positive rotation is in
+* the same sense as rotation from the positive direction of axis 2
+* to the positive direction of axis 1. If the Frame has more than 2
+* axes, a positive value will always be returned in the range zero
+* to PI.
+
+* Notes:
+c - The geodesic curve used by this function is the path of
+f - The geodesic curve used by this routine is the path of
+* shortest distance between two points, as defined by the
+c astDistance function.
+f AST_DISTANCE function.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value, or if the require
+* position angle is undefined.
+*--
+*/
+
+/* Local Variables: */
+ double *aa; /* Pointer to third point */
+ double ab; /* Absolute value of component */
+ double mxab; /* Largest absolute value of component */
+ double result; /* The returned value */
+ int iaxis; /* Axis index */
+ int naxes; /* Number of Frame axes */
+ int ok; /* Are values ok to use? */
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis - 1, 1, "astAxAngle" );
+
+/* Obtain the number of Frame axes. */
+ naxes = astGetNaxes( this );
+
+/* Obtain workspace. */
+ aa = (double *) astMalloc( sizeof(double)*naxes );
+
+/* Create a position which is offset slightly from point A in the
+ positive direction of the specified axis. Also get the largest absolute
+ value of any component of the vector AB. */
+ if( astOK ) {
+ ok = 1;
+ mxab = 0.0;
+
+ for( iaxis = 0; iaxis < naxes; iaxis++ ) {
+ if( a[ iaxis ] != AST__BAD && b[ iaxis ] != AST__BAD ) {
+ aa[ iaxis ] = a[ iaxis ];
+ ab = fabs( a[ iaxis ] - b[ iaxis ] );
+ if( ab > mxab ) mxab = ab;
+ } else {
+ ok = 0;
+ break;
+ }
+ }
+
+ if( ok ) {
+
+ if( a[ axis - 1 ] != 0.0 ) {
+ aa[ axis - 1 ] += 10000.0*DBL_EPSILON*fabs( a[ axis - 1 ] );
+
+ } else if( b[ axis - 1 ] != 0.0 ) {
+ aa[ axis - 1 ] = 10000.0*DBL_EPSILON*fabs( b[ iaxis - 1 ] );
+
+ } else if( mxab != 0.0 ) {
+ aa[ axis - 1 ] = 10000.0*DBL_EPSILON*mxab;
+
+ } else {
+ aa[ axis - 1 ] = 1.0;
+ }
+
+/* Use astAngle to get the required angle. */
+ result = astAngle( this, aa, a, b );
+ }
+ }
+
+/* Free the workspace. */
+ aa = (double *) astFree( (void *) aa );
+
+/* Return the result. */
+ return result;
+
+}
+
+static double AxDistance( AstFrame *this, int axis, double v1, double v2, int *status ) {
+/*
+*++
+* Name:
+c astAxDistance
+f AST_AXDISTANCE
+
+* Purpose:
+* Find the distance between two axis values.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c double astAxDistance( AstFrame *this, int axis, double v1, double v2 )
+f RESULT = AST_AXDISTANCE( THIS, AXIS, V1, V2, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function returns a signed value representing the axis increment
+f This routine returns a signed value representing the axis increment
+* from axis value v1 to axis value v2.
+*
+* For a simple Frame, this is a trivial operation returning the
+* difference between the two axis values. But for other derived classes
+* of Frame (such as a SkyFrame) this is not the case.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c axis
+f AXIS = INTEGER (Given)
+* The index of the axis to which the supplied values refer. The
+* first axis has index 1.
+c v1
+f V1 = DOUBLE PRECISION (Given)
+* The first axis value.
+c v2
+f V2 = DOUBLE PRECISION (Given)
+* The second axis value.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astAxDistance
+f AST_AXDISTANCE = DOUBLE PRECISION
+* The distance from the first to the second axis value.
+
+* Notes:
+* - This function will return a "bad" result value (AST__BAD) if
+* any of the input values has this value.
+* - A "bad" value will also be returned if this function is
+c invoked with the AST error status set, or if it should fail for
+f invoked with STATUS set to an error value, or if it should fail for
+* any reason.
+*--
+
+* Implementation Deficiencies;
+* - The protected interface for this function uses 1-based axis
+* numbering (like the public interface), rather than the more usual
+* zero-based system used by all other protected interfaces. There is
+* no real reason for this, and it should be changed at some time.
+
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ double result; /* The returned answer */
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate the axis index and obtain a pointer to the required Axis. */
+ (void) astValidateAxis( this, axis - 1, 1, "astAxDistance" );
+ ax = astGetAxis( this, axis - 1 );
+
+/* Use the AxisDistance method associated with the Axis. */
+ if( astOK ) result = astAxisDistance( ax, v1, v2 );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* Return the result. */
+ return result;
+
+}
+
+static void AxNorm( AstFrame *this, int axis, int oper, int nval,
+ double *values, int *status ){
+/*
+*++
+* Name:
+c astAxNorm
+f AST_AXNORM
+
+* Purpose:
+* Normalise an array of axis values.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c void astAxNorm( AstFrame *this, int axis, int oper, int nval,
+c double *values, int *status )
+f CALL AST_AXNORM( THIS, AXIS, OPER, NVAL, VALUES, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function
+f This routine
+* modifies a supplied array of axis values so that they are normalised
+* in the manner indicated by
+c parameter "oper".
+f argument 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]. See the
+* "Applicability:" section below for details.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c axis
+f AXIS = INTEGER (Given)
+* The index of the axis to which the supplied values refer. The
+* first axis has index 1.
+c oper
+f OPER = INTEGER (Given)
+* Indicates the type of normalisation to be applied. If zero is
+* supplied, the normalisation will be the same as that performed by
+c function astNorm.
+f routine AST_NORM.
+* If 1 is supplied, the normalisation will be chosen automatically
+* so that the resulting list has the smallest range.
+c nval
+f NVAL = INTEGER (Given)
+* The number of points in the values array.
+c values
+f VALUES( NVAL ) = DOUBLE PRECISION (Given and Returned)
+* On entry, the axis values to be normalised. Modified on exit to
+* hold the normalised values.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Applicability:
+* SkyFrame
+c If "oper"
+f If OPER
+* is 0, longitude values are returned in the range [0,2*PI].
+c If "oper"
+f If OPER
+* is 1, longitude values are returned in either the range
+* [0,2*PI] or [-PI,PI]. The choice is made so that that the
+* resulting list has the smallest range. Latitude values are
+* always returned in the range [-PI,PI].
+* All other classes of Frame
+* The supplied axis values are returned unchanged.
+
+*--
+
+* Implementation Deficiencies;
+* - The protected interface for this function uses 1-based axis
+* numbering (like the public interface), rather than the more usual
+* zero-based system used by all other protected interfaces. There is
+* no real reason for this, and it should be changed at some time.
+
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Validate the axis index and obtain a pointer to the required Axis. */
+ (void) astValidateAxis( this, axis - 1, 1, "astAxNorm" );
+ ax = astGetAxis( this, axis - 1 );
+
+/* Validate ther "oper" value. */
+ if( ( oper < 0 || oper > 1 ) && astOK ) {
+ astError( AST__OPRIN, "astAxNorm(%s): Invalid operation %d.", status,
+ astGetClass( this ), oper );
+ }
+
+/* Use the AxisNormValues method associated with the Axis. */
+ if( astOK ) astAxisNormValues( ax, oper, nval, values );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+}
+
+static int AxIn( AstFrame *this, int axis, double lo, double hi, double val,
+ int closed, int *status ){
+/*
+*+
+* Name:
+* astAxIn
+
+* Purpose:
+* Test if an axis value lies within a given interval.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astAxIn( AstFrame *this, int axis, double lo, double hi, double val,
+* int closed )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function returns non-zero if a given axis values lies within a
+* given axis interval.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The index of the axis. The first axis has index 0.
+* lo
+* The lower axis limit of the interval.
+* hi
+* The upper axis limit of the interval.
+* val
+* The axis value to be tested.
+* closed
+* If non-zero, then the lo and hi axis values are themselves
+* considered to be within the interval. Otherwise they are outside.
+
+* Returned Value:
+* Non-zero if the test value is inside the interval.
+
+* Applicability:
+* Frame
+* Uses simple Euclidean test
+* SkyFrame
+* All angles which are numerically between "lo" and "hi" are within
+* the interval. Angle outside this range are also within the interval
+* if they can be brought into the range by addition or subtraction
+* of a multiple of 2.PI.
+*-
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ int result; /* Returned value */
+
+/* For speed, omit the astOK check and axis validation (since this is
+ protected code, AST should get it right). Obtain a pointer to the
+ required Axis. */
+ ax = astGetAxis( this, axis );
+
+/* Use the AxisIn method associated with the Axis. */
+ result = ax ? astAxisIn( ax, lo, hi, val, closed ) : 0;
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* Return the result. */
+ return result;
+}
+
+static double AxOffset( AstFrame *this, int axis, double v1, double dist, int *status ) {
+/*
+*++
+* Name:
+c astAxOffset
+f AST_AXOFFSET
+
+* Purpose:
+* Add an increment onto a supplied axis value.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c double astAxOffset( AstFrame *this, int axis, double v1, double dist )
+f RESULT = AST_AXOFFSET( THIS, AXIS, V1, DIST, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function returns an axis value formed by adding a signed axis
+f This routine returns an axis value formed by adding a signed axis
+* increment onto a supplied axis value.
+*
+* For a simple Frame, this is a trivial operation returning the
+* sum of the two supplied values. But for other derived classes
+* of Frame (such as a SkyFrame) this is not the case.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c axis
+f AXIS = INTEGER (Given)
+* The index of the axis to which the supplied values refer. The
+* first axis has index 1.
+c v1
+f V1 = DOUBLE PRECISION (Given)
+* The original axis value.
+c dist
+f DIST = DOUBLE PRECISION (Given)
+* The axis increment to add to the original axis value.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astAxOffset
+f AST_AXOFFSET = DOUBLE PRECISION
+* The incremented axis value.
+
+* Notes:
+* - This function will return a "bad" result value (AST__BAD) if
+* any of the input values has this value.
+* - A "bad" value will also be returned if this function is
+c invoked with the AST error status set, or if it should fail for
+f invoked with STATUS set to an error value, or if it should fail for
+* any reason.
+*--
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ double result; /* The returned answer */
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate the axis index and obtain a pointer to the required Axis. */
+ (void) astValidateAxis( this, axis - 1, 1, "astAxOffset" );
+ ax = astGetAxis( this, axis - 1 );
+
+/* Use the AxisOffset method associated with the Axis. */
+ if( astOK ) result = astAxisOffset( ax, v1, dist );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* Return the result. */
+ return result;
+
+}
+
+static double Centre( AstFrame *this, int axis, double value, double gap, int *status ) {
+/*
+*+
+* Name:
+* astCentre
+
+* Purpose:
+* Find a "nice" central value for tabulating Axis values.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* double astCentre( AstFrame *this, int axis, double value, double gap )
+
+* Class Membership:
+* Frame method.
+
+* 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 gap 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: */
+ AstAxis *ax; /* Pointer to Axis object */
+ double result; /* The nice central value */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0.0;
+
+/* Validate the axis index and obtain a pointer to the required
+ Axis. */
+ (void) astValidateAxis( this, axis, 1, "astCentre" );
+ ax = astGetAxis( this, axis );
+
+/* Find the nice central value. */
+ result = astAxisCentre( ax, value, gap );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0.0;
+
+/* Return the result. */
+ return result;
+}
+
+static void CheckPerm( AstFrame *this, const int *perm, const char *method, int *status ) {
+/*
+*+
+* Name:
+* astCheckPerm
+
+* Purpose:
+* Check that an array contains a valid permutation.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astCheckPerm( AstFrame *this, const int *perm, const char *method )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function checks the validity of a permutation array that
+* will be used to permute the order of a Frame's axes. If the
+* permutation specified by the array is not valid, an error is
+* reported and the global error status is set. Otherwise, the
+* function returns without further action.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* perm
+* Pointer to an array of integers with the same number of
+* elements as there are axes in the Frame. For each axis, the
+* corresponding integer gives the (zero based) axis index to be
+* used to identify the information for that axis (using the
+* un-permuted axis numbering). To be valid, the integers in
+* this array should therefore all lie in the range zero to
+* (naxes-1) inclusive, where "naxes" is the number of Frame
+* axes, and each value should occur exactly once.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate a permutation array. This method name is used
+* solely for constructing error messages.
+
+* Notes:
+* - Error messages issued by this function refer to the external
+* (public) numbering system used for axes (which is one-based),
+* whereas zero-based axis indices are used internally.
+*-
+*/
+
+/* Local Variables: */
+ int *there; /* Pointer to temporary array */
+ int axis; /* Loop counter for axes */
+ int naxes; /* Number of Frame axes */
+ int valid; /* Permutation array is valid? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Initialise. */
+ valid = 1;
+
+/* Obtain the number of Frame axes and allocate a temporary array of integers
+ with the same number of elements. */
+ naxes = astGetNaxes( this );
+ there = astMalloc( sizeof( int ) * (size_t) naxes );
+ if ( astOK ) {
+
+/* Initialise the temporary array to zero. */
+ for ( axis = 0; axis < naxes; axis++ ) there[ axis ] = 0;
+
+/* Scan the permutation array, checking that each permuted axis index it
+ contains is within the correct range. Note an error and quit checking
+ if an invalid value is found. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+ if ( ( perm[ axis ] < 0 ) || ( perm[ axis ] >= naxes ) ) {
+ valid = 0;
+ break;
+
+/* Use the temporary array to count how many times each valid axis index
+ occurs. */
+ } else {
+ there[ perm[ axis ] ]++;
+ }
+ }
+
+/* If all the axis indices were within range, check to ensure that each value
+ occurred only once. */
+ if ( valid ) {
+ for ( axis = 0; axis < naxes; axis++ ) {
+
+/* Note an error and quit checking if any value did not occur exactly once. */
+ if ( there[ axis ] != 1 ) {
+ valid = 0;
+ break;
+ }
+ }
+ }
+ }
+
+/* Free the temporary array. */
+ there = astFree( there );
+
+/* If an invalid permutation was detected and no other error has
+ occurred, then report an error (note we convert to one-based axis
+ numbering in the error message). */
+ if ( !valid && astOK ) {
+ astError( AST__PRMIN, "%s(%s): Invalid axis permutation array.", status,
+ method, astGetClass( this ) );
+ astError( AST__PRMIN, "Each axis index should lie in the range 1 to %d "
+ "and should occur only once.", status, naxes );
+ }
+}
+
+static void CleanAttribs( AstObject *this_object, int *status ) {
+/*
+* Name:
+* CleanAttribs
+
+* Purpose:
+* Clear any invalid set attribute values.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* void CleanAttribs( AstObject *this_object, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the protected astCleanAttribs
+* method inherited from the Object class).
+
+* Description:
+* This function clears any attributes that are currently set to
+* invalid values in thr supplied object.
+
+* Parameters:
+* this
+* Pointer to the Object to be cleaned.
+
+*/
+
+/* Local Variables; */
+ AstAxis *ax;
+ AstFrame *this;
+ int i;
+ int nax;
+ int reporting;
+
+/* Check inherited status */
+ if( !astOK ) return;
+
+/* Get a pointer to the Frame structure. */
+ this = (AstFrame *) this_object;
+
+/* Defer error reporting, as required by the astCLEAN_ATTRIB macro. */
+ reporting = astReporting( 0 );
+
+/* Clean attributes in any Objects contained within "this". */
+ nax = astGetNaxes( this );
+ for( i = 0; i < nax; i++ ) {
+ ax = astGetAxis( this, i );
+ astCleanAttribs( ax );
+ ax = astAnnul( ax );
+ }
+
+/* Clean attributes of this class. */
+ astCLEAN_ATTRIB(System)
+ astCLEAN_ATTRIB(AlignSystem)
+
+/* Re-establish error reporting. */
+ astReporting( reporting );
+
+/* Invoke the method inherited form the parent to clean attributes
+ defined by the parent class. */
+ (*parent_cleanattribs)( this_object, status );
+}
+
+static char *CleanDomain( char *domain, int *status ) {
+/*
+* Name:
+* CleanDomain
+
+* Purpose:
+* Clean a Domain string and convert to upper case.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* char *CleanDomain( char *domain, int *status )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function removes all white space from a string and converts
+* other characters to upper case. It is intended for cleaning up
+* values supplied for the Domain attribute of a Frame.
+
+* Parameters:
+* domain
+* Pointer to the null terminated Domain string to be modified.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The pointer value "domain" is always returned (even under error
+* conditions).
+*/
+
+/* Local Variables: */
+ int i; /* Loop counter for characters */
+ int j; /* Good character count */
+
+/* Check the global error status. */
+ if ( !astOK ) return domain;
+
+/* Eliminate white space characters and convert the rest to upper
+ case. */
+ for ( i = j = 0; domain[ i ]; i++ ) {
+ if ( !isspace( domain[ i ] ) ) domain[ j++ ] = toupper( domain[ i ] );
+ }
+ domain[ j ] = '\0';
+
+/* Return the string pointer. */
+ return domain;
+}
+
+static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* ClearAttrib
+
+* Purpose:
+* Clear an attribute value for a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* void ClearAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the astClearAttrib protected
+* method inherited from the Mapping class).
+
+* Description:
+* This function clears the value of a specified attribute for a
+* Frame, so that the default value will subsequently be used.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* attrib
+* Pointer to a null terminated string specifying the attribute
+* name. This should be in lower case with no surrounding white
+* space.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - This function uses one-based axis numbering so that it is
+* suitable for external (public) use.
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis */
+ AstFrame *pfrm; /* Pointer to primary Frame containing axis */
+ AstFrame *this; /* Pointer to the Frame structure */
+ char pfrm_attrib[ 100 ]; /* Primary Frame attribute */
+ char *axis_attrib; /* Pointer to axis attribute name */
+ const char *old_attrib; /* Pointer to supplied attribute name string */
+ int axis; /* Frame axis number */
+ int axis_nc; /* No. characters in axis attribute name */
+ int free_axis_attrib; /* Should axis_attrib be freed? */
+ int has_axis; /* Does attrib name include axis specifier? */
+ int len; /* Length of attrib string */
+ int nc; /* No. characters read by astSscanf */
+ int oldrep; /* Original error reporting state */
+ int paxis; /* Axis index within primary frame */
+ int used; /* Could the setting string be used? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_object;
+
+/* Set a flag indicating if the attribute name includes an axis
+ specifier. */
+ has_axis = ( strchr( attrib, '(' ) != NULL );
+
+/* A flag indicating that we do not need to free the axis_attrib memory. */
+ free_axis_attrib = 0;
+
+/* Initialise things to avoid compiler warnings. */
+ axis_attrib = NULL;
+ old_attrib = NULL;
+
+/* Jump back to here if we are trying the same attribute but with an explicit
+ axis "(1)" added to the end of the name. */
+L1:
+
+/* Obtain the length of the "attrib" string. */
+ len = strlen( attrib );
+
+/* Check the attribute name and clear the appropriate attribute. */
+
+/* Digits. */
+/* ------- */
+ if ( !strcmp( attrib, "digits" ) ) {
+ astClearDigits( this );
+
+/* Digits(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+
+/* There is no function to clear the Digits attribute for an axis
+ directly, so obtain a pointer to the Axis and use this to clear the
+ attribute. */
+ (void) astValidateAxis( this, axis - 1, 1, "astClearDigits(axis)" );
+ ax = astGetAxis( this, axis - 1 );
+ astClearAxisDigits( ax );
+ ax = astAnnul( ax );
+
+/* Direction(axis). */
+/* ---------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ astClearDirection( this, axis - 1 );
+
+/* Epoch. */
+/* ------ */
+ } else if ( !strcmp( attrib, "epoch" ) ) {
+ astClearEpoch( this );
+
+/* Top(axis). */
+/* ---------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ astClearTop( this, axis - 1 );
+
+/* Bottom(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ astClearBottom( this, axis - 1 );
+
+/* Domain. */
+/* ------- */
+ } else if ( !strcmp( attrib, "domain" ) ) {
+ astClearDomain( this );
+
+/* Format(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ astClearFormat( this, axis - 1 );
+
+/* Label(axis). */
+/* ------------ */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ astClearLabel( this, axis - 1 );
+
+/* MatchEnd. */
+/* --------- */
+ } else if ( !strcmp( attrib, "matchend" ) ) {
+ astClearMatchEnd( this );
+
+/* MaxAxes. */
+/* -------- */
+ } else if ( !strcmp( attrib, "maxaxes" ) ) {
+ astClearMaxAxes( this );
+
+/* MinAxes. */
+/* -------- */
+ } else if ( !strcmp( attrib, "minaxes" ) ) {
+ astClearMinAxes( this );
+
+/* Permute. */
+/* -------- */
+ } else if ( !strcmp( attrib, "permute" ) ) {
+ astClearPermute( this );
+
+/* PreserveAxes. */
+/* ------------- */
+ } else if ( !strcmp( attrib, "preserveaxes" ) ) {
+ astClearPreserveAxes( this );
+
+/* Symbol(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ astClearSymbol( this, axis - 1 );
+
+/* System. */
+/* ------- */
+ } else if ( !strcmp( attrib, "system" ) ) {
+ astClearSystem( this );
+
+/* AlignSystem. */
+/* ------------ */
+ } else if ( !strcmp( attrib, "alignsystem" ) ) {
+ astClearAlignSystem( this );
+
+/* Title. */
+/* ------ */
+ } else if ( !strcmp( attrib, "title" ) ) {
+ astClearTitle( this );
+
+/* Unit(axis). */
+/* ----------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ astClearUnit( this, axis - 1 );
+
+/* ObsLat. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obslat" ) ) {
+ astClearObsLat( this );
+
+/* ObsLon. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obslon" ) ) {
+ astClearObsLon( this );
+
+/* ObsAlt. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obsalt" ) ) {
+ astClearObsAlt( this );
+
+/* Dtai */
+/* --- */
+ } else if ( !strcmp( attrib, "dtai" ) ) {
+ astClearDtai( this );
+
+/* Dut1 */
+/* --- */
+ } else if ( !strcmp( attrib, "dut1" ) ) {
+ astClearDut1( this );
+
+/* Read-only attributes. */
+/* --------------------- */
+/* Test if the attribute name matches any of the read-only attributes
+ of this class. If it does, then report an error. */
+ } else if ( !strcmp( attrib, "naxes" ) ||
+ !strncmp( attrib, "normunit", 8 ) ||
+ !strncmp( attrib, "internalunit", 12 ) ) {
+ astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" "
+ "value for a %s.", status, attrib, astGetClass( this ) );
+ astError( AST__NOWRT, "This is a read-only attribute." , status);
+
+/* Other axis attributes. */
+/* ---------------------- */
+/* If the attribute was not identified above, but appears to refer to
+ a Frame axis, then it may refer to an Axis object of a derived type
+ (which has additional attributes not recognised here). */
+ } else if( !free_axis_attrib && ( nc = 0,
+ ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n",
+ &axis_nc, &axis, &nc ) )
+ && ( nc >= len ) ) ) {
+
+/* Validate the axis index and extract the attribute name. */
+ (void) astValidateAxis( this, axis - 1, 1, "astClear" );
+ axis_attrib = astString( attrib, axis_nc );
+
+/* Obtain a pointer to the Axis object. */
+ ax = astGetAxis( this, axis - 1 );
+ if( astOK ) {
+
+/* Assume that we will be able to use the attribute name. */
+ used = 1;
+
+/* Temporarily switch off error reporting so that if the following attempt
+ to access the axis attribute fails, we can try to interpret the
+ attribute name as an attribute of the primary Frame containing the
+ specified axis. Any errors reported in this context will simply be
+ ignored, in particularly they are not deferred for later delivery. */
+ oldrep = astReporting( 0 );
+
+/* Use the Axis astClearAttrib method to clear the attribute value. */
+ astClearAttrib( ax, axis_attrib );
+
+/* If the above call failed with a status of AST__BADAT, indicating that
+ the attribute name was not recognised, clear the status so that we can
+ try to interpret the attribute name as an attribute of the primary Frame
+ containing the specified axis. */
+ if( astStatus == AST__BADAT ) {
+ astClearStatus;
+
+/* Find the primary Frame containing the specified axis. */
+ astPrimaryFrame( this, axis - 1, &pfrm, &paxis );
+
+/* Only attempt to use the primary Frame if it is not the same as "this"
+ - otherwise we could end up in an infinite loop. */
+ if( pfrm != this ) {
+
+/* astPrimaryFrame returns the original - unpermuted - axis index within
+ the primary Frame. So we need to take into account any axis permutation
+ which has been applied to the primary Frame when forming the attribute name
+ to use below. Find the permuted (external) axis index which corresponds to
+ the internal (unpermuted) axis index "paxis". */
+ paxis = astValidateAxis( pfrm, paxis, 0, "astClear" );
+
+/* Modify the attribute name to refer to the axis numbering of the
+ primary frame. */
+ sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 );
+
+/* Attempt to clear the attribute as an attribute of the primary Frame. */
+ astClearAttrib( pfrm, pfrm_attrib );
+
+/* If this failed, clear the status and indicate that we have not managed to
+ use the attribute name. */
+ if( !astOK ) {
+ astClearStatus;
+ used = 0;
+ }
+
+ } else {
+ used = 0;
+ }
+
+/* If not found attempt to clear the attribute value in the Axis, omitting
+ the axis index. */
+ if( ! used ) {
+ astClearAttrib( pfrm, axis_attrib );
+ if( !astOK ) {
+ astClearStatus;
+ } else {
+ used = 1;
+ }
+ }
+
+/* Annul the primary Frame pointer. */
+ pfrm = astAnnul( pfrm );
+ }
+
+/* Re-instate the original error reporting state. */
+ astReporting( oldrep );
+
+/* If we could not use the attribute name, attempt to clear the axis
+ attribute again, this time retaining the error report. This is done
+ to ensure the user gets an appropriate error message. */
+ if( !used ) astClearAttrib( ax, axis_attrib );
+ }
+
+/* Annul the Axis pointer and free the memory holding the attribute
+ name. */
+ ax = astAnnul( ax );
+ axis_attrib = astFree( axis_attrib );
+
+/* Not recognised. */
+/* --------------- */
+/* If the attribute is still not recognised, and the Frame has only 1 axis,
+ and the attribute name does not already include an axis specifier, try
+ again after appending "(1)" to the end of the attribute name. */
+ } else if( !has_axis && astGetNaxes( this ) == 1 ) {
+
+/* Take a copy of the supplied name, allowing 3 extra characters for the
+ axis specifier "(1)". */
+ axis_attrib = astMalloc( len + 4 );
+ if( axis_attrib ) memcpy( axis_attrib, attrib, len );
+
+/* Indicate we should free the axis_attrib memory. */
+ free_axis_attrib = 1;
+
+/* Add in the axis specifier. */
+ strcpy( axis_attrib + len, "(1)" );
+
+/* Use the new attribute name instead of the supplied name. */
+ old_attrib = attrib;
+ attrib = axis_attrib;
+
+/* Indicate the attribute name now has an axis specifier. */
+ has_axis = 1;
+
+/* Jump back to try interpreting the new attribute name. */
+ goto L1;
+
+/* Not recognised. */
+/* --------------- */
+/* If the attribute name is still not recognised, pass it on to the parent
+ method for further interpretation. First re-instate the original attrib
+ name string if it was changed above. */
+ } else {
+ if( free_axis_attrib ) {
+ attrib = old_attrib;
+ axis_attrib = astFree( axis_attrib );
+ }
+ (*parent_clearattrib)( this_object, attrib, status );
+ }
+}
+
+static void ClearUnit( AstFrame *this, int axis, int *status ) {
+/*
+* Name:
+* ClearUnit
+
+* Purpose:
+* Clear the Unit attribute of a Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void ClearUnit( AstFrame *this, int axis, int *status )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function clears the Unit value for an axis of a Frame.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the axis (zero-based) for which the Unit value is to
+* be cleared.
+* unit
+* The new value to be set.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* void.
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ const char *units; /* Pointer to units string */
+ char *old_units; /* Pointer to copy of original units */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astSetUnit" );
+
+/* Do nothing more if the attribute is already cleared. */
+ if( astTestUnit( this, axis ) ) {
+
+/* Obtain a pointer to the required Axis. */
+ ax = astGetAxis( this, axis );
+
+/* Save a copy of the old units. */
+ units = astGetAxisUnit( ax );
+ old_units = astStore( NULL, units, strlen( units ) + 1 );
+
+/* Clear the Axis Unit attribute value, and then get a pointer to the
+ new default Units string. */
+ astClearAxisUnit( ax );
+ units = astGetUnit( this, axis );
+
+/* The new unit may require the Label and/or Symbol to be changed, but
+ only if the Frames ActiveUnit flag is set. */
+ if( astGetActiveUnit( this ) ) NewUnit( ax, old_units, units,
+ "astSetUnit", astGetClass( this ), status );
+
+/* Free resources. */
+ old_units = astFree( old_units );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+ }
+}
+
+static int ConsistentMaxAxes( AstFrame *this, int value, int *status ) {
+/*
+* Name:
+* ConsistentMaxAxes
+
+* Purpose:
+* Ensure a consistent value when setting the MaxAxes attribute.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int ConsistentMaxAxes( AstFrame *this, int value, int *status )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function accepts a value which is to be set for a Frame's MaxAxes
+* attribute and returns an appropriately adjusted value to be assigned
+* to the Frame structure's max_axes component. If necessary, the Frame's
+* MinAxes attribute is adjusted to remain consistent with the new MaxAxes
+* value (but note that the MaxAxes value itself is not assigned by this
+* function).
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* value
+* The new value being set for the MaxAxes attribute.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The value to be assigned to the max_axes component.
+
+* Notes:
+* - A value of -INT_MAX will be returned if this function is
+* invoked with the global error status set, or if it should fail
+* for any reason.
+*/
+
+/* Local Variables: */
+ int result; /* Result to be returned */
+
+/* Check the global error status. */
+ if ( !astOK ) return -INT_MAX;
+
+/* Ensure that the result value isn't negative. */
+ result = ( value >= 0 ) ? value : 0;
+
+/* Check if the MinAxes attribute is set. If not, its default value will be
+ consistent with the MaxAxes value (the DefaultMinAxes function ensures
+ this). Otherwise, obtain its value to check for consistency. */
+ if ( astTestMinAxes( this ) ) {
+
+/* If necessary, set a new MinAxes value to prevent it exceeding the MaxAxes
+ value about to be returned. */
+ if ( astGetMinAxes( this ) > result ) astSetMinAxes( this, result );
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = -INT_MAX;
+
+/* Return the result. */
+ return result;
+}
+
+static int ConsistentMinAxes( AstFrame *this, int value, int *status ) {
+/*
+* Name:
+* ConsistentMinAxes
+
+* Purpose:
+* Ensure a consistent value when setting the MinAxes attribute.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int ConsistentMinAxes( AstFrame *this, int value, int *status )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function accepts a value which is to be set for a Frame's MinAxes
+* attribute and returns an appropriately adjusted value to be assigned
+* to the Frame structure's min_axes component. If necessary, the Frame's
+* MaxAxes attribute is adjusted to remain consistent with the new MinAxes
+* value (but note that the MinAxes value itself is not assigned by this
+* function).
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* value
+* The new value being set for the MinAxes attribute.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The value to be assigned to the min_axes component.
+
+* Notes:
+* - A value of -INT_MAX will be returned if this function is
+* invoked with the global error status set, or if it should fail
+* for any reason.
+*/
+
+/* Local Variables: */
+ int result; /* Result to be returned */
+
+/* Check the global error status. */
+ if ( !astOK ) return -INT_MAX;
+
+/* Ensure that the result value isn't negative. */
+ result = ( value >= 0 ) ? value : 0;
+
+/* Check if the MaxAxes attribute is set. If not, its default value will be
+ consistent with the MinAxes value (the DefaultMaxAxes function ensures
+ this). Otherwise, obtain its value to check for consistency. */
+ if ( astTestMaxAxes( this ) ) {
+
+/* If necessary, set a new MaxAxes value to prevent it being less than the
+ MinAxes value about to be returned. */
+ if ( astGetMaxAxes( this ) < result ) astSetMaxAxes( this, result );
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = -INT_MAX;
+
+/* Return the result. */
+ return result;
+}
+
+static AstFrameSet *Convert( AstFrame *from, AstFrame *to,
+ const char *domainlist, int *status ) {
+/*
+*++
+* Name:
+c astConvert
+f AST_CONVERT
+
+* Purpose:
+* Determine how to convert between two coordinate systems.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c AstFrameSet *astConvert( AstFrame *from, AstFrame *to,
+c const char *domainlist )
+f RESULT = AST_CONVERT( FROM, TO, DOMAINLIST, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function compares two Frames and determines whether it is
+* possible to convert between the coordinate systems which they
+* represent. If conversion is possible, it returns a FrameSet
+* which describes the conversion and which may be used (as a
+* Mapping) to transform coordinate values in either direction.
+*
+* The same function may also be used to determine how to convert
+* between two FrameSets (or between a Frame and a FrameSet, or
+* vice versa). This mode is intended for use when (for example)
+* two images have been calibrated by attaching a FrameSet to each.
+c astConvert might then be used to search for a
+f AST_CONVERT might then be used to search for a
+* celestial coordinate system that both images have in common, and
+* the result could then be used to convert between the pixel
+* coordinates of both images -- having effectively used their
+* celestial coordinate systems to align them.
+*
+* When using FrameSets, there may be more than one possible
+* intermediate coordinate system in which to perform the
+* conversion (for instance, two FrameSets might both have
+* celestial coordinates, detector coordinates, pixel coordinates,
+* etc.). A comma-separated list of coordinate system domains may
+* therefore be given which defines a priority order to use when
+* selecting the intermediate coordinate system. The path used for
+* conversion must go via an intermediate coordinate system whose
+* Domain attribute matches one of the domains given. If conversion
+* cannot be achieved using the first domain, the next one is
+* considered, and so on, until success is achieved.
+
+* Parameters:
+c from
+f FROM = INTEGER (Given)
+* Pointer to a Frame which represents the "source" coordinate
+* system. This is the coordinate system in which you already
+* have coordinates available.
+*
+* If a FrameSet is given, its current Frame (as determined by
+* its Current attribute) is taken to describe the source
+* coordinate system. Note that the Base attribute of this
+* FrameSet may be modified by this function to indicate which
+* intermediate coordinate system was used (see under
+* "FrameSets" in the "Applicability" section for details).
+c to
+f TO = INTEGER (Given)
+* Pointer to a Frame which represents the "destination"
+* coordinate system. This is the coordinate system into which
+* you wish to convert your coordinates.
+*
+* If a FrameSet is given, its current Frame (as determined by
+* its Current attribute) is taken to describe the destination
+* coordinate system. Note that the Base attribute of this
+* FrameSet may be modified by this function to indicate which
+* intermediate coordinate system was used (see under
+* "FrameSets" in the "Applicability" section for details).
+c domainlist
+f DOMAINLIST = CHARACTER * ( * ) (Given)
+c Pointer to a null-terminated character string containing a
+f A character string containing a
+* comma-separated list of Frame domains. This may be used to
+* define a priority order for the different intermediate
+* coordinate systems that might be used to perform the
+* conversion.
+*
+* The function will first try to obtain a conversion by making
+* use only of an intermediate coordinate system whose Domain
+* attribute matches the first domain in this list. If this
+* fails, the second domain in the list will be used, and so on,
+* until conversion is achieved. A blank domain (e.g. two
+* consecutive commas) indicates that all coordinate systems
+* should be considered, regardless of their domains.
+*
+* This list is case-insensitive and all white space is ignored.
+* If you do not wish to restrict the domain in this way,
+c you should supply an empty string. This is normally
+f you should supply a blank string. This is normally
+* appropriate if either of the source or destination coordinate
+* systems are described by Frames (rather than FrameSets),
+* since there is then usually only one possible choice of
+* intermediate coordinate system.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astConvert()
+f AST_CONVERT = INTEGER
+* If the requested coordinate conversion is possible, the
+* function returns a pointer to a FrameSet which describes the
+* conversion. Otherwise, a null Object pointer (AST__NULL) is
+* returned without error.
+*
+* If a FrameSet is returned, it will contain two Frames. Frame
+* number 1 (its base Frame) will describe the source coordinate
+c system, corresponding to the "from" parameter. Frame number 2
+f system, corresponding to the FROM argument. Frame number 2
+* (its current Frame) will describe the destination coordinate
+c system, corresponding to the "to" parameter. The Mapping
+f system, corresponding to the TO argument. The Mapping
+* which inter-relates these two Frames will perform the
+* required conversion between their respective coordinate
+* systems.
+*
+* Note that a FrameSet may be used both as a Mapping and as a
+* Frame. If the result is used as a Mapping (e.g. with
+c astTran2), then it provides a means of converting coordinates
+f AST_TRAN2), then it provides a means of converting coordinates
+* from the source to the destination coordinate system (or
+* vice versa if its inverse transformation is selected). If it
+* is used as a Frame, its attributes will describe the
+* destination coordinate system.
+
+* Applicability:
+* DSBSpecFrame
+* If the AlignSideBand attribute is non-zero, alignment occurs in the
+* upper sideband expressed within the spectral system and standard of
+* rest given by attributes AlignSystem and AlignStdOfRest. If
+* AlignSideBand is zero, the two DSBSpecFrames are aligned as if
+* they were simple SpecFrames (i.e. the SideBand is ignored).
+* Frame
+* This function applies to all Frames. Alignment occurs within the
+* coordinate system given by attribute AlignSystem.
+* FrameSet
+c If either of the "from" or "to" parameters is a pointer to a
+f If either of the FROM or TO arguments is a pointer to a
+c FrameSet, then astConvert will attempt to convert from the
+f FrameSet, then AST_CONVERT will attempt to convert from the
+c coordinate system described by the current Frame of the "from"
+f coordinate system described by the current Frame of the FROM
+c FrameSet to that described by the current Frame of the "to"
+f FrameSet to that described by the current Frame of the TO
+* FrameSet.
+*
+* To achieve this, it will consider all of the Frames within
+* each FrameSet as a possible way of reaching an intermediate
+* coordinate system that can be used for the conversion. There
+* is then the possibility that more than one conversion path
+* may exist and, unless the choice is sufficiently restricted
+c by the "domainlist" string, the sequence in which the Frames
+f by the DOMAINLIST string, the sequence in which the Frames
+* are considered can be important. In this case, the search
+* for a conversion path proceeds as follows:
+c - Each field in the "domainlist" string is considered in turn.
+f - Each field in the DOMAINLIST string is considered in turn.
+* - The Frames within each FrameSet are considered in a
+* specific order: (1) the base Frame is always considered
+* first, (2) after this come all the other Frames in
+* Frame-index order (but omitting the base and current Frames),
+* (3) the current Frame is always considered last. However, if
+* either FrameSet's Invert attribute is set to a non-zero value
+* (so that the FrameSet is inverted), then its Frames are
+* considered in reverse order. (Note that this still means that
+* the base Frame is considered first and the current Frame
+* last, because the Invert value will also cause these Frames
+* to swap places.)
+* - All source Frames are first considered (in the appropriate
+* order) for conversion to the first destination Frame. If no
+* suitable intermediate coordinate system emerges, they are
+* then considered again for conversion to the second
+* destination Frame (in the appropriate order), and so on.
+* - Generally, the first suitable intermediate coordinate
+* system found is used. However, the overall Mapping between
+* the source and destination coordinate systems is also
+* examined. Preference is given to cases where both the
+* forward and inverse transformations are defined (as indicated
+* by the TranForward and TranInverse attributes). If only one
+* transformation is defined, the forward one is preferred.
+* - If the domain of the intermediate coordinate system matches
+c the current "domainlist" field, the conversion path is
+f the current DOMAINLIST field, the conversion path is
+c accepted. Otherwise, the next "domainlist" field is considered
+f accepted. Otherwise, the next DOMAINLIST field is considered
+* and the process repeated.
+*
+* If conversion is possible, the Base attributes of the two
+* FrameSets will be modified on exit to identify the Frames
+* used to access the intermediate coordinate system which was
+* finally accepted.
+*
+* Note that it is possible to force a particular Frame within a
+* FrameSet to be used as the basis for the intermediate
+* coordinate system, if it is suitable, by (a) focussing
+* attention on
+c it by specifying its domain in the "domainlist" string, or (b)
+f it by specifying its domain in the DOMAINLIST string, or (b)
+* making it the base Frame, since this is always considered
+* first.
+* SpecFrame
+* Alignment occurs within the spectral system and standard of rest
+* given by attributes AlignSystem and AlignStdOfRest.
+* TimeFrame
+* Alignment occurs within the time system and time scale given by
+* attributes AlignSystem and AlignTimeScale.
+
+* Examples:
+c cvt = astConvert( a, b, "" );
+f CVT = AST_CONVERT( A, B, ' ', STATUS )
+* Attempts to convert between the coordinate systems represented
+c by "a" and "b" (assumed to be Frames). If successful, a FrameSet
+f by A and B (assumed to be Frames). If successful, a FrameSet
+c is returned via the "cvt" pointer which may be used to apply the
+f is returned via the CVT pointer which may be used to apply the
+c conversion to sets of coordinates (e.g. using astTran2).
+f conversion to sets of coordinates (e.g. using AST_TRAN2).
+c cvt = astConvert( astSkyFrame(""), astSkyFrame("Equinox=2005"), "" );
+f CVT = AST_CONVERT( AST_SKYFRAME( ' ', STATUS ), AST_SKYFRAME( 'Equinox=2005', STATUS ), ' ', STATUS )
+* Creates a FrameSet which describes precession in the default
+* FK5 celestial coordinate system between equinoxes J2000 (also
+c the default) and J2005. The returned "cvt" pointer may then
+f the default) and J2005. The returned CVT pointer may then
+c be passed to astTran2 to apply this precession correction to
+f be passed to AST_TRAN2 to apply this precession correction to
+* any number of coordinate values given in radians.
+*
+* Note that the returned FrameSet also contains information
+* about how to format coordinate values. This means that
+* setting its Report attribute to 1 is a simple way to obtain
+* printed output (formatted in sexagesimal notation) to show
+* the coordinate values before and after conversion.
+c cvt = astConvert( a, b, "sky,detector," );
+f CVT = AST_CONVERT( A, B, 'SKY,DETECTOR,', STATUS )
+* Attempts to convert between the coordinate systems
+c represented by the current Frames of "a" and "b"
+f represented by the current Frames of A and B
+* (now assumed to be FrameSets), via the intermediate "SKY"
+* coordinate system. This, by default, is the Domain
+* associated with a celestial coordinate system represented by
+* a SkyFrame.
+*
+* If this fails (for example, because either FrameSet lacks
+* celestial coordinate information), then the user-defined
+* "DETECTOR" coordinate system is used instead. If this also
+* fails, then all other possible ways of achieving conversion
+* are considered before giving up.
+*
+c The returned pointer "cvt" indicates whether conversion was
+f The returned pointer CVT indicates whether conversion was
+* possible and will have the value AST__NULL if it was not. If
+c conversion was possible, "cvt" will point at a new FrameSet
+f conversion was possible, CVT will point at a new FrameSet
+* describing the conversion.
+*
+* The Base attributes of the two FrameSets
+c will be set by astConvert to indicate which of their Frames was
+f will be set by AST_CONVERT to indicate which of their Frames was
+* used for the intermediate coordinate system. This means that
+* you can subsequently determine which coordinate system was
+* used by enquiring the Domain attribute of either base Frame.
+
+* Notes:
+* - The Mapping represented by the returned FrameSet results in
+* alignment taking place in the coordinate system specified by the
+c AlignSystem attribute of the "to" Frame. See the description of the
+f AlignSystem attribute of the TO Frame. See the description of the
+* AlignSystem attribute for further details.
+* - When aligning (say) two images, which have been calibrated by
+* attaching FrameSets to them, it is usually necessary to convert
+* between the base Frames (representing "native" pixel
+* coordinates) of both FrameSets. This may be achieved by
+* inverting the FrameSets (e.g. using astInvert) so as to
+* interchange their base and current Frames before using
+* astConvert.
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+*--
+
+* Implementation Notes:
+* This function is simply a wrap-up for the protected astConvertX
+* method which performs the required processing but swaps the order
+* of the first two arguments. This is a trick to allow the
+* astConvert method to be over-ridden by derived classes on the
+* basis of the class of either of the first two arguments.
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Invoke the "astConvertX" method with the first two arguments
+ swapped. */
+ return astConvertX( to, from, domainlist );
+}
+
+static AstFrameSet *ConvertX( AstFrame *to, AstFrame *from,
+ const char *domainlist, int *status ) {
+/*
+*+
+* Name:
+* astConvertX
+
+* Purpose:
+* Determine how to convert between two coordinate systems.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* AstFrameSet *astConvertX( AstFrame *to, AstFrame *from,
+* const char *domainlist )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function performs the processing for the public astConvert
+* method and has exactly the same interface except that the order
+* of the first two arguments is swapped. This is a trick to allow
+* the astConvert method to be over-ridden by derived classes on
+* the basis of the class of either of its first two arguments.
+*
+* See the astConvert method for details of the interface.
+*-
+
+* Implementation Deficiencies:
+* - This function's job is basically to negotiate with two Frames
+* to try and find a mutually agreeable coordinate system for
+* conversion. Ideally, it should be able to juggle the number of
+* axes, etc. to do this. At present, however, the implementation
+* is much simpler. This is adequate for the Frame classes which
+* exist at the time of writing, but the implementation may need
+* beefing up in future.
+* - One likely problem is with attributes which default in both
+* the source and destination Frames. This means they also default
+* in the common coordinate system. If these default values were to
+* differ when matching different target Frames, however, we would
+* be in trouble, because the common coordinate system would not
+* then be remaining constant. The longer-term solution to this is
+* probably to provide some mechanism to "fix" all attribute values
+* for a Frame, by taking any attributes that are un-set and
+* explicitly setting a firm value (equal to the default) so they
+* cannot then change.
+*/
+
+/* Local Variables: */
+ AstFrameSet *result; /* Pointer to Mapping to be returned */
+ AstFrame *ftmp; /* Pointer to returned Frame */
+ AstMapping **map1_address; /* Location of first Mapping pointer */
+ AstMapping **map2_address; /* Location of second Mapping pointer */
+ AstMapping *common0; /* Initial common coordinate system */
+ AstMapping *common1; /* Improved common coordinate system */
+ AstMapping *common2; /* Final common coordinate system */
+ AstMapping *frame1; /* Pointer to Frame for first match */
+ AstMapping *frame2; /* Pointer to Frame for second match */
+ AstMapping *from_map; /* Pointer to "from" Mapping */
+ AstMapping *map; /* Pointer to conversion Mapping */
+ AstMapping *result_map; /* Pointer to result Mapping */
+ AstMapping *tmp; /* Temporary Mapping pointer */
+ AstMapping *to_map; /* Pointer to "to" Mapping */
+ char *domain; /* Pointer to result domain */
+ char *domain_end; /* Pointer to null at end of domain */
+ char *domainlist_copy; /* Pointer to copy of domainlist */
+ int *axes1; /* Pointer to axis assignments */
+ int *axes2; /* Pointer to axis assignments */
+ int best_score; /* Score assigned to best match */
+ int icom; /* Common coordinate system loop counter */
+ int match1; /* First match succeeded? */
+ int match2; /* Second match succeeded? */
+ int match; /* Overall match found? */
+ int perfect; /* Perfect match found? */
+ int score; /* Score assigned to match */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Further initialisation. */
+ result_map = NULL;
+
+/* Make a temporary copy of the domains list. */
+ domainlist_copy = astStore( NULL, domainlist,
+ strlen( domainlist ) + (size_t) 1 );
+ if ( astOK ) {
+
+/* Loop to inspect each comma-separated field in the domains list
+ until an error occurs, all the domains are used up, or a match is
+ found. */
+ domain = domainlist_copy;
+ match = 0;
+ while ( astOK && domain && !match ) {
+
+/* Change the comma at the end of each field to a null to terminate
+ the domain. Then convert the domain to upper case and eliminate
+ white space. */
+ if ( ( domain_end = strchr( domain, ',' ) ) ) *domain_end = '\0';
+ CleanDomain( domain, status );
+
+/* For any given domain, we will ignore imperfect matches in favour of
+ better ones by assigning a score to each match. Initialise the best
+ score value for the current domain. */
+ best_score = -1;
+
+/* Loop to consider both the "to" and "from" Frames in turn as the
+ basis of a possible common coordinate system. Quit looping early if
+ an error occurs or a perfect match is found. */
+ perfect = 0;
+ for ( icom = 0; astOK && !perfect && ( icom <= 1 ); icom++ ) {
+
+/* Make a copy of the Frame representing the initial guess at a common
+ coordinate system. We will use this to probe the other
+ Frame. Ensure that axes are not preserved (so that we convert to
+ the common axis number/order). */
+ common0 = astCopy( icom ? from : to );
+ astSetPreserveAxes( common0, 0 );
+
+/* Also, if the current domain is not blank, set the Domain attribute (so
+ we will only find coordinate systems which match the current
+ "domainlist" field). */
+ if ( *domain ) astSetDomain( common0, domain );
+
+/* Obtain a pointer to the other Frame. */
+ frame1 = astClone( icom ? to : from );
+
+/* Set the address at which to store the resulting Mapping pointer. */
+ map1_address = icom ? &to_map : &from_map;
+
+/* See if conversion from "frame1" to the common coordinate system is
+ possible. If successful, this results in a new approximation
+ ("common1") to the possible common coordinate system. */
+ match1 = astMatch( common0, frame1, 1, &axes1, &axes2,
+ map1_address, &ftmp );
+ common1 = (AstMapping *) ftmp;
+
+/* If successful, free memory allocated for the axis association
+ arrays, which are not needed. */
+ if ( astOK && match1 ) {
+ axes1 = astFree( axes1 );
+ axes2 = astFree( axes2 );
+
+/* Using the improved approximation to the common coordinate system,
+ now test if conversion from the alternative Frame "frame2" is
+ possible. */
+ frame2 = astClone( icom ? from : to );
+ map2_address = icom ? &from_map : &to_map;
+ astSetPreserveAxes( common1, 0 );
+ match2 = astMatch( common1, frame2, 1, &axes1, &axes2,
+ map2_address, &ftmp );
+ common2 = (AstMapping *) ftmp;
+
+/* If successful, free memory allocated for the axis association
+ arrays, which are not needed. */
+ if ( astOK && match2 ) {
+ axes1 = astFree( axes1 );
+ axes2 = astFree( axes2 );
+
+/* Invert the "to" Mapping and concatenate the two Mappings to
+ describe the conversion between the "from" and "to" Frames. Then
+ simplify the result. */
+ astInvert( to_map );
+ tmp = (AstMapping *) astCmpMap( from_map, to_map, 1, "", status );
+ map = astSimplify( tmp );
+ tmp = astAnnul( tmp );
+
+/* Assign a score that favours Mappings with both transformations
+ available over those with only one, and Mappings with only a
+ forward transformation over those with only an inverse
+ transformation. */
+ score = ( astGetTranForward( map ) ? 2 : 0 ) +
+ ( astGetTranInverse( map ) ? 1 : 0 );
+
+/* If the new score is better than the previous one (or is the first
+ one), note that we have a possible match. */
+ if ( astOK && ( score > best_score ) ) {
+ match = 1;
+
+/* Update the best score and note if it indicates a perfect match (in
+ which case we can stop searching at this point). */
+ best_score = score;
+ perfect = ( best_score >= 3 );
+
+/* Annul any previous result Mapping pointer and replace it with this
+ better one. */
+ if ( result_map ) result_map = astAnnul( result_map );
+ result_map = astClone( map );
+ }
+
+/* Annul pointers to all the intermediate Objects. */
+ map = astAnnul( map );
+ common2 = astAnnul( common2 );
+ *map2_address = astAnnul( *map2_address );
+ }
+ frame2 = astAnnul( frame2 );
+ common1 = astAnnul( common1 );
+ *map1_address = astAnnul( *map1_address );
+ }
+ frame1 = astAnnul( frame1 );
+ common0 = astAnnul( common0 );
+ }
+
+/* Go on to consider the next field in the domains list. */
+ domain = domain_end ? domain_end + 1 : NULL;
+ }
+ }
+
+/* Free the domain list copy. */
+ domainlist_copy = astFree( domainlist_copy );
+
+/* If returning a result, build the result FrameSet. Then annul the
+ result Mapping pointer. */
+ if ( result_map ) {
+ result = astFrameSet( from, "", status );
+ astAddFrame( result, AST__BASE, result_map, to );
+ result_map = astAnnul( result_map );
+ }
+
+/* If an error occurred, annul the result FrameSet pointer. */
+ if ( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+static int DefaultMaxAxes( AstFrame *this, int *status ) {
+/*
+* Name:
+* DefaultMaxAxes
+
+* Purpose:
+* Obtain the MaxAxes attribute from a Frame structure, with defaulting.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int DefaultMaxAxes( AstFrame *this, int *status )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function inspects the max_axes component of a Frame structure and
+* derives a value for the MaxAxes attribute. If the component's value
+* indicates that the attribute has not been set, a suitable default is
+* returned which is consistent with the state of the Frames's MinAxes
+* attribute.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The value to be used for the MaxAxes attribute.
+*/
+
+/* Local Variables. */
+ int result; /* Result to be returned */
+ int min_axes; /* Value of MinAxes attribute */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* If the Frame's max_axes component is set, return its value. */
+ if ( this->max_axes != -INT_MAX ) {
+ result = this->max_axes;
+
+/* Otherwise, the preferred default value is the number of Frame axes. */
+ } else {
+ result = astGetNaxes( this );
+
+/* Before returning this value, check if the MinAxes attribute is set. If it
+ is, obtain its value. */
+ if ( astTestMinAxes( this ) ) {
+ min_axes = astGetMinAxes( this );
+
+/* If necessary, increase the MaxAxes default value so that it is not less than
+ MinAxes. */
+ if ( result < min_axes ) result = min_axes;
+ }
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static int DefaultMinAxes( AstFrame *this, int *status ) {
+/*
+* Name:
+* DefaultMinAxes
+
+* Purpose:
+* Obtain the MinAxes attribute from a Frame structure, with defaulting.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int DefaultMinAxes( AstFrame *this, int *status )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function inspects the min_axes component of a Frame structure and
+* derives a value for the MinAxes attribute. If the component's value
+* indicates that the attribute has not been set, a suitable default is
+* returned which is consistent with the state of the Frames's MaxAxes
+* attribute.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The value to be used for the MinAxes attribute.
+*/
+
+/* Local Variables: */
+ int result; /* Result to be returned */
+ int max_axes; /* Value of MaxAxes attribute */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* If the Frame's min_axes component is set, return its value. */
+ if ( this->min_axes != -INT_MAX ) {
+ result = this->min_axes;
+
+/* Otherwise, the preferred default value is the number of Frame axes. */
+ } else {
+ result = astGetNaxes( this );
+
+/* Before returning this value, check if the MaxAxes attribute is set. If it
+ is, obtain its value. */
+ if ( astTestMaxAxes( this ) ) {
+ max_axes = astGetMaxAxes( this );
+
+/* If necessary, reduce the MinAxes default value so that it does not exceed
+ MaxAxes. */
+ if ( result > max_axes ) result = max_axes;
+ }
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static double Distance( AstFrame *this,
+ const double point1[], const double point2[], int *status ) {
+/*
+*++
+* Name:
+c astDistance
+f AST_DISTANCE
+
+* Purpose:
+* Calculate the distance between two points in a Frame.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c double astDistance( AstFrame *this,
+c const double point1[], const double point2[] )
+f RESULT = AST_DISTANCE( THIS, POINT1, POINT2, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function finds the distance between two points whose Frame
+* coordinates are given. The distance calculated is that along
+* the geodesic curve that joins the two points.
+*
+* For example, in a basic Frame, the distance calculated will be
+* the Cartesian distance along the straight line joining the two
+* points. For a more specialised Frame describing a sky coordinate
+* system, however, it would be the distance along the great circle
+* passing through two sky positions.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c point1
+f POINT1( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute) containing the coordinates of the first point.
+c point2
+f POINT2( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* containing the coordinates of the second point.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astDistance
+f AST_DISTANCE = DOUBLE PRECISION
+* The distance between the two points.
+
+* Notes:
+* - This function will return a "bad" result value (AST__BAD) if
+* any of the input coordinates has this value.
+* - A "bad" value will also be returned if this function is
+c invoked with the AST error status set, or if it should fail for
+f invoked with STATUS set to an error value, or if it should fail for
+* any reason.
+*--
+*/
+
+/* Local Variables: */
+ double delta; /* Separation along an axis */
+ double result; /* Result value to return */
+ int axis; /* Loop counter for axes */
+ int naxes; /* Number of Frame axes */
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain the number of Frame axes. */
+ naxes = astGetNaxes( this );
+ if ( astOK ) {
+
+/* Loop to determine the Cartesian distance between the points. */
+ result = 0.0;
+ for ( axis = 0; axis < naxes; axis++ ) {
+
+/* If any of the coordinates supplied is bad, set the distance to be
+ bad and quit looping. */
+ if ( ( point1[ axis ] == AST__BAD ) ||
+ ( point2[ axis ] == AST__BAD ) ) {
+ result = AST__BAD;
+ break;
+
+/* Otherwise, accumulate the sum of squared separations along each
+ axis. */
+ } else {
+ delta = point1[ axis ] - point2[ axis ];
+ result += ( delta * delta );
+ }
+ }
+
+/* Take the square root to find the distance (if valid). */
+ if ( result != AST__BAD ) result = sqrt( result );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int DoNotSimplify( AstMapping *this, int *status ) {
+/*
+* Name:
+* DoNotSimplify
+
+* Purpose:
+* Check if a Mapping is appropriate for simplification.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "object.h"
+* int DoNotSImplify( AstMapping *this );
+
+* Class Membership:
+* CmpMap member function (over-rides the astDoNotSimplify protected
+* method inherited from the parent class).
+
+* Description:
+* This function returns a flag indivating if the supplied Mapping is
+* appropriate for simplification.
+
+* Parameters:
+* this
+* Pointer to the Mapping.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Non-zero if the supplied Mapping is not appropriate for
+* simplification, and zero otherwise.
+
+* Notes:
+* - A value of 0 will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+
+*/
+
+/* Unlike basic Mappings, Frames that have a set value for the Ident
+ can be simplified. So always return zero. */
+ return 0;
+}
+
+static int Equal( AstObject *this_object, AstObject *that_object, int *status ) {
+/*
+* Name:
+* Equal
+
+* Purpose:
+* Test if two Frames are equivalent.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int Equal( AstObject *this, AstObject *that, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the astEqual protected
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns a boolean result (0 or 1) to indicate whether
+* two Frames are equivalent.
+
+* Parameters:
+* this
+* Pointer to the first Frame.
+* that
+* Pointer to the second Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* One if the Frames are equivalent, zero otherwise.
+
+* Notes:
+* - The two Frames are considered equivalent if the Mapping between
+* them is a UnitMap.
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *that; /* Pointer to the second Frame structure */
+ AstFrame *this; /* Pointer to the first Frame structure */
+ AstFrameSet *fs; /* FrameSet connecting the two Frames */
+ AstMapping *map1; /* Mapping connecting the two Frames */
+ AstMapping *map2; /* Simplified mapping connecting two Frames */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Checks that the second object is of the same class as the first . */
+ if( !strcmp( astGetClass( this_object ), astGetClass( that_object ) ) ){
+
+/* Obtain pointers to the two Frame structures. */
+ this = (AstFrame *) this_object;
+ that = (AstFrame *) that_object;
+
+/* Get the Mapping between them, and see if it is a UnitMap. */
+ fs = astConvert( that, this, "" );
+ if( fs ) {
+ map1 = astGetMapping( fs, AST__BASE, AST__CURRENT );
+ map2 = astSimplify( map1 );
+ result = astIsAUnitMap( map2 );
+ map1 = astAnnul( map1 );
+ map2 = astAnnul( map2 );
+ fs = astAnnul( fs );
+ }
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result, */
+ return result;
+}
+
+static int Fields( AstFrame *this, int axis, const char *fmt,
+ const char *str, int maxfld, char **fields,
+ int *nc, double *val, int *status ) {
+/*
+*+
+* Name:
+* astFields
+
+* Purpose:
+* Identify numerical fields within a formatted Axis value.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astFields( AstFrame *this, int axis, const char *fmt,
+* const char *str, int maxfld, char **fields,
+* int *nc, double *val )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function identifies the numerical fields within a Frame axis
+* value that has been formatted using astAxisFormat. It assumes that
+* the value was formatted using the supplied format string. It also
+* returns the equivalent floating point value.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the Frame axis for which the values have been
+* formatted (axis numbering starts at zero for the first axis).
+* fmt
+* Pointer to a constant null-terminated string containing the
+* format used when creating "str".
+* str
+* Pointer to a constant null-terminated string containing the
+* formatted value.
+* maxfld
+* The maximum number of fields to identify within "str".
+* fields
+* A pointer to an array of at least "maxfld" character pointers.
+* Each element is returned holding a pointer to the start of the
+* corresponding field in "str" (in the order in which they occur
+* within "str"), or NULL if no corresponding field can be found.
+* nc
+* A pointer to an array of at least "maxfld" integers. Each
+* element is returned holding the number of characters in the
+* corresponding field, or zero if no corresponding field can be
+* found.
+* val
+* Pointer to a location at which to store the value
+* equivalent to the returned field values. If this is NULL,
+* it is ignored.
+
+* Returned Value:
+* The number of fields succesfully identified and returned.
+
+* Notes:
+* - Leading and trailing spaces are ignored.
+* - If the formatted value is not consistent with the supplied format
+* string, then a value of zero will be returned, "fields" will be
+* returned holding NULLs, "nc" will be returned holding zeros, and
+* "val" is returned holding VAL__BAD.
+* - Fields are counted from the start of the formatted string. If the
+* string contains more than "maxfld" fields, then trailing fields are
+* ignored.
+* - If this function is invoked with the global error status set, or
+* if it should fail for any reason, then a value of zero will be returned
+* as the function value, and "fields", "nc" and "val" will be returned
+* holding their supplied values
+*-
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ int result; /* Result field count to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate the axis index and obtain a pointer to the required
+ Axis. */
+ (void) astValidateAxis( this, axis, 1, "astFields" );
+ ax = astGetAxis( this, axis );
+
+/* Invoke the Axis astAxisFields method to perform the processing. */
+ result = astAxisFields( ax, fmt, str, maxfld, fields, nc, val );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static AstFrameSet *FindFrame( AstFrame *target, AstFrame *template,
+ const char *domainlist, int *status ) {
+/*
+*++
+* Name:
+c astFindFrame
+f AST_FINDFRAME
+
+* Purpose:
+* Find a coordinate system with specified characteristics.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c AstFrameSet *astFindFrame( AstFrame *target, AstFrame *template,
+c const char *domainlist )
+f RESULT = AST_FINDFRAME( TARGET, TEMPLATE, DOMAINLIST, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function uses a "template" Frame to search another Frame
+* (or FrameSet) to identify a coordinate system which has a
+* specified set of characteristics. If a suitable coordinate
+* system can be found, the function returns a pointer to a
+* FrameSet which describes the required coordinate system and how
+* to convert coordinates to and from it.
+*
+* This function is provided to help answer general questions about
+* coordinate systems, such as typically arise when coordinate
+* information is imported into a program as part of an initially
+* unknown dataset. For example:
+* - Is there a wavelength scale?
+* - Is there a 2-dimensional coordinate system?
+* - Is there a celestial coordinate system?
+* - Can I plot the data in ecliptic coordinates?
+*
+* You can also use this function as a means of reconciling a
+* user's preference for a particular coordinate system (for
+* example, what type of axes to draw) with what is actually
+* possible given the coordinate information available.
+*
+* To perform a search, you supply a "target" Frame (or FrameSet)
+* which represents the set of coordinate systems to be searched.
+* If a basic Frame is given as the target, this set of coordinate
+* systems consists of the one described by this Frame, plus all
+* other "virtual" coordinate systems which can potentially be
+* reached from it by applying built-in conversions (for example,
+* any of the celestial coordinate conversions known to the AST
+* library would constitute a "built-in" conversion). If a FrameSet
+* is given as the target, the set of coordinate systems to be
+* searched consists of the union of those represented by all the
+* individual Frames within it.
+*
+* To select from this large set of possible coordinate systems,
+* you supply a "template" Frame which is an instance of the type
+* of Frame you are looking for. Effectively, you then ask the
+* function to "find a coordinate system that looks like this".
+*
+* You can make your request more or less specific by setting
+* attribute values for the template Frame. If a particular
+* attribute is set in the template, then the function will only
+* find coordinate systems which have exactly the same value for
+* that attribute. If you leave a template attribute un-set,
+* however, then the function has discretion about the value the
+* attribute should have in any coordinate system it finds. The
+* attribute will then take its value from one of the actual
+* (rather than virtual) coordinate systems in the target. If the
+* target is a FrameSet, its Current attribute will be modified to
+* indicate which of its Frames was used for this purpose.
+*
+* The result of this process is a coordinate system represented by
+* a hybrid Frame which acquires some attributes from the template
+* (but only if they were set) and the remainder from the
+* target. This represents the "best compromise" between what you
+* asked for and what was available. A Mapping is then generated
+* which converts from the target coordinate system to this hybrid
+* one, and the returned FrameSet encapsulates all of this
+* information.
+
+* Parameters:
+c target
+f TARGET = INTEGER (Given)
+* Pointer to the target Frame (or FrameSet).
+*
+* Note that if a FrameSet is supplied (and a suitable
+* coordinate system is found), then its Current attribute will
+* be modified to indicate which Frame was used to obtain
+* attribute values which were not specified by the template.
+* This Frame will, in some sense, represent the "closest"
+* non-virtual coordinate system to the one you requested.
+c template
+f TEMPLATE = INTEGER (Given)
+* Pointer to the template Frame, which should be an instance of
+* the type of Frame you wish to find. If you wanted to find a
+* Frame describing a celestial coordinate system, for example,
+* then you might use a SkyFrame here. See the "Examples"
+* section for more ideas.
+c domainlist
+f DOMAINLIST = CHARACTER * ( * ) (Given)
+c Pointer to a null-terminated character string containing a
+f A character string containing a
+* comma-separated list of Frame domains. This may be used to
+* establish a priority order for the different types of
+* coordinate system that might be found.
+*
+* The function will first try to find a suitable coordinate
+* system whose Domain attribute equals the first domain in this
+* list. If this fails, the second domain in the list will be
+* used, and so on, until a result is obtained. A blank domain
+* (e.g. two consecutive commas) indicates that any coordinate
+* system is acceptable (subject to the template) regardless of
+* its domain.
+*
+* This list is case-insensitive and all white space is ignored.
+* If you do not wish to restrict the domain in this way,
+c you should supply an empty string.
+f you should supply a blank string.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astFindFrame()
+f AST_FINDFRAME = INTEGER
+* If the search is successful, the function returns a pointer
+* to a FrameSet which contains the Frame found and a
+* description of how to convert to (and from) the coordinate
+* system it represents. Otherwise, a null Object pointer
+* (AST__NULL) is returned without error.
+*
+* If a FrameSet is returned, it will contain two Frames. Frame
+* number 1 (its base Frame) represents the target coordinate
+* system and will be the same as the (base Frame of the)
+* target. Frame number 2 (its current Frame) will be a Frame
+* representing the coordinate system which the function
+* found. The Mapping which inter-relates these two Frames will
+* describe how to convert between their respective coordinate
+* systems.
+*
+* Note that a FrameSet may be used both as a Mapping and as a
+* Frame. If the result is used as a Mapping (e.g. with
+* astTran2), then it provides a means of converting coordinates
+* from the target coordinate system into the new coordinate
+* system that was found (and vice versa if its inverse
+* transformation is selected). If it is used as a Frame, its
+* attributes will describe the new coordinate system.
+
+* Applicability:
+* Frame
+* This function applies to all Frames.
+* FrameSet
+* If the target is a FrameSet, the possibility exists that
+* several of the Frames within it might be matched by the
+* template. Unless the choice is sufficiently restricted by
+c the "domainlist" string, the sequence in which Frames are
+f the DOMAINLIST string, the sequence in which Frames are
+* searched can then become important. In this case, the search
+* proceeds as follows:
+c - Each field in the "domainlist" string is considered in turn.
+f - Each field in the DOMAINLIST string is considered in turn.
+* - An attempt is made to match the template to each of the
+* target's Frames in the order: (1) the current Frame, (2) the
+* base Frame, (3) each remaining Frame in the order of being
+* added to the target FrameSet.
+* - Generally, the first match found is used. However, the
+* Mapping between the target coordinate system and the
+* resulting Frame is also examined. Preference is given to
+* cases where both the forward and inverse transformations are
+* defined (as indicated by the TranForward and TranInverse
+* attributes). If only one transformation is defined, the
+* forward one is preferred.
+* - If a match is found and the domain of the resulting Frame also
+c matches the current "domainlist" field, it is
+f matches the current DOMAINLIST field, it is
+c accepted. Otherwise, the next "domainlist" field is considered
+f accepted. Otherwise, the next DOMAINLIST field is considered
+* and the process repeated.
+*
+* If a suitable coordinate system is found, the Current
+* attribute of the target FrameSet will be modified on exit to
+* identify the Frame whose match with the target was eventually
+* accepted.
+
+* Examples:
+c result = astFindFrame( target, astFrame( 3, "" ), "" );
+f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 3, ' ', STATUS ), ' ', STATUS )
+* Searches for a 3-dimensional coordinate system in the target
+* Frame (or FrameSet). No attributes have been set in the
+c template Frame (created by astFrame), so no restriction has
+f template Frame (created by AST_FRAME), so no restriction has
+* been placed on the required coordinate system, other than
+* that it should have 3 dimensions. The first suitable Frame
+c found will be returned as part of the "result" FrameSet.
+f found will be returned as part of the RESULT FrameSet.
+c result = astFindFrame( target, astSkyFrame( "" ), "" );
+f RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( ' ', STATUS ), ' ', STATUS )
+* Searches for a celestial coordinate system in the target
+* Frame (or FrameSet). The type of celestial coordinate system
+c is unspecified, so astFindFrame will return the first one
+f is unspecified, so AST_FINDFRAME will return the first one
+c found as part of the "result" FrameSet. If the target is
+f found as part of the RESULT FrameSet. If the target is
+* a FrameSet, then its Current attribute will be updated to
+* identify the Frame that was used.
+*
+* If no celestial coordinate system can be found, a value of
+* AST__NULL will be returned without error.
+c result = astFindFrame( target, astSkyFrame( "MaxAxes=100" ), "" );
+f RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'MaxAxes=100', STATUS ), ' ', STATUS )
+* This is like the last example, except that in the event of the
+* target being a CmpFrame, the component Frames encapsulated by the
+* CmpFrame will be searched for a SkyFrame. If found, the returned
+* Mapping will included a PermMap which selects the required axes
+* from the target CmpFrame.
+*
+* This is acomplished by setting the MaxAxes attribute of the
+* template SkyFrame to a large number (larger than or equal to the
+* number of axes in the target CmpFrame). This allows the SkyFrame
+* to be used as a match for Frames containing from 2 to 100 axes.
+c result = astFindFrame( target, astSkyFrame( "System=FK5" ), "" );
+f RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'System=FK5', STATUS ), ' ', STATUS )
+* Searches for an equatorial (FK5) coordinate system in the
+* target. The Equinox value for the coordinate system has not
+* been specified, so will be obtained from the target. If the
+* target is a FrameSet, its Current attribute will be updated
+* to indicate which SkyFrame was used to obtain this value.
+c result = astFindFrame( target, astFrame( 2, "" ), "sky,pixel," );
+f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 2, ' ', STATUS ), 'SKY,PIXEL,', STATUS )
+* Searches for a 2-dimensional coordinate system in the
+* target. Initially, a search is made for a suitable coordinate
+* system whose Domain attribute has the value "SKY". If this
+* search fails, a search is then made for one with the domain
+* "PIXEL". If this also fails, then any 2-dimensional
+c coordinate system is returned as part of the "result"
+f coordinate system is returned as part of the RESULT
+* FrameSet.
+*
+* Only if no 2-dimensional coordinate systems can be reached by
+* applying built-in conversions to any of the Frames in the
+* target will a value of AST__NULL be returned.
+c result = astFindFrame( target, astFrame( 1, "Domain=WAVELENGTH" ), "" );
+f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, 'Domain=WAVELENGTH', STATUS ), ' ', STATUS )
+* Searches for any 1-dimensional coordinate system in the
+* target which has the domain "WAVELENGTH".
+c result = astFindFrame( target, astFrame( 1, "" ), "wavelength" );
+f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, ' ', STATUS ), 'WAVELENGTH', STATUS )
+* This example has exactly the same effect as that above. It
+* illustrates the equivalence of the template's Domain attribute
+c and the fields in the "domainlist" string.
+f and the fields in the DOMAINLIST string.
+c result = astFindFrame( target, astFrame( 1, "MaxAxes=3" ), "" );
+f RESULT = AST_FINDFRAME( TARGET, AST_FRAME( 1, 'MaxAxes=3', STATUS ), ' ', STATUS )
+* This is a more advanced example which will search for any
+* coordinate system in the target having 1, 2 or 3
+c dimensions. The Frame returned (as part of the "result"
+f dimensions. The Frame returned (as part of the RESULT
+* FrameSet) will always be 1-dimensional, but will be related
+* to the coordinate system that was found by a suitable Mapping
+* (e.g. a PermMap) which simply extracts the first axis.
+*
+* If we had wanted a Frame representing the actual (1, 2 or
+* 3-dimensional) coordinate system found, we could set the
+* PreserveAxes attribute to a non-zero value in the template.
+c result = astFindFrame( target, astSkyFrame( "Permute=0" ), "" );
+f RESULT = AST_FINDFRAME( TARGET, AST_SKYFRAME( 'Permute=0', STATUS ), ' ', STATUS )
+* Searches for any celestial coordinate system in the target,
+* but only finds one if its axes are in the conventional
+* (longitude,latitude) order and have not been permuted
+c (e.g. with astPermAxes).
+f (e.g. with AST_PERMAXES).
+
+* Notes:
+* - The Mapping represented by the returned FrameSet results in
+* alignment taking place in the coordinate system specified by the
+c AlignSystem attribute of the "template" Frame. See the description
+f AlignSystem attribute of the TEMPLATE Frame. See the description
+* of the AlignSystem attribute for further details.
+* - Beware of setting the Domain attribute of the template and then
+c using a "domainlist" string which does not include the template's domain
+f using a DOMAINLIST string which does not include the template's domain
+* (or a blank field). If you do so, no coordinate system will be
+* found.
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+
+* More on Using Templates:
+* A Frame (describing a coordinate system) will be found by this
+* function if (a) it is "matched" by the template you supply, and
+c (b) the value of its Domain attribute appears in the "domainlist"
+f (b) the value of its Domain attribute appears in the DOMAINLIST
+* string (except that a blank field in this string permits any
+* domain). A successful match by the template depends on a number
+* of criteria, as outlined below:
+* - In general, a template will only match another Frame which
+* belongs to the same class as the template, or to a derived (more
+* specialised) class. For example, a SkyFrame template will match
+* any other SkyFrame, but will not match a basic
+* Frame. Conversely, a basic Frame template will match any class
+* of Frame.
+* - The exception to this is that a Frame of any class can be used to
+* match a CmpFrame, if that CmpFrame contains a Frame of the same
+* class as the template. Note however, the MaxAxes and MinAxes
+* attributes of the template must be set to suitable values to allow
+* it to match the CmpFrame. That is, the MinAxes attribute must be
+* less than or equal to the number of axes in the target, and the MaxAxes
+* attribute must be greater than or equal to the number of axes in
+* the target.
+* - If using a CmpFrame as a template frame, the MinAxes and MaxAxes
+* for the template are determined by the MinAxes and MaxAxes values of
+* the component Frames within the template. So if you want a template
+* CmpFrame to be able to match Frames with different numbers of axes,
+* then you must set the MaxAxes and/or MinAxes attributes in the component
+* template Frames, before combining them together into the template
+* CmpFrame.
+* - If a template has a value set for any of its main attributes, then
+* it will only match Frames which have an identical value for that
+* attribute (or which can be transformed, using a built-in
+* conversion, so that they have the required value for that
+* attribute). If any attribute in the template is un-set, however,
+* then Frames are matched regardless of the value they may have
+* for that attribute. You may therefore make a template more or
+* less specific by choosing the attributes for which you set
+* values. This requirement does not apply to 'descriptive' attributes
+* such as titles, labels, symbols, etc.
+* - An important application of this principle involves the Domain
+* attribute. Setting the Domain attribute of the template has the
+* effect of restricting the search to a particular type of Frame
+* (with the domain you specify). Conversely, if the Domain
+* attribute is not set in the template, then the domain of the
+* Frame found is not relevant, so all Frames are searched. Note
+* that the
+c "domainlist" string provides an alternative way of restricting the
+f DOMAINLIST string provides an alternative way of restricting the
+* search in the same manner, but is a more convenient interface if
+* you wish to search automatically for another domain if the first
+* search fails.
+* - Normally, a template will only match a Frame which has the
+* same number of axes as itself. However, for some classes of
+* template, this default behaviour may be changed by means of the
+* MinAxes, MaxAxes and MatchEnd attributes. In addition, the
+* behaviour of a template may be influenced by its Permute and
+* PreserveAxes attributes, which control whether it matches Frames
+* whose axes have been permuted, and whether this permutation is
+* retained in the Frame which is returned (as opposed to returning
+* the axes in the order specified in the template, which is the
+* default behaviour). You should consult the descriptions of these
+* attributes for details of this more advanced use of templates.
+*--
+*/
+
+/* Local Variables: */
+ AstFrame *frame; /* Pointer to result Frame */
+ AstFrameSet *result; /* Pointer to result FrameSet */
+ AstMapping *map; /* Pointer to result Mapping */
+ AstMapping *tmp; /* Temporary Mapping pointer */
+ char *domain_copy; /* Pointer to copy of result domain */
+ char *domainlist_copy; /* Pointer to copy of domains list */
+ const char *domain; /* Pointer to result Domain value */
+ int *target_axes; /* Pointer to target axis assignments */
+ int *template_axes; /* Pointer to template axis assignments */
+ int i; /* Loop counter for characters */
+ int j; /* Character index */
+ int match; /* Template matched target? */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Allocate space to store a copy of the domains list, with added
+ commas. */
+ domainlist_copy = astMalloc( strlen( domainlist ) + (size_t) 3 );
+ if ( astOK ) {
+
+/* Make a copy of the domains list, with an extra comma added at each
+ end. Also remove all white space and convert to upper case. */
+ domainlist_copy[ 0 ] = ',';
+ for ( i = 0, j = 1; domainlist[ i ]; i++ ) {
+ if ( !isspace( domainlist[ i ] ) ) {
+ domainlist_copy[ j++ ] = toupper( domainlist[ i ] );
+ }
+ }
+ domainlist_copy[ j++ ] = ',';
+ domainlist_copy[ j ] = '\0';
+
+/* Invoke the protected astMatch method associated with the template
+ Frame. This matches the template to the target and returns
+ information about how to convert between the target and the Frame
+ it found (if any). */
+ match = astMatch( template, target, 0,
+ &template_axes, &target_axes, &map, &frame );
+
+/* If successful, obtain a pointer to the Domain string of the result
+ Frame. Allocate space for a copy of this string, with added
+ commas. */
+ if ( match && astOK ) {
+ domain = astGetDomain( frame );
+ if ( astOK ) {
+ domain_copy = astMalloc( strlen( domain ) + (size_t) 3 );
+ if ( astOK ) {
+
+/* Make a copy of the domain, adding an extra comma at each end. */
+ domain_copy[ 0 ] = ',';
+ for ( i = 0, j = 1; domain[ i ]; i++ ) {
+ domain_copy[ j++ ] = domain[ i ];
+ }
+ domain_copy[ j++ ] = ',';
+ domain_copy[ j ] = '\0';
+
+/* Test if the domain appears in the domains list (with added
+ commas). If not, test if a blank domain (which permits the result
+ Frame to have any Domain) appears instead. */
+ if ( strstr( domainlist_copy, domain_copy ) ||
+ strstr( domainlist_copy, ",," ) ) {
+
+/* If the result Frame is acceptable, simplify the result Mapping. */
+ tmp = astSimplify( map );
+ map = astAnnul( map );
+ map = tmp;
+
+/* Build the result FrameSet. */
+ result = astFrameSet( target, "", status );
+ astAddFrame( result, AST__BASE, map, frame );
+ }
+ }
+
+/* Free the copy of the result domain. */
+ domain_copy = astFree( domain_copy );
+ }
+
+/* Free space and annul pointers allocated by astMatch. */
+ template_axes = astFree( template_axes );
+ target_axes = astFree( target_axes );
+ map = astAnnul( map );
+ frame = astAnnul( frame );
+ }
+ }
+
+/* Free the copy of the domains list. */
+ domainlist_copy = astFree( domainlist_copy );
+
+/* If an error occurred, annul any result pointer. */
+ if ( !astOK && result ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+}
+
+const char *astFmtDecimalYr_( double year, int digits, int *status ) {
+/*
+*+
+* Name:
+* astFmtDecimalYr
+
+* Purpose:
+* Format an epoch expressed in years as a decimal string.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frame.h"
+* const char *astFmtDecimalYr( double year, int digits )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function formats an epoch expressed in years as a decimal string
+* and returns a pointer to the result. It is intended for formatting
+* Frame Epoch values, etc, for display.
+
+* Parameters:
+* year
+* The epoch to be formatted.
+* digits
+* The number of digits of precision required.
+
+* Returned Value:
+* Pointer to a null terminated string containing the formatted value.
+
+* Notes:
+* - The result string is stored in static memory and may be
+* over-written by a subsequent invocation of this function.
+* - A NULL pointer is returned if this function is invoked with
+* the global error status set or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ int nc; /* Number of characters in buffer */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(NULL);
+
+/* Limit the precision to what is meaningful. */
+ digits = ( digits > AST__DBL_DIG ) ? AST__DBL_DIG : digits;
+
+/* Format the year value. Use "g" format to avoid buffer overflow and
+ to get useful diagnostic output if a silly value is given. */
+ nc = sprintf( astfmtdecimalyr_buff, "%#.*g", digits, year );
+
+/* Loop to remove redundant zeros from the end of the result. */
+ while ( astfmtdecimalyr_buff[ --nc ] == '0' ) astfmtdecimalyr_buff[ nc ] = '\0';
+
+/* If the last character is now a decimal point, put back one zero. */
+ if ( astfmtdecimalyr_buff[ nc ] == '.' ) {
+ astfmtdecimalyr_buff[ ++nc ] = '0';
+ astfmtdecimalyr_buff[ ++nc ] = '\0';
+ }
+
+/* Return the result. */
+ return astfmtdecimalyr_buff;
+}
+
+static const char *Format( AstFrame *this, int axis, double value, int *status ) {
+/*
+*+
+* Name:
+* astFormat
+
+* Purpose:
+* Format a coordinate value for a Frame axis.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* const char *astFormat( AstFrame *this, int axis, double value )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns a pointer to a string containing the
+* formatted (character) version of a coordinate value for a Frame
+* axis. The formatting applied is determined by the Frame's
+* attributes and, in particular, by any Format attribute string
+* that has been set for the axis. A suitable default format will
+* be applied if necessary.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the Frame axis for which formatting is to be
+* performed (axis numbering starts at zero for the first axis).
+* value
+* The coordinate value to be formatted.
+
+* Returned Value:
+* A pointer to a null-terminated string containing the formatted
+* value.
+
+* Notes:
+* - The returned string pointer may point at memory allocated
+* within the Frame, or at static memory. The contents of the
+* string may be over-written or the pointer may become invalid
+* following a further invocation of the same function or any
+* modification of the Frame. A copy of the string should
+* therefore be made if necessary.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+
+* Implementation Notes:
+* - This function implements the basic astFormat method available
+* via the protected interface to the Frame class. The public
+* interface to this method is provided by the astFormatId_
+* function.
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ const char *result; /* Pointer value to return */
+ int digits_set; /* Axis Digits attribute set? */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Validate the axis index and obtain a pointer to the required Axis. */
+ (void) astValidateAxis( this, axis, 1, "astFormat" );
+ ax = astGetAxis( this, axis );
+
+/* Test if any Axis attributes which may affect the result are undefined (i.e.
+ have not been explicitly set). If so, we over-ride them, giving them
+ temporary values dictated by the Frame. Only the Digits attribute is
+ relevant here. */
+ digits_set = astTestAxisDigits( ax );
+ if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) );
+
+/* Format the value. */
+ result = astAxisFormat( ax, value );
+
+/* Clear any Axis attributes that were temporarily over-ridden. */
+ if ( !digits_set ) astClearAxisDigits( ax );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+static AstPointSet *FrameGrid( AstFrame *this, int size, const double *lbnd,
+ const double *ubnd, int *status ){
+/*
+*+
+* Name:
+* astFrameGrid
+
+* Purpose:
+* Return a grid of points covering a rectangular area of a Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* AstPointSet *astFrameGrid( AstFrame *this_frame, int size,
+* const double *lbnd, const double *ubnd )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns a PointSet containing positions spread
+* approximately evenly throughtout a specified rectangular area of
+* the Frame.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* size
+* The preferred number of points in the returned PointSet. The
+* actual number of points in the returned PointSet may be
+* different, but an attempt is made to stick reasonably closely to
+* the supplied value.
+* lbnd
+* Pointer to an array holding the lower bound of the rectangular
+* area on each Frame axis. The array should have one element for
+* each Frame axis.
+* ubnd
+* Pointer to an array holding the upper bound of the rectangular
+* area on each Frame axis. The array should have one element for
+* each Frame axis.
+
+* Returned Value:
+* A pointer to a new PointSet holding the grid of points.
+
+* Notes:
+* - A NULL pointer is returned if an error occurs.
+*-
+*/
+
+/* Local Variables: */
+ AstPointSet *result;
+ const char *unit;
+ double **ptr;
+ double *gmean;
+ double *step;
+ int *maxi;
+ int *nsame;
+ int *ntick;
+ int *pi;
+ int bad;
+ int iax;
+ int ipp;
+ int jax;
+ int naxes;
+ int np;
+ int ntick0;
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get the number of axes in the Frame. */
+ naxes = astGetNaxes( this );
+
+/* Allocate an array to hold the number of ticks along each axis. */
+ ntick = astMalloc( sizeof(int)*naxes );
+
+/* Allocate an array to hold the geometric mean of the lengths of the
+ axes that have the same units as the current axis. */
+ gmean = astMalloc( naxes*sizeof(double) );
+
+/* Allocate an array to hold the number of axes that share the same unit. */
+ nsame = astMalloc( naxes*sizeof(int) );
+ if( astOK ) {
+
+/* For each axis, find the total number of axes in the Frame that have
+ the same unit string. Also, find the product of the lengths of these
+ axes. */
+ bad = 0;
+ for( iax = 0; iax < naxes; iax++ ) {
+ nsame[ iax ] = 1;
+
+ if( ubnd[ iax ] == AST__BAD &&
+ lbnd[ iax ] == AST__BAD ) {
+ bad = 1;
+ break;
+ }
+
+ gmean[ iax ] = ubnd[ iax ] - lbnd[ iax ];
+ unit = astGetUnit( this, iax );
+ for( jax = 0; jax < naxes; jax++ ) {
+ if( jax != iax ) {
+ if( astOK && !strcmp( unit, astGetUnit( this, jax ) ) ) {
+ nsame[ iax ]++;
+ gmean[ iax ] *= ubnd[ jax ] - lbnd[ jax ];
+ }
+ }
+ }
+ }
+
+/* Do nothing if any bad bounds were supplied, or if the size is less
+ than 1. */
+ if( !bad && size >= 1 ) {
+
+/* Get the nominal number of ticks per axis. */
+ ntick0 = pow( size, 1.0/(double)naxes );
+ if( ntick0 < 2 ) ntick0 = 2;
+
+/* Convert the dimension products into geometric means. */
+ for( iax = 0; iax < naxes; iax++ ) {
+ gmean[ iax ] = pow( fabs(gmean[ iax ]), 1.0/(double)nsame[ iax ] );
+ }
+
+/* The number of ticks to use on each axis is equal to the nominal number
+ multiplied by the ratio of the axis length to the geometric mean of the
+ axis lengths that sahare the same unit string. This gives more ticks
+ on the longer axes within any group of common-unit axes, whilst
+ retaining the overall number of ticks (roughly). Also find the total
+ number of points. */
+ np = 1;
+ for( iax = 0; iax < naxes; iax++ ) {
+ ntick[ iax ] = ntick0*( ubnd[ iax ] - lbnd[ iax ] )/gmean[ iax ];
+ if( ntick[ iax ] < 2 ) ntick[ iax ] = 2;
+ np *= ntick[ iax ];
+ }
+
+/* Create a PointSet large enough to hold this many points. */
+ result = astPointSet( np, naxes, " ", status );
+ ptr = astGetPoints( result );
+
+/* Allocate memory to hold the max indices on each axis. */
+ maxi = astMalloc( sizeof( int )*(size_t) naxes );
+
+/* Allocate memory to hold the indices of the current position.*/
+ pi = astMalloc( sizeof( int )*(size_t) naxes );
+
+/* Allocate memory to hold the step size for each axis. */
+ step = astMalloc( sizeof( double )*(size_t) naxes );
+ if( astOK ) {
+
+/* For every axis, set up the step size, initialise the current position to
+ the lower bound, and store a modified upper limit which includes some
+ safety marging to allow for rounding errors. */
+ for( iax = 0; iax < naxes; iax++ ) {
+ step[ iax ] = ( ubnd[ iax ] - lbnd[ iax ] )/( ntick[ iax ] - 1 );
+ pi[ iax ] = 0;
+ maxi[ iax ] = ntick[ iax ] - 1;
+ }
+
+/* Initialise the index of the next position to store. */
+ ipp = 0;
+
+/* Loop round adding points to the array until the whole volume has been
+ done. */
+ iax = 0;
+ while( iax < naxes ) {
+
+/* Add the current point to the supplied array, and increment the index of
+ the next point to add. */
+ for( iax = 0; iax < naxes; iax++ ) {
+ ptr[ iax ][ ipp ] = lbnd[ iax ] + pi[ iax ]*step[ iax ];
+ }
+ ipp++;
+
+/* We now move the current position on to the next sample */
+ iax = 0;
+ while( iax < naxes ) {
+ pi[ iax ]++;
+ if( pi[ iax ] > maxi[ iax ] ) {
+ pi[ iax ] = 0;
+ iax++;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+/* Free resources. */
+ maxi = astFree( maxi );
+ pi = astFree( pi );
+ step = astFree( step );
+
+/* Report error if supplied values were bad. */
+ } else if( astOK ) {
+ if( bad ) {
+ astError( AST__ATTIN, "astFrameGrid(%s): One of more of the "
+ "supplied bounds is AST__BAD (programming error).",
+ status, astGetClass( this ) );
+ } else if( size < 1 ) {
+ astError( AST__ATTIN, "astFrameGrid(%s): The supplied grid "
+ "size (%d) is invalid (programming error).",
+ status, astGetClass( this ), size );
+ }
+ }
+ }
+
+/* Free resources. */
+ ntick = astFree( ntick );
+ nsame = astFree( nsame );
+ gmean = astFree( gmean );
+
+/* Annul the returned PointSet if an error has occurred. */
+ if( !astOK ) result = astAnnul( result );
+
+/* Return the PointSet holding the grid. */
+ return result;
+}
+
+static double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status ) {
+/*
+*+
+* Name:
+* astGap
+
+* Purpose:
+* Find a "nice" gap for tabulating Frame axis values.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* double astGap( AstFrame *this, int axis, double gap, int *ntick )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns a gap size which produces a nicely spaced
+* series of formatted values for a Frame axis, the returned gap
+* size being as close as possible to the supplied target gap
+* size. It also returns a convenient number of divisions into
+* which the gap can be divided.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the axis (zero-based) for which a gap is to be found.
+* gap
+* The target gap size.
+* ntick
+* Address of an int in which to return a convenient number of
+* divisions into which the gap can be divided.
+
+* Returned Value:
+* The nice gap size.
+
+* Notes:
+* - A value of zero is returned if the target gap size is zero.
+* - A negative gap size is returned if the supplied gap size is negative.
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ double result; /* The nice gap value */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0.0;
+
+/* Validate the axis index and obtain a pointer to the required
+ Axis. */
+ (void) astValidateAxis( this, axis, 1, "astGap" );
+ ax = astGetAxis( this, axis );
+
+/* Find the gap. */
+ result = astAxisGap( ax, gap, ntick );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0.0;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetActiveUnit( AstFrame *this, int *status ){
+/*
+*++
+* Name:
+c astGetActiveUnit
+f AST_GETACTIVEUNIT
+
+* Purpose:
+* Determines how the Unit attribute will be used.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c int astGetActiveUnit( AstFrame *this )
+f RESULT = AST_GETACTIVEUNIT( THIS, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function
+f This routine
+* returns the current value of the ActiveUnit flag for a Frame. See
+c the description of the astSetActiveUnit function
+f the description of the AST_SETACTIVEUNIT routine
+* for a description of the ActiveUnit flag.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astGetActiveUnit
+f AST_GETACTIVEUNIT = LOGICAL
+* The current value of the ActiveUnit flag.
+
+* Notes:
+c - A zero value will be returned if this function is
+c invoked with the AST error status set, or if it should fail for
+f - A value of .FALSE. will be returned if this function is
+f invoked with STATUS set to an error value, or if it should fail for
+* any reason.
+*--
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to axis structure */
+ int i; /* Index of axis in Frame */
+ int has_skyaxis; /* Does Frame contain any SkyAxes? */
+ int nax; /* Number of axes in Frame */
+ int result; /* The returned value */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* See if the Frame contains a SkyAxis. */
+ has_skyaxis = 0;
+ nax = astGetNaxes( this );
+ for( i = 0; i < nax; i++ ) {
+ ax = astGetAxis( this, i );
+ if( astIsASkyAxis( ax ) ) has_skyaxis = 1;
+ ax = astAnnul( ax );
+ }
+
+/* If the Frame contains a SkyAxis the ActiveUnit flag is always zero. */
+ if( !has_skyaxis ) {
+
+/* Otherwise, get the value from the Frame. If it has not yet been assigned a
+ value return the value zero. */
+ result = this->active_unit;
+ if( result == -INT_MAX ) result = 0;
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* GetAttrib
+
+* Purpose:
+* Get the value of a specified attribute for a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* const char *GetAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the protected astGetAttrib
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns a pointer to the value of a specified
+* attribute for a Frame, formatted as a character string.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* attrib
+* Pointer to a null-terminated string containing the name of
+* the attribute whose value is required. This name should be in
+* lower case, with all white space removed.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* - Pointer to a null-terminated string containing the attribute
+* value.
+
+* Notes:
+* - This function uses one-based axis numbering so that it is
+* suitable for external (public) use.
+* - The returned string pointer may point at memory allocated
+* within the Frame, or at static memory. The contents of the
+* string may be over-written or the pointer may become invalid
+* following a further invocation of the same function or any
+* modification of the Frame. A copy of the string should
+* therefore be made if necessary.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstAxis *ax; /* Pointer to Axis */
+ AstFrame *pfrm; /* Pointer to primary Frame containing axis */
+ AstFrame *this; /* Pointer to the Frame structure */
+ AstSystemType system; /* System code */
+ char pfrm_attrib[ 100 ]; /* Primary Frame attribute */
+ char *axis_attrib; /* Pointer to axis attribute name */
+ const char *old_attrib; /* Pointer to supplied attribute name string */
+ const char *result; /* Pointer value to return */
+ double dval; /* Double attibute value */
+ double epoch; /* Epoch attribute value (as MJD) */
+ int axis; /* Frame axis number */
+ int axis_nc; /* No. characters in axis attribute name */
+ int digits; /* Digits attribute value */
+ int direction; /* Direction attribute value */
+ int free_axis_attrib; /* Should axis_attrib be freed? */
+ int has_axis; /* Does attrib name include axis specifier? */
+ int len; /* Length of attrib string */
+ int match_end; /* MatchEnd attribute value */
+ int max_axes; /* MaxAxes attribute value */
+ int min_axes; /* MinAxes attribute value */
+ int naxes; /* Naxes attribute value */
+ int nc; /* No. characters read by astSscanf */
+ int oldrep; /* Original error reporting state */
+ int paxis; /* Axis index within primary frame */
+ int permute; /* Permute attribute value */
+ int preserve_axes; /* PreserveAxes attribute value */
+ int used; /* Could the setting string be used? */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_object);
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_object;
+
+/* Set a flag indicating if the attribute name includes an axis
+ specifier. */
+ has_axis = ( strchr( attrib, '(' ) != NULL );
+
+/* A flag indicating that we do not need to free the axis_attrib memory. */
+ free_axis_attrib = 0;
+
+/* Initialise things to avoid compiler warnings. */
+ axis_attrib = NULL;
+ old_attrib = NULL;
+
+/* Jump back to here if we are trying the same attribute but with an explicit
+ axis "(1)" added to the end of the name. */
+L1:
+
+/* Obtain the length of the attrib string. */
+ len = strlen( attrib );
+
+/* Save the number of axes in the Frame for later use. */
+ naxes = astGetNaxes( this );
+
+/* Compare "attrib" with each recognised attribute name in turn,
+ obtaining the value of the required attribute. If necessary, write
+ the value into "getattrib_buff" as a null-terminated string in an appropriate
+ format. Set "result" to point at the result string. */
+
+/* Digits. */
+/* ------- */
+ if ( !strcmp( attrib, "digits" ) ) {
+ digits = astGetDigits( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", digits );
+ result = getattrib_buff;
+ }
+
+/* Digits(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+
+/* There is no function to obtain the Digits attribute value for an
+ axis directly, so obtain a pointer to the Axis and use this to
+ obtain the value. Use the Frame's Digits attribute instead if the
+ Axis attribute value is not set. */
+ (void) astValidateAxis( this, axis - 1, 1, "astGetDigits(axis)" );
+ ax = astGetAxis( this, axis - 1 );
+ if ( astTestAxisDigits( ax ) ) {
+ digits = astGetAxisDigits( ax );
+ } else {
+ digits = astGetDigits( this );
+ }
+ ax = astAnnul( ax );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", digits );
+ result = getattrib_buff;
+ }
+
+
+/* Direction(axis). */
+/* ---------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ direction = astGetDirection( this, axis - 1 );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", direction );
+ result = getattrib_buff;
+ }
+
+/* Epoch. */
+/* ------ */
+ } else if ( !strcmp( attrib, "epoch" ) ) {
+ epoch = astGetEpoch( this );
+ if ( astOK ) {
+
+/* Format the Epoch as decimal years. Use a Besselian epoch if it will
+ be less than 1984.0, otherwise use a Julian epoch. */
+ result = astFmtDecimalYr( ( epoch < palEpj2d( 1984.0 ) ) ?
+ palEpb( epoch ) : palEpj( epoch ), AST__DBL_DIG );
+ }
+
+/* Top(axis). */
+/* ---------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ dval = astGetTop( this, axis -1 );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval );
+ result = getattrib_buff;
+ }
+
+/* Bottom(axis). */
+/* ---------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ dval = astGetBottom( this, axis -1 );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval );
+ result = getattrib_buff;
+ }
+
+/* Domain. */
+/* ------- */
+ } else if ( !strcmp( attrib, "domain" ) ) {
+ result = astGetDomain( this );
+
+/* Format(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astGetFormat( this, axis - 1 );
+
+/* Label(axis). */
+/* ------------ */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astGetLabel( this, axis - 1 );
+
+/* MatchEnd. */
+/* --------- */
+ } else if ( !strcmp( attrib, "matchend" ) ) {
+ match_end = astGetMatchEnd( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", match_end );
+ result = getattrib_buff;
+ }
+
+/* MaxAxes. */
+/* -------- */
+ } else if ( !strcmp( attrib, "maxaxes" ) ) {
+ max_axes = astGetMaxAxes( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", max_axes );
+ result = getattrib_buff;
+ }
+
+/* MinAxes. */
+/* -------- */
+ } else if ( !strcmp( attrib, "minaxes" ) ) {
+ min_axes = astGetMinAxes( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", min_axes );
+ result = getattrib_buff;
+ }
+
+/* Naxes. */
+/* -----_ */
+ } else if ( !strcmp( attrib, "naxes" ) ) {
+ (void) sprintf( getattrib_buff, "%d", naxes );
+ result = getattrib_buff;
+
+/* Permute. */
+/* -------- */
+ } else if ( !strcmp( attrib, "permute" ) ) {
+ permute = astGetPermute( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", permute );
+ result = getattrib_buff;
+ }
+
+/* PreserveAxes. */
+/* ------------- */
+ } else if ( !strcmp( attrib, "preserveaxes" ) ) {
+ preserve_axes = astGetPreserveAxes( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", preserve_axes );
+ result = getattrib_buff;
+ }
+
+/* Symbol(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astGetSymbol( this, axis - 1 );
+
+/* AlignSystem. */
+/* ------------ */
+/* Obtain the AlignSystem code and convert to a string. */
+ } else if ( !strcmp( attrib, "alignsystem" ) ) {
+ system = astGetAlignSystem( this );
+ if ( astOK ) {
+ result = astSystemString( this, system );
+
+/* Report an error if the value was not recognised. */
+ if ( !result ) {
+ astError( AST__SCSIN,
+ "astGetAttrib(%s): Corrupt %s contains invalid "
+ "AlignSystem identification code (%d).", status,
+ astGetClass( this ), astGetClass( this ), (int) system );
+ }
+ }
+
+/* System. */
+/* ------- */
+/* Obtain the System code and convert to a string. */
+ } else if ( !strcmp( attrib, "system" ) ) {
+ system = astGetSystem( this );
+ if ( astOK ) {
+ result = astSystemString( this, system );
+
+/* Report an error if the value was not recognised. */
+ if ( !result ) {
+ astError( AST__SCSIN,
+ "astGetAttrib(%s): Corrupt %s contains invalid "
+ "System identification code (%d).", status,
+ astGetClass( this ), astGetClass( this ), (int) system );
+ }
+ }
+
+/* Title. */
+/* ------ */
+ } else if ( !strcmp( attrib, "title" ) ) {
+ result = astGetTitle( this );
+
+/* Unit(axis). */
+/* ----------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astGetUnit( this, axis - 1 );
+
+/* NormUnit(axis). */
+/* --------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "normunit(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astGetNormUnit( this, axis - 1 );
+
+/* InternalUnit(axis). */
+/* --------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "internalunit(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astGetInternalUnit( this, axis - 1 );
+
+/* ObsLat. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obslat" ) ) {
+ dval = astGetObsLat( this );
+ if ( astOK ) {
+
+/* If not already created, create an FK5 J2000 SkyFrame which will be used
+ for formatting and unformatting ObsLon and ObsLat values. */
+ if( !skyframe ) {
+ astBeginPM;
+ skyframe = astSkyFrame("system=FK5,equinox=J2000,format(2)=dms.2", status );
+ astEndPM;
+ }
+
+/* Display absolute value preceded by "N" or "S" as appropriate. */
+ if( dval < 0 ) {
+ (void) sprintf( getattrib_buff, "S%s", astFormat( skyframe, 1, -dval ) );
+ } else {
+ (void) sprintf( getattrib_buff, "N%s", astFormat( skyframe, 1, dval ) );
+ }
+ result = getattrib_buff;
+ }
+
+/* ObsLon. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obslon" ) ) {
+ dval = astGetObsLon( this );
+ if ( astOK ) {
+
+/* Put into range +/- PI. */
+ dval = palDrange( dval );
+
+/* If not already created, create an FK5 J2000 SkyFrame which will be used
+ for formatting and unformatting ObsLon and ObsLat values. */
+ if( !skyframe ) {
+ astBeginPM;
+ skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status );
+ astEndPM;
+ }
+
+/* Display absolute value preceded by "E" or "W" as appropriate. */
+ if( dval < 0 ) {
+ (void) sprintf( getattrib_buff, "W%s", astFormat( skyframe, 1, -dval ) );
+ } else {
+ (void) sprintf( getattrib_buff, "E%s", astFormat( skyframe, 1, dval ) );
+ }
+ result = getattrib_buff;
+
+ }
+
+/* ObsAlt. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obsalt" ) ) {
+ dval = astGetObsAlt( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval );
+ result = getattrib_buff;
+ }
+
+/* Dtai. */
+/* ---- */
+ } else if ( !strcmp( attrib, "dtai" ) ) {
+ dval = astGetDtai( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval );
+ result = getattrib_buff;
+ }
+
+/* Dut1. */
+/* ---- */
+ } else if ( !strcmp( attrib, "dut1" ) ) {
+ dval = astGetDut1( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval );
+ result = getattrib_buff;
+ }
+
+/* Other axis attributes. */
+/* ---------------------- */
+/* If the attribute was not identified above, but appears to refer to
+ a Frame axis, then it may refer to an Axis object of a derived type
+ (which has additional attributes not recognised here). */
+ } else if ( !free_axis_attrib && ( nc = 0,
+ ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n",
+ &axis_nc, &axis, &nc ) )
+ && ( nc >= len ) ) ) {
+
+/* Validate the axis index and extract the attribute name. */
+ (void) astValidateAxis( this, axis - 1, 1, "astGet" );
+ axis_attrib = astString( attrib, axis_nc );
+
+/* Obtain a pointer to the Axis object. */
+ ax = astGetAxis( this, axis - 1 );
+ if( astOK ) {
+
+/* Assume that we will be able to use the attribute name. */
+ used = 1;
+
+/* Temporarily switch off error reporting so that if the following attempt
+ to access the axis attribute fails, we can try to interpret the
+ attribute name as an attribute of the primary Frame containing the
+ specified axis. Any errors reported in this context will simply be
+ ignored, in particularly they are not deferred for later delivery. */
+ oldrep = astReporting( 0 );
+
+/* Use the Axis astGetAttrib method to obtain the result. */
+ result = astGetAttrib( ax, axis_attrib );
+
+/* If the above call failed with a status of AST__BADAT, indicating that
+ the attribute name was not recognised, clear the status so that we can
+ try to interpret the attribute name as an attribute of the primary Frame
+ containing the specified axis. */
+ if( astStatus == AST__BADAT ) {
+ astClearStatus;
+
+/* Find the primary Frame containing the specified axis. */
+ astPrimaryFrame( this, axis - 1, &pfrm, &paxis );
+
+/* Only attempt to use the primary Frame if it is not the same as "this"
+ - otherwise we could end up in an infinite loop. */
+ if( pfrm != this ) {
+
+/* astPrimaryFrame returns the original - unpermuted - axis index within
+ the primary Frame. So we need to take into account any axis permutation
+ which has been applied to the primary Frame when forming the attribute name
+ to use below. Find the permuted (external) axis index which corresponds to
+ the internal (unpermuted) axis index "paxis". */
+ paxis = astValidateAxis( pfrm, paxis, 0, "astGet" );
+
+/* Modify the attribute name to refer to the axis numbering of the
+ primary frame. */
+ sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 );
+
+/* Attempt to use the Axis astGetAttrib method to obtain the result. */
+ result = astGetAttrib( pfrm, pfrm_attrib );
+
+/* If this failed, clear the status and indicate that we have not managed to
+ use the attribute name. */
+ if( !astOK ) {
+ astClearStatus;
+ used = 0;
+ }
+
+ } else {
+ used = 0;
+ }
+
+/* If not found attempt to get the attribute value from the Axis, omitting
+ the axis index. */
+ if( ! used ) {
+ result = astGetAttrib( pfrm, axis_attrib );
+ if( !astOK ) {
+ astClearStatus;
+ } else {
+ used = 1;
+ }
+ }
+
+/* Annul the primary Frame pointer. */
+ pfrm = astAnnul( pfrm );
+ }
+
+/* Re-instate the original error reporting state. */
+ astReporting( oldrep );
+
+/* If we could not use the attribute name, attempt to get the axis
+ attribute again, this time retaining the error report. This is done
+ to ensure the user gets an appropriate error message. */
+ if( !used ) result = astGetAttrib( ax, axis_attrib );
+ }
+
+/* Annul the Axis pointer and free the memory holding the attribute
+ name. */
+ ax = astAnnul( ax );
+ axis_attrib = astFree( axis_attrib );
+
+/* Not recognised. */
+/* --------------- */
+/* If the attribute is still not recognised, and the Frame has only 1 axis,
+ and the attribute name does not already include an axis specifier, try
+ again after appending "(1)" to the end of the attribute name. */
+ } else if( !has_axis && naxes == 1 ) {
+
+/* Take a copy of the supplied name, allowing 3 extra characters for the
+ axis specifier "(1)". */
+ axis_attrib = astMalloc( len + 4 );
+ if( axis_attrib ) memcpy( axis_attrib, attrib, len );
+
+/* Indicate we should free the axis_attrib memory. */
+ free_axis_attrib = 1;
+
+/* Add in the axis specifier. */
+ strcpy( axis_attrib + len, "(1)" );
+
+/* Use the new attribute name instead of the supplied name. */
+ old_attrib = attrib;
+ attrib = axis_attrib;
+
+/* Indicate the attribute name now has an axis specifier. */
+ has_axis = 1;
+
+/* Jump back to try interpreting the new attribute name. */
+ goto L1;
+
+/* Not recognised. */
+/* --------------- */
+/* If the attribute name is still not recognised, pass it on to the parent
+ method for further interpretation. First re-instate the original attrib
+ name string if it was changed above. */
+ } else {
+ if( free_axis_attrib ) {
+ attrib = old_attrib;
+ axis_attrib = astFree( axis_attrib );
+ }
+ result = (*parent_getattrib)( this_object, attrib, status );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static AstAxis *GetAxis( AstFrame *this, int axis, int *status ) {
+/*
+*+
+* Name:
+* astGetAxis
+
+* Purpose:
+* Obtain a pointer to a specified Axis from a Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* AstAxis *astGetAxis( AstFrame *this, int axis )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns a pointer to the Axis object associated
+* with one of the axes of a Frame. This object describes the
+* quantity which is represented along that axis.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the axis (zero-based) for which an Axis pointer is
+* required.
+
+* Returned Value:
+* A pointer to the requested Axis object.
+
+* Notes:
+* - The reference count of the requested Axis object will be
+* incremented by one to reflect the additional pointer returned by
+* this function.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ AstAxis *result; /* Pointer to Axis */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Initialise. */
+ result = NULL;
+
+/* Validate and permute the axis index. */
+ axis = astValidateAxis( this, axis, 1, "astGetAxis" );
+
+/* If OK, clone the required Axis pointer. */
+ if ( astOK ) result = astClone( this->axis[ axis ] );
+
+/* Return the result. */
+ return result;
+}
+
+static const char *GetDefaultLabel( int axis, int *status ) {
+/*
+* Name:
+* GetDefaultLabel
+
+* Purpose:
+* Return a pointer to a default axis Label string.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* const char *GetDefaultLabel( int axis, int *status )
+
+* Class Membership:
+* Frame member function
+
+* Description:
+* This function returns a pointer to a string holding a default axis
+* Label value.
+
+* Parameters:
+* axis
+* Zero based axis index.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* - Pointer to a static null-terminated string containing the attribute
+* value.
+
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(NULL);
+
+/* Format the axis index, putting the string in a global buffer. */
+ (void) sprintf( label_buff, "Axis %d", axis + 1 );
+
+/* Return a pointer to the global buffer. */
+ return label_buff;
+}
+
+static const char *GetDefaultSymbol( AstFrame *this, int axis, int *status ) {
+/*
+* Name:
+* GetDefaultSymbol
+
+* Purpose:
+* Return a pointer to a default axis Symbol string.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* const char *GetDefaultSymbol( AstFrame *this, int axis, int *status )
+
+* Class Membership:
+* Frame member function
+
+* Description:
+* This function returns a pointer to a string holding a default axis
+* Symbol value.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* Zero based axis index.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* - Pointer to a static null-terminated string containing the attribute
+* value.
+
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* Note we use "sprintf" once to determine how many characters are
+ produced by the "%d" format string and then limit the number of
+ characters used from the Domain string in the second invocation of
+ "sprintf" so that the total length of the default Symbol string
+ does not exceed SYMBOL_BUFF_LEN characters. */
+ (void) sprintf( symbol_buff, "%.*s%d",
+ SYMBOL_BUFF_LEN - sprintf( symbol_buff, "%d", axis + 1 ),
+ astTestDomain( this ) ? astGetDomain( this ) : "x",
+ axis + 1 );
+
+/* Use the AddUnderscores function to replace any white space in the Symbol
+ string with underscore characters. */
+ AddUnderscores( symbol_buff, status );
+
+/* Return a pointer to the global buffer. */
+ return symbol_buff;
+}
+
+static const char *GetDefaultTitle( AstFrame *this, int *status ) {
+/*
+* Name:
+* GetDefaultTitle
+
+* Purpose:
+* Return a pointer to a default Title string.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* const char *GetDefaultTitle( AstFrame *this, int *status )
+
+* Class Membership:
+* Frame member function
+
+* Description:
+* This function returns a pointer to a string holding a default Title value.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* - Pointer to a static null-terminated string containing the attribute
+* value.
+
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* Create the Title value and put it in the global buffer. */
+ (void) sprintf( title_buff, "%d-d coordinate system", astGetNaxes( this ) );
+
+/* Return a pointer to the global buffer. */
+ return title_buff;
+}
+
+static int GetFrameFlags( AstFrame *this, int *status ){
+/*
+*+
+* Name:
+* astGetFrameFlags
+
+* Purpose:
+* Return the bit mask of flags associated with a Frame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frame.h"
+* int *astGetFrameFlags( astFrame *this )
+
+* Class Membership:
+* Frame virtual function.
+
+* Description:
+* This function returns a bit mask holding the current set of flags
+* associated with a Frame. See astSetFrameFlags for details of these
+* flags.
+
+* Parameters:
+* this
+* The Frame.
+
+* Returned Value:
+* The bit mask.
+
+* Notes:
+* - Zero is returned if this function is invoked with
+* the global error status set or if it should fail for any reason.
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Return the result. */
+ return this->flags;
+}
+
+static int GetIsLinear( AstMapping *this_mapping, int *status ){
+/*
+* Name:
+* GetIsLinear
+
+* Purpose:
+* Return the value of the IsLinear attribute for a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "mapping.h"
+* void GetIsLinear( AstMapping *this, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the protected astGetIsLinear
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns the value of the IsLinear attribute for a
+* Frame, which is always one because a Frame is treated like a UnitMap.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+*/
+ return 1;
+}
+
+static int GetIsSimple( AstMapping *this_mapping, int *status ){
+/*
+* Name:
+* GetIsSimple
+
+* Purpose:
+* Return the value of the IsSimple attribute for a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "mapping.h"
+* void GetIsSimple( AstMapping *this, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the protected astGetIsSimple
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns the value of the IsSimple attribute for a
+* Frame, which is always zero because Frames are not immutable (unlike
+* non-Frame Mappings).
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+*/
+ return 0;
+}
+
+static int GetNaxes( AstFrame *this, int *status ) {
+/*
+*+
+* Name:
+* astGetNaxes
+
+* Purpose:
+* Determine how many axes a Frame has.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astGetNaxes( AstFrame *this )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns the number of axes for a Frame.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+
+* Returned Value:
+* The number of Frame axes.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Return the number of Frame axes. */
+ return this->naxes;
+}
+
+static int GetNin( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* GetNin
+
+* Purpose:
+* Get the number of input coordinates for a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int GetNin( AstMapping *this, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the astGetNin method inherited
+* from the Mapping class).
+
+* Description:
+* This function returns the number of input coordinate values
+* required per point by a Frame, when used as a Mapping (i.e. the
+* number of dimensions of the space in which input points reside).
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Number of coordinate values required.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *this; /* Pointer to Frame structure */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_mapping;
+
+/* Return the number of Frame axes. */
+ result = astGetNaxes( this );
+
+/* Return the result. */
+ return result;
+}
+
+static int GetNout( AstMapping *this_mapping, int *status ) {
+/*
+* Name:
+* GetNout
+
+* Purpose:
+* Get the number of output coordinates for a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int GetNout( AstMapping *this, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the astGetNout method
+* inherited from the Mapping class).
+
+* Description:
+* This function returns the number of output coordinate values
+* generated per point by a Frame, when used as a Mapping (i.e. the
+* number of dimensions of the space in which output points
+* reside).
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Number of coordinate values generated.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstFrame *this; /* Pointer to Frame structure */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_mapping;
+
+/* Return the number of Frame axes. */
+ result = astGetNaxes( this );
+
+/* Return the result. */
+ return result;
+}
+
+static int GetObjSize( AstObject *this_object, int *status ) {
+/*
+* Name:
+* GetObjSize
+
+* Purpose:
+* Return the in-memory size of an Object.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int GetObjSize( AstObject *this, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the astGetObjSize protected
+* method inherited from the parent class).
+
+* Description:
+* This function returns the in-memory size of the supplied Frame,
+* in bytes.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The Object size, in bytes.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstFrame *this; /* Pointer to Frame structure */
+ int axis; /* Axis index */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointers to the FrameSet structure. */
+ this = (AstFrame *) this_object;
+
+/* Invoke the GetObjSize method inherited from the parent class, and then
+ add on any components of the class structure defined by this class
+ which are stored in dynamically allocated memory. */
+ result = (*parent_getobjsize)( this_object, status );
+ result += astGetObjSize( this->variants );
+ result += astTSizeOf( this->domain );
+ result += astTSizeOf( this->title );
+ result += astTSizeOf( this->axis );
+ result += astTSizeOf( this->perm );
+
+ for ( axis = 0; axis < this->naxes; axis++ ) {
+ result += astGetObjSize( this->axis[ axis ] );
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result, */
+ return result;
+}
+
+static const int *GetPerm( AstFrame *this, int *status ) {
+/*
+*+
+* Name:
+* astGetPerm
+
+* Purpose:
+* Access the axis permutation array for a Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* const int *astGetPerm( AstFrame *this )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns a pointer to the axis permutation array
+* for a Frame. This array constitutes a lookup-table that converts
+* between an axis number supplied externally and the corresponding
+* index in the Frame's internal axis arrays.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+
+* Returned Value:
+* Pointer to the Frame's axis permutation array (a constant array
+* of int). Each element of this contains the (zero-based)
+* internal axis index to be used in place of the external index
+* which is used to address the permutation array. If the Frame has
+* zero axes, this pointer will be NULL.
+
+* Notes:
+* - This protected method is provided to assist class
+* implementations which need to implement axis-dependent
+* extensions to Frame methods, and which therefore need to know
+* how a Frames's external axis index is converted for internal
+* use.
+* - The pointer returned by this function gives direct access to
+* data internal to the Frame object. It remains valid only so long
+* as the Frame exists. The permutation array contents may be
+* modified by other functions which operate on the Frame and this
+* may render the returned pointer invalid.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Return a pointer to the axis permutation array. */
+ return this->perm;
+}
+
+static AstFrameSet *GetFrameVariants( AstFrame *this, int *status ){
+/*
+*+
+* Name:
+* astGetFrameVariants
+
+* Purpose:
+* Returns the FrameSet holding the available Frame variants.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* AstFrameSet *astGetFrameVariants( AstFrame *this )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns a pointer to any FrameSet previously stored
+* in the Frame using method astSetVariants.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+
+* Returned Value:
+* astGetFrameVariants
+* A pointer to the FrameSet. It should be annulled using astAnnul
+* when no longer needed. NULL will be returned if no FrameSet is
+* stored in the Frame.
+
+* Notes:
+* - A NULL value will be returned if this function is invoked with the
+* AST error status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstFrameSet *result;
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a clone of any FrameSet pointer. */
+ if( this->variants ) result = astClone( this->variants );
+
+/* Return the result. */
+ return result;
+}
+
+void astInitFrameVtab_( AstFrameVtab *vtab, const char *name, int *status ) {
+/*
+*+
+* Name:
+* astInitFrameVtab
+
+* Purpose:
+* Initialise a virtual function table for a Frame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frame.h"
+* void astInitFrameVtab( AstFrameVtab *vtab, const char *name )
+
+* Class Membership:
+* Frame vtab initialiser.
+
+* Description:
+* This function initialises the component of a virtual function
+* table which is used by the Frame class.
+
+* Parameters:
+* vtab
+* Pointer to the virtual function table. The components used by
+* all ancestral classes will be initialised if they have not already
+* been initialised.
+* name
+* Pointer to a constant null-terminated character string which contains
+* the name of the class to which the virtual function table belongs (it
+* is this pointer value that will subsequently be returned by the Object
+* astClass function).
+*-
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstObjectVtab *object; /* Pointer to Object component of Vtab */
+ AstMappingVtab *mapping; /* Pointer to Mapping component of Vtab */
+
+/* Check the local error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Initialize the component of the virtual function table used by the
+ parent class. */
+ astInitMappingVtab( (AstMappingVtab *) vtab, name );
+
+/* Store a unique "magic" value in the virtual function table. This
+ will be used (by astIsAFrame ) to determine if an object belongs
+ to this class. We can conveniently use the address of the (static)
+ class_check variable to generate this unique value. */
+ vtab->id.check = &class_check;
+ vtab->id.parent = &(((AstMappingVtab *) vtab)->id);
+
+/* Initialise member function pointers. */
+/* ------------------------------------ */
+/* Store pointers to the member functions (implemented here) that provide
+ virtual methods for this class. */
+ vtab->Abbrev = Abbrev;
+ vtab->CheckPerm = CheckPerm;
+ vtab->ClearDigits = ClearDigits;
+ vtab->ClearDirection = ClearDirection;
+ vtab->ClearDomain = ClearDomain;
+ vtab->ClearFormat = ClearFormat;
+ vtab->ClearLabel = ClearLabel;
+ vtab->ClearMatchEnd = ClearMatchEnd;
+ vtab->ClearMaxAxes = ClearMaxAxes;
+ vtab->ClearMinAxes = ClearMinAxes;
+ vtab->ClearPermute = ClearPermute;
+ vtab->ClearPreserveAxes = ClearPreserveAxes;
+ vtab->ClearSymbol = ClearSymbol;
+ vtab->ClearTitle = ClearTitle;
+ vtab->ClearUnit = ClearUnit;
+ vtab->Convert = Convert;
+ vtab->ConvertX = ConvertX;
+ vtab->Angle = Angle;
+ vtab->Distance = Distance;
+ vtab->Fields = Fields;
+ vtab->FindFrame = FindFrame;
+ vtab->MatchAxes = MatchAxes;
+ vtab->MatchAxesX = MatchAxesX;
+ vtab->Format = Format;
+ vtab->Centre = Centre;
+ vtab->Gap = Gap;
+ vtab->GetAxis = GetAxis;
+ vtab->GetDigits = GetDigits;
+ vtab->GetDirection = GetDirection;
+ vtab->GetDomain = GetDomain;
+ vtab->GetFormat = GetFormat;
+ vtab->GetLabel = GetLabel;
+ vtab->GetMatchEnd = GetMatchEnd;
+ vtab->GetMaxAxes = GetMaxAxes;
+ vtab->GetMinAxes = GetMinAxes;
+ vtab->GetNaxes = GetNaxes;
+ vtab->GetPerm = GetPerm;
+ vtab->GetPermute = GetPermute;
+ vtab->GetPreserveAxes = GetPreserveAxes;
+ vtab->GetSymbol = GetSymbol;
+ vtab->GetTitle = GetTitle;
+ vtab->GetUnit = GetUnit;
+ vtab->GetInternalUnit = GetInternalUnit;
+ vtab->GetNormUnit = GetNormUnit;
+ vtab->Intersect = Intersect;
+ vtab->IsUnitFrame = IsUnitFrame;
+ vtab->Match = Match;
+ vtab->Norm = Norm;
+ vtab->NormBox = NormBox;
+ vtab->AxDistance = AxDistance;
+ vtab->AxNorm = AxNorm;
+ vtab->AxOffset = AxOffset;
+ vtab->AxIn = AxIn;
+ vtab->AxAngle = AxAngle;
+ vtab->FrameGrid = FrameGrid;
+ vtab->Offset = Offset;
+ vtab->Offset2 = Offset2;
+ vtab->Resolve = Resolve;
+ vtab->ResolvePoints = ResolvePoints;
+ vtab->LineDef = LineDef;
+ vtab->LineContains = LineContains;
+ vtab->LineCrossing = LineCrossing;
+ vtab->LineOffset = LineOffset;
+ vtab->Overlay = Overlay;
+ vtab->PermAxes = PermAxes;
+ vtab->PickAxes = PickAxes;
+ vtab->PrimaryFrame = PrimaryFrame;
+ vtab->SetAxis = SetAxis;
+ vtab->SetDigits = SetDigits;
+ vtab->SetDirection = SetDirection;
+ vtab->SetDomain = SetDomain;
+ vtab->SetFormat = SetFormat;
+ vtab->SetLabel = SetLabel;
+ vtab->SetMatchEnd = SetMatchEnd;
+ vtab->SetMaxAxes = SetMaxAxes;
+ vtab->SetMinAxes = SetMinAxes;
+ vtab->SetPermute = SetPermute;
+ vtab->SetPreserveAxes = SetPreserveAxes;
+ vtab->SetSymbol = SetSymbol;
+ vtab->SetTitle = SetTitle;
+ vtab->SetUnit = SetUnit;
+ vtab->SubFrame = SubFrame;
+ vtab->TestDigits = TestDigits;
+ vtab->TestDirection = TestDirection;
+ vtab->TestDomain = TestDomain;
+ vtab->TestFormat = TestFormat;
+ vtab->TestLabel = TestLabel;
+ vtab->TestMatchEnd = TestMatchEnd;
+ vtab->TestMaxAxes = TestMaxAxes;
+ vtab->TestMinAxes = TestMinAxes;
+ vtab->TestPermute = TestPermute;
+ vtab->TestPreserveAxes = TestPreserveAxes;
+ vtab->TestSymbol = TestSymbol;
+ vtab->TestTitle = TestTitle;
+ vtab->TestUnit = TestUnit;
+ vtab->Unformat = Unformat;
+ vtab->ValidateAxis = ValidateAxis;
+ vtab->ValidateAxisSelection = ValidateAxisSelection;
+ vtab->ValidateSystem = ValidateSystem;
+ vtab->SystemString = SystemString;
+ vtab->SystemCode = SystemCode;
+
+ vtab->GetFrameFlags = GetFrameFlags;
+ vtab->SetFrameFlags = SetFrameFlags;
+
+ vtab->TestActiveUnit = TestActiveUnit;
+ vtab->GetActiveUnit = GetActiveUnit;
+ vtab->SetActiveUnit = SetActiveUnit;
+
+ vtab->GetFrameVariants = GetFrameVariants;
+ vtab->SetFrameVariants = SetFrameVariants;
+
+ vtab->ClearSystem = ClearSystem;
+ vtab->GetSystem = GetSystem;
+ vtab->SetSystem = SetSystem;
+ vtab->TestSystem = TestSystem;
+
+ vtab->ClearAlignSystem = ClearAlignSystem;
+ vtab->GetAlignSystem = GetAlignSystem;
+ vtab->SetAlignSystem = SetAlignSystem;
+ vtab->TestAlignSystem = TestAlignSystem;
+
+ vtab->ClearTop = ClearTop;
+ vtab->GetTop = GetTop;
+ vtab->SetTop = SetTop;
+ vtab->TestTop = TestTop;
+
+ vtab->ClearBottom = ClearBottom;
+ vtab->GetBottom = GetBottom;
+ vtab->SetBottom = SetBottom;
+ vtab->TestBottom = TestBottom;
+
+ vtab->ClearEpoch = ClearEpoch;
+ vtab->GetEpoch = GetEpoch;
+ vtab->SetEpoch = SetEpoch;
+ vtab->TestEpoch = TestEpoch;
+
+ vtab->ClearObsLat = ClearObsLat;
+ vtab->TestObsLat = TestObsLat;
+ vtab->GetObsLat = GetObsLat;
+ vtab->SetObsLat = SetObsLat;
+
+ vtab->ClearObsLon = ClearObsLon;
+ vtab->TestObsLon = TestObsLon;
+ vtab->GetObsLon = GetObsLon;
+ vtab->SetObsLon = SetObsLon;
+
+ vtab->ClearObsAlt = ClearObsAlt;
+ vtab->TestObsAlt = TestObsAlt;
+ vtab->GetObsAlt = GetObsAlt;
+ vtab->SetObsAlt = SetObsAlt;
+
+ vtab->ClearDtai = ClearDtai;
+ vtab->GetDtai = GetDtai;
+ vtab->SetDtai = SetDtai;
+ vtab->TestDtai = TestDtai;
+
+ vtab->ClearDut1 = ClearDut1;
+ vtab->GetDut1 = GetDut1;
+ vtab->SetDut1 = SetDut1;
+ vtab->TestDut1 = TestDut1;
+
+/* Save the inherited pointers to methods that will be extended, and
+ replace them with pointers to the new member functions. */
+ object = (AstObjectVtab *) vtab;
+
+ parent_getobjsize = object->GetObjSize;
+ object->GetObjSize = GetObjSize;
+ parent_clearattrib = object->ClearAttrib;
+ object->ClearAttrib = ClearAttrib;
+ parent_getattrib = object->GetAttrib;
+ object->GetAttrib = GetAttrib;
+ parent_setattrib = object->SetAttrib;
+ object->SetAttrib = SetAttrib;
+ parent_testattrib = object->TestAttrib;
+ object->TestAttrib = TestAttrib;
+
+ parent_cleanattribs = object->CleanAttribs;
+ object->CleanAttribs = CleanAttribs;
+
+#if defined(THREAD_SAFE)
+ parent_managelock = object->ManageLock;
+ object->ManageLock = ManageLock;
+#endif
+
+/* Store replacement pointers for methods which will be over-ridden by
+ new member functions implemented here. */
+ mapping = (AstMappingVtab *) vtab;
+
+ object->Equal = Equal;
+ mapping->GetIsLinear = GetIsLinear;
+ mapping->GetIsSimple = GetIsSimple;
+ mapping->GetNin = GetNin;
+ mapping->GetNout = GetNout;
+ mapping->ReportPoints = ReportPoints;
+ mapping->Transform = Transform;
+ mapping->MapSplit = MapSplit;
+ mapping->DoNotSimplify = DoNotSimplify;
+
+/* Declare the copy constructor, destructor and class dump
+ function. */
+ astSetCopy( vtab, Copy );
+ astSetDelete( vtab, Delete );
+ astSetDump( vtab, Dump, "Frame", "Coordinate system description" );
+
+/* If we have just initialised the vtab for the current class, indicate
+ that the vtab is now initialised, and store a pointer to the class
+ identifier in the base "object" level of the vtab. */
+ if( vtab == &class_vtab ) {
+ class_init = 1;
+ astSetVtabClassIdentifier( vtab, &(vtab->id) );
+ }
+}
+
+static void Intersect( AstFrame *this, const double a1[2],
+ const double a2[2], const double b1[2],
+ const double b2[2], double cross[2],
+ int *status ) {
+/*
+*++
+* Name:
+c astIntersect
+f AST_INTERSECT
+
+* Purpose:
+* Find the point of intersection between two geodesic curves.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c void astIntersect( AstFrame *this, const double a1[2],
+c const double a2[2], const double b1[2],
+c const double b2[2], double cross[2] )
+f CALL AST_INTERSECT( THIS, A1, A2, B1, B2, CROSS, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function
+f This routine
+* finds the coordinate values at the point of intersection between
+* two geodesic curves. Each curve is specified by two points on
+* the curve. It can only be used with 2-dimensional Frames.
+*
+* For example, in a basic Frame, it will find the point of
+* intersection between two straight lines. But for a SkyFrame it
+* will find an intersection of two great circles.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c a1
+f A1( 2 ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This should contain the coordinates of the
+* first point on the first geodesic curve.
+c a2
+f A2( 2 ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This should contain the coordinates of a
+* second point on the first geodesic curve. It should not be
+* co-incident with the first point.
+c b1
+f B1( 2 ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This should contain the coordinates of the
+* first point on the second geodesic curve.
+c b2
+f B2( 2 ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This should contain the coordinates of a
+* second point on the second geodesic curve. It should not be
+* co-incident with the first point.
+c cross
+f CROSS( 2 ) = DOUBLE PRECISION (Returned)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* in which the coordinates of the required intersection will
+* be returned.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - For SkyFrames each curve will be a great circle, and in general
+* each pair of curves will intersect at two diametrically opposite
+* points on the sky. The returned position is the one which is
+* closest to point
+c "a1".
+f A1.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value, or if the two
+* points defining either geodesic are co-incident, or if the two
+* curves do not intersect.
+c - The geodesic curve used by this function is the path of
+f - The geodesic curve used by this routine is the path of
+* shortest distance between two points, as defined by the
+c astDistance function.
+f AST_DISTANCE function.
+* - An error will be reported if the Frame is not 2-dimensional.
+*--
+*/
+
+/* Local Variables: */
+ double ca; /* Y axis intercept of line a */
+ double cb; /* Y axis intercept of line b */
+ double dxa; /* X range spanned by line a */
+ double dxb; /* X range spanned by line b */
+ double ma; /* Gradient of line a */
+ double mb; /* Gradient of line b */
+ int naxes; /* Number of Frame axes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Initialize bad values. */
+ cross[ 0 ] = AST__BAD;
+ cross[ 1 ] = AST__BAD;
+
+/* Determine the number of Frame axes. */
+ naxes = astGetNaxes( this );
+
+/* Report an error if the Frame is not 2 dimensional. */
+ if( naxes != 2 && astOK ) {
+ astError( AST__NAXIN, "astIntersect(%s): Invalid number of Frame axes (%d)."
+ " astIntersect can only be used with 2 dimensonal Frames.", status,
+ astGetClass( this ), naxes );
+ }
+
+/* Check that all supplied values are OK. */
+ if ( ( a1[ 0 ] != AST__BAD ) && ( a1[ 1 ] != AST__BAD ) &&
+ ( a2[ 0 ] != AST__BAD ) && ( a2[ 1 ] != AST__BAD ) &&
+ ( b1[ 0 ] != AST__BAD ) && ( b1[ 1 ] != AST__BAD ) &&
+ ( b2[ 0 ] != AST__BAD ) && ( b2[ 1 ] != AST__BAD ) ) {
+
+/* Find the x increments spanned by the two lines. */
+
+/* Check the first line is not vertical. */
+ dxa = a2[ 0 ] - a1[ 0 ];
+ dxb = b2[ 0 ] - b1[ 0 ];
+ if( dxa != 0.0 ) {
+
+/* Find the gradient and Y axis intercept of the first line. */
+ ma = ( a2[ 1 ] - a1[ 1 ] )/dxa;
+ ca = a1[ 1 ] - a1[ 0 ]*ma;
+
+/* Check the second line is not vertical. */
+ if( dxb != 0.0 ) {
+
+/* Find the gradient and Y axis intercept of the second line. */
+ mb = ( b2[ 1 ] - b1[ 1 ] )/dxb;
+ cb = b1[ 1 ] - b1[ 0 ]*mb;
+
+/* Check the lines are not parallel. */
+ if( ma != mb ) {
+
+/* Find the intersection of the two lines. */
+ cross[ 0 ] = ( cb -ca )/( ma - mb );
+ cross[ 1 ] = ( ( ma + mb )*cross[ 0 ] + ca + cb )/2;
+ }
+
+/* If the second line is vertical but the first is not. */
+ } else if( b1[ 1 ] != b2[ 1 ] ){
+ cross[ 0 ] = b1[ 0 ];
+ cross[ 1 ] = ma*b1[ 0 ] + ca;
+ }
+
+/* First line is vertical but second is not. */
+ } else if( dxb != 0.0 && a1[ 1 ] != a2[ 1 ] ){
+
+/* Find the gradient and Y axis intercept of the second line. */
+ mb = ( b2[ 1 ] - b1[ 1 ] )/dxb;
+ cb = b1[ 1 ] - b1[ 0 ]*mb;
+
+/* Find the intercection. */
+ cross[ 0 ] = a1[ 0 ];
+ cross[ 1 ] = mb*a1[ 0 ] + cb;
+ }
+ }
+}
+
+static int IsUnitFrame( AstFrame *this, int *status ){
+/*
+*+
+* Name:
+* astIsUnitFrame
+
+* Purpose:
+* Is this Frame equivalent to a UnitMap?
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astIsUnitFrame( AstFrame *this )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns a flag indicating if the supplied Frame is
+* equivalent to a UnitMap when treated as a Mapping (note, the Frame
+* class inherits from Mapping and therefore every Frame is also a Mapping).
+
+* Parameters:
+* this
+* Pointer to the Frame.
+
+* Returned Value:
+* A non-zero value is returned if the supplied Frame is equivalent to
+* a UnitMap when treated as a Mapping.
+
+*-
+*/
+
+/* Check the local error status. */
+ if( !astOK ) return 0;
+
+/* The base Frame class is always equivalent to a UnitMap. */
+ return 1;
+}
+
+static int LineContains( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) {
+/*
+*+
+* Name:
+* astLineContains
+
+* Purpose:
+* Determine if a line contains a point.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astLineContains( AstFrame *this, AstLineDef *l, int def, double *point )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function determines if the supplied point is on the supplied
+* line within the supplied Frame. The start point of the line is
+* considered to be within the line, but the end point is not. The tests
+* are that the point of closest approach of the line to the point should
+* be between the start and end, and that the distance from the point to
+* the point of closest aproach should be less than 1.0E-7 of the length
+* of the line.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* l
+* Pointer to the structure defining the line.
+* def
+* Should be set non-zero if the "point" array was created by a
+* call to astLineCrossing (in which case it may contain extra
+* information following the axis values),and zero otherwise.
+* point
+* Point to an array containing the axis values of the point to be
+* tested, possibly followed by extra cached information (see "def").
+
+* Returned Value:
+* A non-zero value is returned if the line contains the point.
+
+* Notes:
+* - The pointer supplied for "l" should have been created using the
+* astLineDef method. These structures contained cached information about
+* the lines which improve the efficiency of this method when many
+* repeated calls are made. An error will be reported if the structure
+* does not refer to the Frame specified by "this".
+* - Zero will be returned if this function is invoked with the global
+* error status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ int result;
+ double dx, dy, p;
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Check that the line refers to the supplied Frame. */
+ if( l->frame != this ) {
+ astError( AST__INTER, "astLineContains(%s): The supplied line does "
+ "not relate to the supplied %s (AST internal programming "
+ "error).", status, astGetClass( this ), astGetClass( this ) );
+
+/* If the point is good, find the offsets from the start of the line. */
+ } else if( point[ 0 ] != AST__BAD && point[ 1 ] != AST__BAD ) {
+ dx = point[ 0 ] - l->start[ 0 ];
+ dy = point[ 1 ] - l->start[ 1 ];
+
+/* Check the nearest point on the line is between the start and end.
+ Exclude the end point. */
+ p = dx*l->dir[ 0 ] + dy*l->dir[ 1 ];
+ if( p >= 0.0 && p < l->length ) {
+
+/* Check the distance from the point to the nearest point on the line is not
+ further than 1.0E-7 of the length of the line. */
+ if( fabs( dx*l->q[ 0 ] + dy*l->q[ 1 ] ) <= 1.0E-7*l->length ) {
+ result = 1;
+ }
+ }
+ }
+
+/* Return zero if an error occurred. */
+ if( !astOK ) result = 0;
+
+/* Return a pointer to the output structure. */
+ return result;
+}
+
+static int LineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
+ double **cross, int *status ) {
+/*
+*+
+* Name:
+* astLineCrossing
+
+* Purpose:
+* Determine if two lines cross.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astLineCrossing( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
+* double **cross )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function determines if the two suplied line segments cross,
+* and if so returns the axis values at the point where they cross.
+* A flag is also returned indicating if the crossing point occurs
+* within the length of both line segments, or outside one or both of
+* the line segments.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* l1
+* Pointer to the structure defining the first line.
+* l2
+* Pointer to the structure defining the second line.
+* cross
+* Pointer to a location at which to put a pointer to a dynamically
+* alocated array containing the axis values at the crossing. If
+* NULL is supplied no such array is returned. Otherwise, the returned
+* array should be freed using astFree when no longer needed. If the
+* lines are parallel (i.e. do not cross) then AST__BAD is returned for
+* all axis values. Note usable axis values are returned even if the
+* lines cross outside the segment defined by the start and end points
+* of the lines. The order of axes in the returned array will take
+* account of the current axis permutation array if appropriate. Note,
+* sub-classes such as SkyFrame may append extra values to the end
+* of the basic frame axis values. A NULL pointer is returned if an
+* error occurs.
+
+* Returned Value:
+* A non-zero value is returned if the lines cross at a point which is
+* within the [start,end) segment of the lines that are flagged as
+* finite (if a line is marked as infinite any crossing is assumed to
+* be within the bounds of the line). If the crossing point is outside
+* this segment on either (inifinte) line, or if the lines are parallel,
+* zero is returned. Note, the start point is considered to be inside
+* the length of the segment, but the end point is outside.
+
+* Notes:
+* - The pointers supplied for "l1" and "l2" should have been created
+* using the astLineDef method. These structures contained cached
+* information about the lines which improve the efficiency of this method
+* when many repeated calls are made. An error will be reported if
+* either structure does not refer to the Frame specified by "this".
+* - Zero will be returned if this function is invoked with the global
+* error status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ double *crossing; /* Returned array */
+ double den; /* Denominator */
+ double dx; /* Offset in start X values */
+ double dy; /* Offset in start Y values */
+ double t1; /* Distance from start of line 1 to crossing */
+ double t2; /* Distance from start of line 2 to crossing */
+ int result; /* Returned value */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Initialise. */
+ result = 0;
+ crossing = astMalloc( sizeof(double)*2 );
+
+/* Check that both lines refer to the supplied Frame. */
+ if( l1->frame != this ) {
+ astError( AST__INTER, "astLineCrossing(%s): First supplied line does "
+ "not relate to the supplied %s (AST internal programming "
+ "error).", status, astGetClass( this ), astGetClass( this ) );
+
+ } else if( l2->frame != this ) {
+ astError( AST__INTER, "astLineCrossing(%s): Second supplied line does "
+ "not relate to the supplied %s (AST internal programming "
+ "error).", status, astGetClass( this ), astGetClass( this ) );
+
+ } else if( crossing ){
+
+/* Each of the lines can be represented as "p = start + t.v" where start is
+ the start position, v is the unit vector pointing from start to end,
+ and t is the scalar distance from the start position. So to find the
+ intersection put "start1 + t1.v1 = start2 + t2.v2" and solve for t1
+ and t2. */
+ den = (l1->dir[ 0 ])*(l2->dir[ 1 ]) - (l2->dir[ 0 ])*(l1->dir[ 1 ]);
+ if( den != 0.0 ) {
+ dx = l2->start[ 0 ] - l1->start[ 0 ];
+ dy = l2->start[ 1 ] - l1->start[ 1 ];
+ t1 = ( l2->dir[ 1 ]*dx - l2->dir[ 0 ]*dy )/den;
+ t2 = ( l1->dir[ 1 ]*dx - l1->dir[ 0 ]*dy )/den;
+
+/* Store the crossing point, using the smaller t value to redue error. */
+ if( fabs( t1 ) < fabs( t2 ) ) {
+ crossing[ 0 ] = l1->start[ 0 ] + t1*l1->dir[ 0 ];
+ crossing[ 1 ] = l1->start[ 1 ] + t1*l1->dir[ 1 ];
+ } else {
+ crossing[ 0 ] = l2->start[ 0 ] + t2*l2->dir[ 0 ];
+ crossing[ 1 ] = l2->start[ 1 ] + t2*l2->dir[ 1 ];
+ }
+
+/* See if the intersection is within the length of both lines (excluding
+ the end points). If a line is flagged as infinite, set the "t" parameter
+ to zero to make it look like the crossing is within the line. */
+ if( l1->infinite ) t1 = 0.0;
+ if( l2->infinite ) t2 = 0.0;
+
+ if( t1 >= 0.0 && t1 < l1->length &&
+ t2 >= 0.0 && t2 < l2->length ) result = 1;
+
+ } else {
+ crossing[ 0 ] = AST__BAD;
+ crossing[ 1 ] = AST__BAD;
+ }
+ }
+
+/* Return zero if an error occurred. */
+ if( !astOK ) {
+ crossing = astFree( crossing );
+ result = 0;
+ }
+
+/* Return the crossing pointer. */
+ if( cross ) {
+ *cross = crossing;
+ } else if( crossing ){
+ crossing = astFree( crossing );
+ }
+
+/* Return a pointer to the output structure. */
+ return result;
+}
+
+static AstLineDef *LineDef( AstFrame *this, const double start[2],
+ const double end[2], int *status ) {
+/*
+*+
+* Name:
+* astLineDef
+
+* Purpose:
+* Creates a structure describing a line segment in a 2D Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* AstLineDef *astLineDef( AstFrame *this, const double start[2],
+* const double end[2] )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function creates a structure containing information describing a
+* given line segment within the supplied 2D Frame. This may include
+* information which allows other methods such as astLineCrossing to
+* function more efficiently. Thus the returned structure acts as a
+* cache to store intermediate values used by these other methods.
+
+* Parameters:
+* this
+* Pointer to the Frame. Must have 2 axes.
+* start
+* An array of 2 doubles marking the start of the line segment.
+* end
+* An array of 2 doubles marking the end of the line segment.
+
+* Returned Value:
+* Pointer to the memory structure containing the description of the
+* line. This structure should be freed using astFree when no longer
+* needed. A NULL pointer is returned (without error) if any of the
+* supplied axis values are AST__BAD.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ AstLineDef *result; /* Pointer to output structure */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Check the Frame has 2 axes. */
+ if( astGetNaxes( this ) != 2 ) {
+ astError( AST__INTER, "astLineDef(%s): The supplied %s is not 2 "
+ "dimensional (internal AST proramming error).", status,
+ astGetClass( this ), astGetClass( this ) );
+ }
+
+/* Check the axis values are good */
+ if( start[ 0 ] != AST__BAD && start[ 1 ] != AST__BAD &&
+ end[ 0 ] != AST__BAD && end[ 1 ] != AST__BAD ) {
+
+/* Allocate memory for the returned structure. */
+ result = astMalloc( sizeof( AstLineDef ) );
+ if( result ) {
+
+/* Store the supplied axis values in the returned structure. */
+ result->start[ 0 ] = start[ 0 ];
+ result->start[ 1 ] = start[ 1 ];
+ result->end[ 0 ] = end[ 0 ];
+ result->end[ 1 ] = end[ 1 ];
+
+/* Store the length of the line segment. */
+ result->length = astDistance( this, start, end );
+
+/* Store a unit vector pointing from the start to the end. */
+ if( result->length > 0.0 ) {
+ result->dir[ 0 ] = ( end[ 0 ] - start[ 0 ] )/result->length;
+ result->dir[ 1 ] = ( end[ 1 ] - start[ 1 ] )/result->length;
+ } else {
+ result->dir[ 0 ] = 1.0;
+ result->dir[ 1 ] = 0.0;
+ }
+
+/* Store a unit vector perpendicular to the line, such that the vector
+ points to the left, as vewied from the observer, when moving from the
+ start to the end of the line. */
+ result->q[ 0 ] = -result->dir[ 1 ];
+ result->q[ 1 ] = result->dir[ 0 ];
+
+/* Store a pointer to the defining Frame. */
+ result->frame = this;
+
+/* Indicate that the line is considered to be terminated at the start and
+ end points. */
+ result->infinite = 0;
+ }
+ }
+
+/* Free the returned pointer if an error occurred. */
+ if( !astOK ) result = astFree( result );
+
+/* Return a pointer to the output structure. */
+ return result;
+}
+
+static void LineOffset( AstFrame *this, AstLineDef *line, double par,
+ double prp, double point[2], int *status ){
+/*
+*+
+* Name:
+* astLineOffset
+
+* Purpose:
+* Find a position close to a line.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void LineOffset( AstFrame *this, AstLineDef *line, double par,
+* double prp, double point[2] )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns a position formed by moving a given distance along
+* the supplied line, and then a given distance away from the supplied line.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* line
+* Pointer to the structure defining the line.
+* par
+* The distance to move along the line from the start towards the end.
+* prp
+* The distance to move at right angles to the line. Positive
+* values result in movement to the left of the line, as seen from
+* the observer, when moving from start towards the end.
+
+* Notes:
+* - The pointer supplied for "line" should have been created using the
+* astLineDef method. This structure contains cached information about the
+* line which improves the efficiency of this method when many repeated
+* calls are made. An error will be reported if the structure does not
+* refer to the Frame specified by "this".
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Check that the line refers to the supplied Frame. */
+ if( line->frame != this ) {
+ astError( AST__INTER, "astLineOffset(%s): The supplied line does "
+ "not relate to the supplied %s (AST internal programming "
+ "error).", status, astGetClass( this ), astGetClass( this ) );
+
+/* This implementation uses simple flat geometry. */
+ } else {
+ point[ 0 ] = line->start[ 0 ] + par*line->dir[ 0 ] + prp*line->q[ 0 ];
+ point[ 1 ] = line->start[ 1 ] + par*line->dir[ 1 ] + prp*line->q[ 1 ];
+ }
+}
+
+#if defined(THREAD_SAFE)
+static int ManageLock( AstObject *this_object, int mode, int extra,
+ AstObject **fail, int *status ) {
+/*
+* Name:
+* ManageLock
+
+* Purpose:
+* Manage the thread lock on an Object.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "object.h"
+* AstObject *ManageLock( AstObject *this, int mode, int extra,
+* AstObject **fail, int *status )
+
+* Class Membership:
+* CmpMap member function (over-rides the astManageLock protected
+* method inherited from the parent class).
+
+* Description:
+* This function manages the thread lock on the supplied Object. The
+* lock can be locked, unlocked or checked by this function as
+* deteremined by parameter "mode". See astLock for details of the way
+* these locks are used.
+
+* Parameters:
+* this
+* Pointer to the Object.
+* mode
+* An integer flag indicating what the function should do:
+*
+* AST__LOCK: Lock the Object for exclusive use by the calling
+* thread. The "extra" value indicates what should be done if the
+* Object is already locked (wait or report an error - see astLock).
+*
+* AST__UNLOCK: Unlock the Object for use by other threads.
+*
+* AST__CHECKLOCK: Check that the object is locked for use by the
+* calling thread (report an error if not).
+* extra
+* Extra mode-specific information.
+* fail
+* If a non-zero function value is returned, a pointer to the
+* Object that caused the failure is returned at "*fail". This may
+* be "this" or it may be an Object contained within "this". Note,
+* the Object's reference count is not incremented, and so the
+* returned pointer should not be annulled. A NULL pointer is
+* returned if this function returns a value of zero.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A local status value:
+* 0 - Success
+* 1 - Could not lock or unlock the object because it was already
+* locked by another thread.
+* 2 - Failed to lock a POSIX mutex
+* 3 - Failed to unlock a POSIX mutex
+* 4 - Bad "mode" value supplied.
+
+* Notes:
+* - This function attempts to execute even if an error has already
+* occurred.
+*/
+
+/* Local Variables: */
+ AstFrame *this; /* Pointer to Frame structure */
+ int i; /* Loop count */
+ int result; /* Returned status value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the supplied pointer is not NULL. */
+ if( !this_object ) return result;
+
+/* Obtain a pointers to the Frame structure. */
+ this = (AstFrame *) this_object;
+
+/* Invoke the ManageLock method inherited from the parent class. */
+ if( !result ) result = (*parent_managelock)( this_object, mode, extra,
+ fail, status );
+
+/* Invoke the astManageLock method on any Objects contained within
+ the supplied Object. */
+ for( i = 0; i < this->naxes; i++ ) {
+ if( !result ) result = astManageLock( this->axis[ i ], mode, extra,
+ fail );
+ }
+ if( this->variants && !result ) result = astManageLock( this->variants, mode,
+ extra, fail );
+
+ return result;
+
+}
+#endif
+
+static int *MapSplit( AstMapping *this_map, int nin, const int *in, AstMapping **map, int *status ){
+/*
+* Name:
+* MapSplit
+
+* Purpose:
+* Create a Mapping representing a subset of the inputs of an existing
+* Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int *MapSplit( AstMapping *this, int nin, const int *in, AstMapping **map, int *status )
+
+* Class Membership:
+* Frame method (over-rides the protected astMapSplit method
+* inherited from the Mapping class).
+
+* Description:
+* This function creates a new Mapping by picking specified inputs from
+* an existing Frame. This is only possible if the specified inputs
+* correspond to some subset of the Frame outputs. That is, there
+* must exist a subset of the Frame outputs for which each output
+* depends only on the selected Frame inputs, and not on any of the
+* inputs which have not been selected. If this condition is not met
+* by the supplied Frame, then a NULL Mapping is returned.
+
+* Parameters:
+* this
+* Pointer to the Frame to be split (the Frame is not actually
+* modified by this function).
+* nin
+* The number of inputs to pick from "this".
+* in
+* Pointer to an array of indices (zero based) for the inputs which
+* are to be picked. This array should have "nin" elements. If "Nin"
+* is the number of inputs of the supplied Frame, then each element
+* should have a value in the range zero to Nin-1.
+* map
+* Address of a location at which to return a pointer to the new
+* Mapping. This Mapping will have "nin" inputs (the number of
+* outputs may be different to "nin"). A NULL pointer will be
+* returned if the supplied Frame has no subset of outputs which
+* depend only on the selected inputs.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to a dynamically allocated array of ints. The number of
+* elements in this array will equal the number of outputs for the
+* returned Mapping. Each element will hold the index of the
+* corresponding output in the supplied Frame. The array should be
+* freed using astFree when no longer needed. A NULL pointer will
+* be returned if no output Mapping can be created.
+
+* Notes:
+* - If this function is invoked with the global error status set,
+* or if it should fail for any reason, then NULL values will be
+* returned as the function value and for the "map" pointer.
+*/
+
+/* Local Variables: */
+ int *result; /* Returned pointer */
+
+/* Initialise */
+ result = NULL;
+ *map = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Pick the selected axes from the Frame. */
+ *map = (AstMapping *) astPickAxes( (AstFrame *) this_map, nin, in, NULL );
+
+/* Return a copy of the supplied axis array.*/
+ result = astStore( NULL, in, sizeof( int )*(size_t) nin );
+
+/* Free returned resources if an error has occurred. */
+ if( !astOK ) {
+ result = astFree( result );
+ *map = astAnnul( *map );
+ }
+
+/* Return the list of output indices. */
+ return result;
+}
+
+static int Match( AstFrame *template, AstFrame *target, int matchsub,
+ int **template_axes, int **target_axes,
+ AstMapping **map, AstFrame **result, int *status ) {
+/*
+*+
+* Name:
+* astMatch
+
+* Purpose:
+* Determine if conversion is possible between two coordinate systems.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astMatch( AstFrame *template, AstFrame *target, int matchsub,
+* int **template_axes, int **target_axes,
+* AstMapping **map, AstFrame **result )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function matches a "template" frame to a "target" frame and
+* determines whether it is possible to convert coordinates between
+* them. If it is, a mapping that performs the transformation is
+* returned along with a new Frame that describes the coordinate
+* system that results when this mapping is applied to the "target"
+* coordinate system. In addition, information is returned to allow
+* the axes in this "result" Frame to be associated with the
+* corresponding axes in the "target" and "template" Frames from
+* which they are derived.
+
+* Parameters:
+* template
+* Pointer to the template Frame. This describes the coordinate
+* system (or set of possible coordinate systems) into which we
+* wish to convert our coordinates.
+* target
+* Pointer to the target Frame. This describes the coordinate
+* system in which we already have coordinates.
+* matchsub
+* If zero then a match only occurs if the template is of the same
+* class as the target, or of a more specialised class. If non-zero
+* then a match can occur even if this is not the case (i.e. if the
+* target is of a more specialised class than the template). In
+* this latter case, the target is cast down to the class of the
+* template. NOTE, this argument is handled by the global method
+* wrapper function "astMatch_", rather than by the class-specific
+* implementations of this method.
+* template_axes
+* Address of a location where a pointer to int will be returned
+* if the requested coordinate conversion is possible. This
+* pointer will point at a dynamically allocated array of
+* integers with one element for each axis of the "result" Frame
+* (see below). It must be freed by the caller (using astFree)
+* when no longer required.
+*
+* For each axis in the result Frame, the corresponding element
+* of this array will return the (zero-based) index of the
+* template Frame axis from which it is derived. If it is not
+* derived from any template frame axis, a value of -1 will be
+* returned instead.
+* target_axes
+* Address of a location where a pointer to int will be returned
+* if the requested coordinate conversion is possible. This
+* pointer will point at a dynamically allocated array of
+* integers with one element for each axis of the "result" Frame
+* (see below). It must be freed by the caller (using astFree)
+* when no longer required.
+*
+* For each axis in the result Frame, the corresponding element
+* of this array will return the (zero-based) index of the
+* target Frame axis from which it is derived. If it is not
+* derived from any target Frame axis, a value of -1 will be
+* returned instead.
+* map
+* Address of a location where a pointer to a new Mapping will
+* be returned if the requested coordinate conversion is
+* possible. If returned, the forward transformation of this
+* Mapping may be used to convert coordinates between the
+* "target" Frame and the "result" Frame (see below) and the
+* inverse transformation will convert in the opposite
+* direction.
+* result
+* Address of a location where a pointer to a new Frame will be
+* returned if the requested coordinate conversion is
+* possible. If returned, this Frame describes the coordinate
+* system that results from applying the returned Mapping
+* (above) to the "target" coordinate system. In general, this
+* Frame will combine attributes from (and will therefore be
+* more specific than) both the target and the template
+* Frames. In particular, when the template allows the
+* possibility of transformaing to any one of a set of
+* alternative coordinate systems, the "result" Frame will
+* indicate which of the alternatives was used.
+
+* Returned Value:
+* A non-zero value is returned if the requested coordinate
+* conversion is possible. Otherwise zero is returned (this will
+* not in itself result in an error condition).
+
+* Notes:
+* - By default, the "result" frame will have its number of axes
+* and axis order determined by the "template" Frame. However, if
+* the PreserveAxes attribute of the template frame is non-zero,
+* then the axis count and axis order of the "target" frame will be
+* used instead.
+* - The template_axes and target_axes arrays are provided so that
+* if the caller needs to permute the target and/or template axes
+* before invoking this function, it is possible to deduce how the
+* result axes should be permuted so as to correspond with the
+* original template/target axis order.
+* - For result axes that do not correspond with a template and/or
+* target axis (where a value of -1 is returned in the
+* template_axes and/or target_axes arrays), the caller has no
+* clear way of knowing where these axes should appear in any
+* permuted order. In this case, the relative position of these
+* axes within the result Frame (with respect to axes that do have
+* template/target axis associations) will be used to convey this
+* information. Such axes should be taken to be associated either
+* with the next preceding or following axis (depending on the
+* AST__MATCHEND flag of the template frame) which does have an
+* association.
+* - If the result Frame has zero axes, then NULL pointer values
+* will be returned for *template_axes and *target_axes.
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+
+* Implementation Notes:
+* This implementation addresses the matching of a Frame class
+* object to other types of Frames (i.e. the target may be from a
+* derived class). A Frame will match any other type of Frame with
+* an acceptable number of axes but will not distinguish axis order
+* (i.e. it will match the axes in whatever order they are
+* given). If the template Frame has a value set for its Domain
+* attribute, then it will only match another Frame with the same
+* Domain.
+*/
+
+/* Local Variables: */
+ char *template_domain; /* Pointer to copy of template domain */
+ const char *ptr; /* Pointer to domain string */
+ const char *target_domain; /* Pointer to target domain string */
+ int match; /* Template matches target? */
+ int match_end; /* Match final axes of target? */
+ int max_axes; /* Maximum acceptable number of axes */
+ int min_axes; /* Minimum acceptable nu,ber of axes */
+ int preserve_axes; /* Preserve target axes? */
+ int result_axis; /* Loop counter for result axes */
+ int result_naxes; /* Number of result axes */
+ int target_naxes; /* Number of target axes */
+ int template_naxes; /* Number of template axes */
+
+/* Initialise the returned values. */
+ *template_axes = NULL;
+ *target_axes = NULL;
+ *map = NULL;
+ *result = NULL;
+ match = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return match;
+
+/* The first requirement for a match is that the target object is a Frame. This
+ is already known to be true, as it forms part of the argument validation
+ for this function. */
+
+/* The second requirement is that the number of target axes is acceptable.
+ Obtain the number of target axes and the minimum and maximum number of axes
+ that the template will match. */
+ target_naxes = astGetNaxes( target );
+ min_axes = astGetMinAxes( template );
+ max_axes = astGetMaxAxes( template );
+
+/* Test if the number of target axes is acceptable. */
+ if ( astOK ) {
+ match = ( ( target_naxes >= min_axes ) && ( target_naxes <= max_axes ) );
+ }
+
+/* The third requirement is that if the template has its Domain
+ attribute defined, then the target must also have the same Domain
+ (although it need not be set - the default will do). First check if
+ the template has a domain. */
+ if ( astOK && match ) {
+ if ( astTestDomain( template ) ) {
+
+/* Obtain a pointer to the template domain. Then allocate memory and
+ make a copy of it (this is necessary as we will next inquire the
+ domain of the target and may over-write the buffer holding the
+ template's domain). */
+ ptr = astGetDomain( template );
+ if ( astOK ) {
+ template_domain = astStore( NULL, ptr,
+ strlen( ptr ) + (size_t) 1 );
+
+/* Obtain a pointer to the target domain. */
+ target_domain = astGetDomain( target );
+
+/* Compare the domain strings for equality. Then free the memory
+ allocated above. */
+ match = astOK && !strcmp( template_domain, target_domain );
+ template_domain = astFree( template_domain );
+ }
+ }
+ }
+
+/* If the template matches, obtain the values of the template's PreserveAxes
+ and MatchEnd attributes and determine the number of template axes. */
+ if ( astOK && match ) {
+ preserve_axes = astGetPreserveAxes( template );
+ match_end = astGetMatchEnd( template );
+ template_naxes = astGetNaxes( template );
+
+/* If the PreserveAxes attribute is non-zero, the target axes should be
+ preserved, so the number of result axes equals the number of target axes.
+ Otherwise the number of template axes is used. */
+ result_naxes = preserve_axes ? target_naxes : template_naxes;
+
+/* Allocate memory for the arrays of axis associations to be returned. */
+ *template_axes = astMalloc( sizeof( int ) * (size_t) result_naxes );
+ *target_axes = astMalloc( sizeof( int ) * (size_t) result_naxes );
+ if ( astOK ) {
+
+/* Loop through each of the result axes. */
+ for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) {
+
+/* Set up the axis associations. By default, associate the first result axis
+ with the first template/target axis. */
+ (*template_axes)[ result_axis ] = result_axis;
+ (*target_axes)[ result_axis ] = result_axis;
+
+/* However, if the MatchEnd attribute is non-zero, associate the last result
+ axis with the last template/target axis (this only makes a difference if
+ there is a difference in the number of axes). */
+ if ( match_end ) {
+ (*template_axes)[ result_axis ] +=
+ template_naxes - result_naxes;
+ (*target_axes)[ result_axis ] += target_naxes - result_naxes;
+ }
+
+/* If any of the associations would be with a template/target axis that doesn't
+ exist, then use an axis index of -1 for the association instead. */
+ if ( ( (*template_axes)[ result_axis ] < 0 ) ||
+ ( (*template_axes)[ result_axis ] >= template_naxes ) ) {
+ (*template_axes)[ result_axis ] = -1;
+ }
+ if ( ( (*target_axes)[ result_axis ] < 0 ) ||
+ ( (*target_axes)[ result_axis ] >= target_naxes ) ) {
+ (*target_axes)[ result_axis ] = -1;
+ }
+ }
+
+/* Use the target's astSubFrame method to select the required axes from it,
+ overlaying the template's attributes on to the resulting Frame. This process
+ also generates the required Mapping between the target and result Frames. */
+ match = astSubFrame( target, template,
+ result_naxes, *target_axes, *template_axes,
+ map, result );
+ }
+ }
+
+/* If an error occurred, free any allocated memory and reset the result. */
+ if ( !astOK || !match ) {
+ *template_axes = astFree( *template_axes );
+ *target_axes = astFree( *target_axes );
+ match = 0;
+ }
+
+/* Return the result. */
+ return match;
+}
+
+static void MatchAxes( AstFrame *frm1, AstFrame *frm2, int *axes,
+ int *status ) {
+/*
+*++
+* Name:
+c astMatchAxes
+f AST_MATCHAXES
+
+* Purpose:
+* Find any corresponding axes in two Frames.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c void astMatchAxes( AstFrame *frm1, AstFrame *frm2, int *axes )
+f CALL AST_MATCHAXES( FRM1, FRM2, AXES, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function looks for corresponding axes within two supplied
+* Frames. An array of integers is returned that contains an element
+* for each axis in the second supplied Frame. An element in this array
+* will be set to zero if the associated axis within the second Frame
+* has no corresponding axis within the first Frame. Otherwise, it
+* will be set to the index (a non-zero positive integer) of the
+* corresponding axis within the first supplied Frame.
+
+* Parameters:
+c frm1
+f FRM1 = INTEGER (Given)
+* Pointer to the first Frame.
+c frm2
+f FRM2 = INTEGER (Given)
+* Pointer to the second Frame.
+c axes
+f AXES = INTEGER( * ) (Returned)
+c Pointer to an
+f An
+* integer array in which to return the indices of the axes (within
+* the first Frame) that correspond to each axis within the second
+* Frame. Axis indices start at 1. A value of zero will be stored
+* in the returned array for each axis in the second Frame that has
+* no corresponding axis in the first Frame.
+*
+* The number of elements in this array must be greater than or
+* equal to the number of axes in the second Frame.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Applicability:
+* Frame
+* This function applies to all Frames.
+
+* Notes:
+* - Corresponding axes are identified by the fact that a Mapping can
+* be found between them using
+c astFindFrame or astConvert.
+f AST_FINDFRAME or AST_CONVERT.
+* Thus, "corresponding axes" are not necessarily identical. For
+* instance, SkyFrame axes in two Frames will match even if they
+* describe different celestial coordinate systems
+*--
+
+* Implementation Notes:
+* This function is simply a wrap-up for the protected astMatchAxesX
+* method which performs the required processing but swaps the order
+* of the first two arguments. This is a trick to allow the
+* astMatchAxes method to be over-ridden by derived classes on the
+* basis of the class of either of the first two arguments.
+*
+* In practice, each class that represents an encapsulated Frame (e.g.
+* FrameSet, Region, etc) should over-ride this method, extracting a
+* Frame from the supplied "frm1" pointer, and then invoking
+* astMatchAxesX.
+
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Invoke the "astMatchAxesX" method with the first two arguments
+ swapped. */
+ astMatchAxesX( frm2, frm1, axes );
+}
+
+static void MatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes,
+ int *status ) {
+/*
+*+
+* Name:
+* astMatchAxesX
+
+* Purpose:
+* Find any corresponding axes in two Frames.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astMatchAxesX( AstFrame *frm2, AstFrame *frm1, int *axes )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function performs the processing for the public astMatchAxes
+* method and has exactly the same interface except that the order
+* of the first two arguments is swapped. This is a trick to allow
+* the astMatchAxes method to be over-ridden by derived classes on
+* the basis of the class of either of its first two arguments.
+*
+* See the astMatchAxes method for details of the interface.
+*-
+*/
+
+/* Local Variables: */
+ AstFrame *pfrm;
+ AstFrame *resfrm;
+ AstMapping *resmap;
+ int *frm1_axes;
+ int *pfrm_axes;
+ int ifirst;
+ int max_axes;
+ int min_axes;
+ int nax2;
+ int pax;
+ int preserve_axes;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Temporarily ensure that the PreserveAxes attribute is non-zero in
+ the second supplied Frame. This means thte result Frame returned by
+ astMatch below will have the axis count and order of the target Frame
+ (i.e. "pfrm"). */
+ if( astTestPreserveAxes( frm1 ) ) {
+ preserve_axes = astGetPreserveAxes( frm1 ) ? 1 : 0;
+ } else {
+ preserve_axes = -1;
+ }
+ astSetPreserveAxes( frm1, 1 );
+
+/* Temporarily ensure that the MaxAxes and MinAxes attributes in the
+ second supplied Frame are set so the Frame can be used as a template
+ in astMatch for matching any number of axes. */
+ if( astTestMaxAxes( frm1 ) ) {
+ max_axes = astGetMaxAxes( frm1 );
+ } else {
+ max_axes = -1;
+ }
+ astSetMaxAxes( frm1, 10000 );
+
+ if( astTestMinAxes( frm1 ) ) {
+ min_axes = astGetMinAxes( frm1 );
+ } else {
+ min_axes = -1;
+ }
+ astSetMinAxes( frm1, 1 );
+
+/* Get the number of axes in the frm2 Frame. */
+ nax2 = astGetNaxes( frm2 );
+
+/* Loop round the axes in the frm2 Frame. */
+ for( ifirst = 0; ifirst < nax2; ifirst++ ) {
+
+/* Identify the primary Frame defining the current axis in the frm2
+ Frame. */
+ astPrimaryFrame( frm2, ifirst, &pfrm, &pax );
+
+/* Attempt to find a sub-frame within the frm1 Frame that corresponds to
+ this primary Frame. */
+ if( astMatch( frm1, pfrm, 1, &frm1_axes, &pfrm_axes, &resmap, &resfrm ) ) {
+
+/* Store the one-based index within "frm1" of the corresponding axis. */
+ axes[ ifirst ] = frm1_axes[ pax ] + 1;
+
+/* Free resources */
+ frm1_axes = astFree( frm1_axes );
+ pfrm_axes = astFree( pfrm_axes );
+ resmap = astAnnul( resmap );
+ resfrm = astAnnul( resfrm );
+
+/* If no corresponding axis was found store zero in the returned array. */
+ } else {
+ axes[ ifirst ] = 0;
+ }
+
+/* Free resouces. */
+ pfrm = astAnnul( pfrm );
+ }
+
+/* Re-instate the original attribute values in the frm1 Frame. */
+ if( preserve_axes == -1 ) {
+ astClearPreserveAxes( frm1 );
+ } else {
+ astSetPreserveAxes( frm1, preserve_axes );
+ }
+
+ if( max_axes == -1 ) {
+ astClearMaxAxes( frm1 );
+ } else {
+ astSetMaxAxes( frm1, max_axes );
+ }
+
+ if( min_axes == -1 ) {
+ astClearMinAxes( frm1 );
+ } else {
+ astSetMinAxes( frm1, min_axes );
+ }
+}
+
+static void NewUnit( AstAxis *ax, const char *old_units, const char *new_units,
+ const char *method, const char *class, int *status ) {
+/*
+* Name:
+* NewUnit
+
+* Purpose:
+* Modify an Axis Label and Symbol to reflect a new Unit value.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* void NewUnit( AstAxis *ax, const char *old_units, const char *new_units,
+* const char *method, const char *class )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function modifies the Label and Symbol attributes of an Axis
+* to reflect a new Unit value. This function should only be called if
+* the ActiveUnit flag of the parent Frame is non-zero (this is not
+* checked within this function).
+*
+* If the axis has a set label, then we may be able to modify it to
+* correctly describe the axis in the supplied new units. For instance,
+* if the original units were "Hz", the original label was "frequency",
+* and the new units are "log(Hz)", then the label is modified to become
+* "log( frequency )".
+*
+* The Axis Format attribute is cleared if the supplied units are
+* different to the old units (because any set format is probably not
+* going to be appropriate for a new system of units.
+
+* Parameters:
+* ax
+* Pointer to the Axis.
+* old_units
+* The original units value.
+* new_units
+* The new units value.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate an axis selection. This method name is used
+* solely for constructing error messages.
+* class
+* Pointer to a constant null-terminated character string
+* containing the name of the class upon which this function
+* was invoked. This is used solely for constructing error messages.
+
+* Returned Value:
+* void.
+*/
+
+/* Local Variables: */
+ AstMapping *map; /* Pointer to units Mapping */
+ char *new_lab; /* Pointer to new axis label */
+ char *new_sym; /* Pointer to new axis symbol */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Check that the axis label is set. We relay on sub-classes to return
+ appropriate default labels if the label is not set. */
+ if( astTestAxisLabel( ax ) ) {
+
+/* See if it is possible to map the old units into the new units.
+ If it is, then a Mapping is returned together with an appropriately
+ modified label. */
+ map = astUnitMapper( old_units, new_units, astGetAxisLabel( ax ),
+ &new_lab );
+
+/* If succesfull, annul the Mapping (which we do not need), and store the
+ modified label in the Axis, finally freeing the memory used to hold
+ the modified label. */
+ if( map ) {
+ map = astAnnul( map );
+ if( new_lab ) {
+ astSetAxisLabel( ax, new_lab );
+ new_lab = astFree( new_lab );
+ }
+ }
+ }
+
+/* Do the same for the axis symbol. */
+ if( astTestAxisSymbol( ax ) ) {
+ map = astUnitMapper( old_units, new_units, astGetAxisSymbol( ax ),
+ &new_sym );
+ if( map ) {
+ map = astAnnul( map );
+ if( new_sym ) {
+ astSetAxisSymbol( ax, new_sym );
+ new_sym = astFree( new_sym );
+ }
+ }
+ }
+
+/* If succesful, clear the axis format if the new and old units are
+ different. */
+ if( astOK ) {
+ if( strcmp( old_units, new_units ) ) astClearAxisFormat( ax );
+ }
+
+}
+
+static void Norm( AstFrame *this, double value[], int *status ) {
+/*
+*++
+* Name:
+c astNorm
+f AST_NORM
+
+* Purpose:
+* Normalise a set of Frame coordinates.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c void astNorm( AstFrame *this, double value[] )
+f CALL AST_NORM( THIS, VALUE, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function normalises a set of Frame coordinate values which
+f This routine normalises a set of Frame coordinate values which
+* might be unsuitable for display (e.g. may lie outside the
+* expected range) into a set of acceptable values suitable for
+* display.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c value
+f VALUE( * ) = DOUBLE PRECISION (Given and Returned)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). Initially, this should contain a set of
+* coordinate values representing a point in the space which the
+* Frame describes. If these values lie outside the expected
+* range for the Frame, they will be replaced with more
+* acceptable (normalised) values. Otherwise, they will be
+* returned unchanged.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - For some classes of Frame, whose coordinate values are not
+* constrained, this function will never modify the values
+* supplied. However, for Frames whose axes represent cyclic
+* quantities (such as angles or positions on the sky), coordinates
+* will typically be wrapped into an appropriate standard range,
+* such as zero to 2*pi.
+* - The NormMap class is a Mapping which can be used to normalise a
+* set of points using the
+c astNorm function
+f AST_NORM routine
+* of a specified Frame.
+* - It is intended to be possible to put any set of coordinates
+* into a form suitable for display by using this function to
+* normalise them, followed by appropriate formatting
+c (using astFormat).
+f (using AST_FORMAT).
+*--
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ int axis; /* Loop counter for axes */
+ int naxes; /* Number of Frame axes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain the number of Frame axes. */
+ naxes = astGetNaxes( this );
+
+/* Loop to process the coordinate for each axis in turn. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+
+/* Obtain a pointer to the relevant Frame Axis. */
+ ax = astGetAxis( this, axis );
+
+/* Normalise the coordinate for this axis. */
+ astAxisNorm( ax, value + axis );
+
+/* Annul the pointer to the Axis. */
+ ax = astAnnul( ax );
+
+/* Quit looping if an error occurs. */
+ if ( !astOK ) break;
+ }
+}
+
+static void NormBox( AstFrame *this, double lbnd[], double ubnd[],
+ AstMapping *reg, int *status ) {
+/*
+*+
+* Name:
+* astNormBox
+
+* Purpose:
+* Extend a box to include effect of any singularities in the Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astNormBox( AstFrame *this, double lbnd[], double ubnd[],
+* AstMapping *reg )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function modifies a supplied box to include the effect of any
+* singularities in the co-ordinate system represented by the Frame.
+* For a normal Cartesian coordinate system, the box will be returned
+* unchanged. Other classes of Frame may do other things. For instance,
+* a SkyFrame will check to see if the box contains either the north
+* or south pole and extend the box appropriately.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* lbnd
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). Initially, this should contain a set of
+* lower axis bounds for the box. They will be modified on exit
+* to include the effect of any singularities within the box.
+* ubnd
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). Initially, this should contain a set of
+* upper axis bounds for the box. They will be modified on exit
+* to include the effect of any singularities within the box.
+* reg
+* A Mapping which should be used to test if any singular points are
+* inside or outside the box. The Mapping should leave an input
+* position unchanged if the point is inside the box, and should
+* set all bad if the point is outside the box.
+*-
+*/
+
+/* This base class returns the box limits unchanged. */
+}
+
+static double Offset2( AstFrame *this, const double point1[2], double angle,
+ double offset, double point2[2], int *status ){
+/*
+*++
+* Name:
+c astOffset2
+f AST_OFFSET2
+
+* Purpose:
+* Calculate an offset along a geodesic curve in a 2D Frame.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c double astOffset2( AstFrame *this, const double point1[2], double angle,
+c double offset, double point2[2] );
+f RESULT = AST_OFFSET2( THIS, POINT1, ANGLE, OFFSET, POINT2, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function finds the Frame coordinate values of a point which
+f This routine finds the Frame coordinate values of a point which
+* is offset a specified distance along the geodesic curve at a
+* given angle from a specified starting point. It can only be
+* used with 2-dimensional Frames.
+*
+* For example, in a basic Frame, this offset will be along the
+* straight line joining two points. For a more specialised Frame
+* describing a sky coordinate system, however, it would be along
+* the great circle passing through two sky positions.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c point1
+f POINT1( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This should contain the coordinates of the
+* point marking the start of the geodesic curve.
+c angle
+f ANGLE = DOUBLE PRECISION (Given)
+* The angle (in radians) from the positive direction of the second
+* axis, to the direction of the required position, as seen from
+* the starting position. Positive rotation is in the sense of
+* rotation from the positive direction of axis 2 to the positive
+* direction of axis 1.
+c offset
+f OFFSET = DOUBLE PRECISION
+* The required offset from the first point along the geodesic
+* curve. If this is positive, it will be in the direction of the
+* given angle. If it is negative, it will be in the opposite
+* direction.
+c point2
+f POINT2( * ) = DOUBLE PRECISION (Returned)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* in which the coordinates of the required point will be returned.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astOffset2
+f AST_OFFSET2 = DOUBLE PRECISION
+* The direction of the geodesic curve at the end point. That is, the
+* angle (in radians) between the positive direction of the second
+* axis and the continuation of the geodesic curve at the requested
+* end point. Positive rotation is in the sense of rotation from
+* the positive direction of axis 2 to the positive direction of axis
+* 1.
+
+* Notes:
+c - The geodesic curve used by this function is the path of
+f - The geodesic curve used by this routine is the path of
+* shortest distance between two points, as defined by the
+c astDistance function.
+f AST_DISTANCE function.
+* - An error will be reported if the Frame is not 2-dimensional.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value.
+*--
+*/
+
+/* Local Variables: */
+ int naxes; /* Number of Frame axes */
+ double result; /* Returned value */
+
+/* Check the global error status. */
+ result = AST__BAD;
+ if ( !astOK ) return result;
+
+/* Initialize bad values. */
+ point2[ 0 ] = AST__BAD;
+ point2[ 1 ] = AST__BAD;
+
+/* Determine the number of Frame axes. */
+ naxes = astGetNaxes( this );
+
+/* Report an error if the Frame is not 2 dimensional. */
+ if( naxes != 2 && astOK ) {
+ astError( AST__NAXIN, "astOffset2(%s): Invalid number of Frame axes (%d)."
+ " astOffset2 can only be used with 2 dimensonal Frames.", status,
+ astGetClass( this ), naxes );
+ }
+
+/* Check the supplied values. */
+ if ( astOK && point1[ 0 ] != AST__BAD && point1[ 1 ] != AST__BAD &&
+ angle != AST__BAD && offset != AST__BAD ) {
+
+/* Store the results. */
+ point2[ 0 ] = point1[ 0 ] + sin( angle )*offset;
+ point2[ 1 ] = point1[ 1 ] + cos( angle )*offset;
+
+/* The position angle of the curve does not vary in cartesian coordinates */
+ result = angle;
+
+ }
+
+/* Return the result. */
+ return result;
+
+}
+
+static void Offset( AstFrame *this, const double point1[],
+ const double point2[], double offset, double point3[], int *status ) {
+/*
+*++
+* Name:
+c astOffset
+f AST_OFFSET
+
+* Purpose:
+* Calculate an offset along a geodesic curve.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c void astOffset( AstFrame *this,
+c const double point1[], const double point2[],
+c double offset, double point3[] )
+f CALL AST_OFFSET( THIS, POINT1, POINT2, OFFSET, POINT3, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function finds the Frame coordinate values of a point which
+f This routine finds the Frame coordinate values of a point which
+* is offset a specified distance along the geodesic curve between
+* two other points.
+*
+* For example, in a basic Frame, this offset will be along the
+* straight line joining two points. For a more specialised Frame
+* describing a sky coordinate system, however, it would be along
+* the great circle passing through two sky positions.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c point1
+f POINT1( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This should contain the coordinates of the
+* point marking the start of the geodesic curve.
+c point2
+f POINT2( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis.
+* This should contain the coordinates of the point marking the
+* end of the geodesic curve.
+c offset
+f OFFSET = DOUBLE PRECISION
+* The required offset from the first point along the geodesic
+* curve. If this is positive, it will be towards the second
+* point. If it is negative, it will be in the opposite
+* direction. This offset need not imply a position lying
+* between the two points given, as the curve will be
+* extrapolated if necessary.
+c point3
+f POINT3( * ) = DOUBLE PRECISION (Returned)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* in which the coordinates of the required point will be returned.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+c - The geodesic curve used by this function is the path of
+f - The geodesic curve used by this routine is the path of
+* shortest distance between two points, as defined by the
+c astDistance function.
+f AST_DISTANCE function.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value.
+* - "Bad" coordinate values will also be returned if the two
+* points supplied are coincident (or otherwise fail to uniquely
+* specify a geodesic curve) but the requested offset is non-zero.
+*--
+*/
+
+/* Local Variables: */
+ double delta; /* Displacement along axis */
+ double dist; /* Distance between points */
+ double fract; /* Fraction of distance required */
+ int axis; /* Loop counter for axes */
+ int naxes; /* Number of Frame axes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Determine the number of Frame axes. */
+ naxes = astGetNaxes( this );
+ if ( astOK ) {
+
+/* Loop to determine the Cartesian distance between points 1 and 2. */
+ dist = 0.0;
+ for ( axis = 0; axis < naxes; axis++ ) {
+
+/* If any of the coordinates supplied is bad, set the distance to be
+ bad and quit looping. */
+ if ( ( point1[ axis ] == AST__BAD ) ||
+ ( point2[ axis ] == AST__BAD ) ) {
+ dist = AST__BAD;
+ break;
+
+/* Otherwise, accumulate the sum of squared displacements along each
+ axis. */
+ } else {
+ delta = point1[ axis ] - point2[ axis ];
+ dist += ( delta * delta );
+ }
+ }
+
+/* Take the square root to find the distance (if valid). */
+ if ( dist != AST__BAD ) dist = sqrt( dist );
+
+/* If the distance between the points cannot be found, or the distance
+ is zero but the required offset is non-zero, then set the result
+ coordinates to be bad. */
+ if ( ( dist == AST__BAD ) ||
+ ( ( dist == 0.0 ) && ( offset != 0.0 ) ) ) {
+ for ( axis = 0; axis < naxes; axis++ ) {
+ point3[ axis ] = AST__BAD;
+ }
+
+/* Otherwise, calculate what fraction of the distance between the
+ points we need to move, and apply this fraction of the displacement
+ along each axis. */
+ } else {
+ fract = ( dist == 0.0 ) ? 0.0 : offset / dist;
+ for ( axis = 0; axis < naxes; axis++ ) {
+ point3[ axis ] = point1[ axis ] +
+ fract * ( point2[ axis ] - point1[ axis ] );
+ }
+ }
+ }
+}
+
+static void Overlay( AstFrame *template, const int *template_axes,
+ AstFrame *result, int *status ) {
+/*
+*+
+* Name:
+* astOverlay
+
+* Purpose:
+* Overlay the attributes of a template Frame on to another Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astOverlay( AstFrame *template, const int *template_axes,
+* AstFrame *result )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function overlays attributes of one Frame (the "template") on to
+* another Frame, so as to over-ride selected attributes of that second
+* Frame. Normally only those attributes which have been specifically set
+* in the template will be transferred. This implements a form of
+* defaulting, in which a Frame acquires attributes from the template, but
+* retains its original attributes (as the default) if new values have not
+* previously been explicitly set in the template.
+
+* Parameters:
+* template
+* Pointer to the template Frame, for which values should have been
+* explicitly set for any attribute which is to be transferred.
+* template_axes
+* Pointer to an array of int, with one element for each axis of the
+* "result" Frame (see below). For each axis in the result frame, the
+* corresponding element of this array should contain the (zero-based)
+* index of the template axis to which it corresponds. This array is used
+* to establish from which template axis any axis-dependent attributes
+* should be obtained.
+*
+* If any axis in the result Frame is not associated with a template
+* axis, the corresponding element of this array should be set to -1.
+*
+* If a NULL pointer is supplied, the template and result axis
+* indices are assumed to be identical.
+* result
+* Pointer to the Frame which is to receive the new attribute values.
+*-
+*/
+
+/* Local Variables: */
+ AstAxis *result_ax; /* Pointer to result Axis object */
+ AstAxis *template_ax; /* Pointer to template Axis object */
+ AstSystemType sys; /* System value */
+ int result_axis; /* Loop counter for result Frame axes */
+ int result_naxes; /* Number of result Frame axes */
+ int template_axis; /* Index of template Frame axis */
+ int template_naxes; /* Number of template Frame axes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Define a macro that tests whether an attribute is set in the template and,
+ if so, transfers its value to the target. */
+#define OVERLAY(attribute) \
+ if ( astTest##attribute( template ) ) { \
+ astSet##attribute( result, astGet##attribute( template ) ); \
+ }
+
+/* Use the macro to transfer each Frame attribute in turn. */
+ OVERLAY(Dtai);
+ OVERLAY(Dut1);
+ OVERLAY(Digits);
+ OVERLAY(Domain);
+ OVERLAY(Epoch);
+ OVERLAY(Title);
+ OVERLAY(ObsLat)
+ OVERLAY(ObsLon)
+ OVERLAY(ObsAlt)
+
+/* Transfer the ActiveUnit flag. */
+ astSetActiveUnit( result, astGetActiveUnit( template ) );
+
+/* Only overlay the System and AlignSystem attribute if the values are
+ valid for the result class. */
+ if( astTestSystem( template ) ) {
+ sys = astGetSystem( template );
+ if( astValidateSystem( result, sys, "astOverlay" ) ) {
+ astSetSystem( result, sys );
+ }
+ }
+
+ if( astTestAlignSystem( template ) ) {
+ sys = astGetAlignSystem( template );
+ if( astValidateSystem( result, sys, "astOverlay" ) ) {
+ astSetAlignSystem( result, sys );
+ }
+ }
+
+/* Now transfer attributes associated with individual axes. Obtain the number
+ of axes in the template and result Frames. */
+ template_naxes = astGetNaxes( template );
+ result_naxes = astGetNaxes( result );
+ if ( astOK ) {
+
+/* Loop through all the axes in the result Frame and determine to which
+ template axis each one corresponds. Check that the resulting axis index is
+ valid. If not, then the axis will not receive new attributes. */
+ for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) {
+ template_axis = template_axes ? template_axes[ result_axis ] : result_axis;
+ if ( ( template_axis >= 0 ) && ( template_axis < template_naxes ) ) {
+
+/* Obtain pointers to the relevant Axis objects of each Frame and use the
+ astAxisOverlay method of the template Axis to overlay attributes on to
+ the result Axis. Annul the Axis pointers afterwards. */
+ template_ax = astGetAxis( template, template_axis );
+ result_ax = astGetAxis( result, result_axis );
+ astAxisOverlay( template_ax, result_ax );
+ template_ax = astAnnul( template_ax );
+ result_ax = astAnnul( result_ax );
+
+/* Quit looping if an error occurs. */
+ if ( !astOK ) break;
+ }
+ }
+ }
+
+/* Undefine macros local to this function. */
+#undef OVERLAY
+}
+
+static void PermAxes( AstFrame *this, const int perm[], int *status ) {
+/*
+*+
+* Name:
+* astPermAxes
+
+* Purpose:
+* Permute the order of a Frame's axes.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astPermAxes( AstFrame *this, const int perm[] )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function permutes the order in which a Frame's axes occur.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* perm
+* An array of int (with one element for each axis of the Frame)
+* which lists the axes in their new order. Each element of this
+* array should be a (zero-based) axis index identifying the
+* axes according to their old (un-permuted) order.
+
+* Notes:
+* - Only genuine permutations of the axis order are permitted, so
+* each axis must be referenced exactly once in the "perm" array.
+* - If more than one axis permutation is applied to a Frame, the
+* effects are cumulative.
+*-
+
+* Implementation Notes:
+* - This function implements the basic astPermAxes method which is
+* available via the protected interface to the Frame class. A
+* public interface to this method is provided by the
+* astPermAxesId_ function.
+*/
+
+/* Local Variables: */
+ int *old; /* Pointer to copy of old permutation array */
+ int axis; /* Loop counter for Frame axes */
+ int naxes; /* Number of Frame axes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Validate the permutation array, to check that it describes a genuine
+ permutation. */
+ astCheckPerm( this, perm, "astPermAxes" );
+
+/* Obtain the number of Frame axes. */
+ naxes = astGetNaxes( this );
+
+/* Allocate memory and use it to store a copy of the old permutation array for
+ the Frame. */
+ old = astStore( NULL, this->perm, sizeof( int ) * (size_t) naxes );
+
+/* Apply the new axis permutation cumulatively to the old one and store the
+ result in the Frame. */
+ if ( astOK ) {
+ for ( axis = 0; axis < naxes; axis++ ) {
+ this->perm[ axis ] = old[ perm[ axis ] ];
+ }
+ }
+
+/* Free the temporary copy of the old array. */
+ old = astFree( old );
+}
+
+static AstFrame *PickAxes( AstFrame *this, int naxes, const int axes[],
+ AstMapping **map, int *status ) {
+/*
+*+
+* Name:
+* astPickAxes
+
+* Purpose:
+* Create a new Frame by picking axes from an existing one.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* AstFrame *PickAxes( AstFrame *this, int naxes, const int axes[],
+* AstMapping **map )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function creates a new Frame whose axes are copies of axes
+* picked from an existing Frame. Other Frame attributes are also
+* copied to the new Frame. Zero or more of the original axes may
+* be picked in any order, but each can be used only
+* once. Additional axes (with default characteristics) may be
+* included in the new Frame if required.
+*
+* Optionally, a Mapping that converts between the original Frame's
+* axes and those of the new Frame may also be returned.
+
+* Parameters:
+* this
+* Pointer to the original Frame.
+* naxes
+* The number of axes required in the new Frame.
+* axes
+* Pointer to an array of int with naxes elements. This should
+* contain (zero based) axis indices specifying the axes which
+* are to be included in the new Frame, in the order
+* required. Each axis index may occur only once.
+*
+* If additional (default) axes are also to be included, the
+* corresponding elements of this array should be set to -1.
+* map
+* Address of a location to receive a pointer to a new
+* Mapping. This will be a PermMap (or a UnitMap as a special
+* case) that describes the axis permutation that has taken
+* place between the original and new Frames. The forward
+* transformation will convert from the original Frame's axes to
+* the new one's, and vice versa.
+*
+* If this Mapping is not required, a NULL value may be supplied
+* for this parameter.
+
+* Returned Value:
+* Pointer to the new Frame.
+
+* Notes:
+* - The class of object returned may differ from that of the
+* original Frame, depending on which axes are selected. For
+* example, if a single axis is picked from a SkyFrame (which
+* always has two axes), the resulting Frame cannot be a valid
+* SkyFrame, so will revert to the parent class (Frame) instead.
+* - The new Frame contains a deep copy of all the data selected
+* from the original Frame. Modifying the new Frame will therefore
+* not affect the original one.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+
+* Implementation Notes:
+* - This function implements the basic astPickAxes method
+* available via the protected interface to the Frame class. The
+* public interface to this method is provided by the
+* astPickAxesId_ function.
+*/
+
+/* Local Variables: */
+ AstFrame *frame; /* Pointer to Frame to be returned */
+ AstMapping *mapping; /* Pointer to Mapping to be returned */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Initialise the returned pointers. */
+ frame = NULL;
+ if ( map ) *map = NULL;
+
+/* Check that a valid set of axes is being selected . */
+ astValidateAxisSelection( this, naxes, axes, "astPickAxes" );
+
+/* Create the required new Frame by selecting the axes. This also returns a
+ Mapping which transforms between the original Frame and the new one. */
+ astSubFrame( this, NULL, naxes, axes, NULL, &mapping, &frame );
+ if ( astOK ) {
+
+/* Return the Mapping pointer if required. */
+ if ( map ) {
+ *map = mapping;
+
+/* Otherwise annul the Mapping. If an error occurs, also annul the Frame. */
+ } else {
+ mapping = astAnnul( mapping );
+ if ( !astOK ) frame = astAnnul( frame );
+ }
+ }
+
+/* Return the pointer to the new Frame. */
+ return frame;
+}
+
+static void PrimaryFrame( AstFrame *this, int axis1,
+ AstFrame **frame, int *axis2, int *status ) {
+/*
+*+
+* Name:
+* astPrimaryFrame
+
+* Purpose:
+* Uniquely identify a primary Frame and one of its axes.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astPrimaryFrame( AstFrame *this, int axis1, AstFrame **frame,
+* int *axis2 )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function returns information about the underlying (primary) Frame
+* corresponding to a specified axis, when given what may be a compound
+* Frame composed of more than one simpler one.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis1
+* An axis index (zero-based) identifying the Frame axis for which
+* information is required.
+* frame
+* Address of a location to receive a pointer to the underlying (primary)
+* frame to which the requested axis belongs (i.e. this will not be a
+* compound Frame).
+* axis2
+* Pointer to an int which is to receive the (zero-based) axis
+* index within "frame" which identifies the axis being referred
+* to, using the axis order that applied when the primary Frame
+* was originally constructed (i.e. this function undoes all
+* subsequent axis pemutations and the effects of combining
+* Frames, in order to reveal the original underlying axis
+* order).
+
+* Notes:
+* - This protected method is provided so that class implementations can
+* distinguish the axes of frames from one another (e.g. can distinguish
+* a longitude axis as being different from a latitide axis) even after
+* their order has been permuted and they have been combined with axes from
+* other Frames.
+* - The reference count of the primary Frame will be incremented by one to
+* reflect the new pointer returned.
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Initialise the returned values. */
+ *frame = NULL;
+ *axis2 = 0;
+
+/* Validate and permute the axis index supplied. */
+ axis1 = astValidateAxis( this, axis1, 1, "astPrimaryFrame" );
+
+/* Since "this" is a primary Frame (i.e. is not compound), simply clone a
+ pointer to it. */
+ if ( astOK ) *frame = astClone( this );
+
+/* Return the permuted axis index, which refers to the original axis order. */
+ if ( astOK ) *axis2 = axis1;
+}
+
+double astReadDateTime_( const char *value, int *status ) {
+/*
+*+
+* Name:
+* astReadDateTime
+
+* Purpose:
+* Read a date/time string.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* double astReadDateTime( const char *value )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function reads a date/time string in a variety of formats and
+* returns the resulting time as a Modified Julian Date. If the string
+* cannot be interpreted as a date/time or contains invalid values, an
+* error is reported.
+
+* Parameters:
+* value
+* Pointer to a null terminated string containing the value to be read.
+
+* Returned Value:
+* The time as a Modified Julian date.
+
+* Date/Time Formats:
+* The date/time formats supported by this function are listed below. These
+* are interpreted in a case-insensitive manner and the function is
+* generally flexible about the presence of additional white space and the
+* use of alternative field delimiters.
+*
+* Besselian Epoch
+* Expressed in decimal years, with or without decimal places
+* ("B1950" or "B1976.13", for example).
+* Julian Epoch
+* Expressed in decimal years, with or without decimal places
+* ("J2000" or "J2100.9", for example).
+* Year
+* Decimal years, with or without decimal places ("1996.8" for example).
+* Such values are interpreted as a Besselian epoch (see above) if less
+* than 1984.0 and as a Julian epoch otherwise.
+* Julian Date
+* With or without decimal places ("JD 2454321.9" for example).
+* Modified Julian Date
+* With or without decimal places ("MJD 54321.4" for example).
+* Gregorian Calendar Date
+* With the month expressed as an integer or 3-character
+* abbreviation, and with optional decimal places to represent a
+* fraction of a day ("1996-10-2" or "1996-Oct-2.6" for
+* example). If no fractional part of a day is given, the time
+* refers to the start of the day (zero hours).
+* Gregorian Date and Time
+* Any calendar date (as above) but with a fraction of a day expressed
+* as hours, minutes and seconds ("1996-Oct-2 12:13:56.985" for example).
+* The date and time can be separated by a space or by a "T" (as used
+* by ISO8601).
+
+* Notes:
+* - The date/time value is interpreted as a calendar date and time, not
+* linked to any particular time system. Thus, interpretation of hours,
+* minutes and seconds is done in the obvious manner assuming 86400 seconds
+* in a day. No allowance for is made, for instance, for leap seconds or for
+* the varying length of a second in some time systems.
+* - A value of AST__BAD is returned if this function is invoked with the
+* global error status set or if it should fail for any reason.
+*-
+*/
+
+/* Local Vaiables: */
+ char cmonth[ 4 ]; /* Buffer for name of month */
+ char sep1[ 2 ]; /* Year/month separator string */
+ char sep2[ 2 ]; /* Month/day separator string */
+ char sep3[ 2 ]; /* Hour/minute separator string */
+ char sep4[ 2 ]; /* Minute/second separator string */
+ char *cc; /* Pointer to copy of remaining text */
+ const char *v; /* Pointer into value string */
+ const char *p; /* Pointer to date/time separator */
+ double day; /* Day number plus fraction of whole day */
+ double epoch; /* Epoch stored as decimal years */
+ double hms; /* Hours, min & sec as fraction of a day */
+ double jd; /* Julian Date */
+ double mjd; /* Modified Julian Date */
+ double result; /* Result to be returned */
+ double sec; /* Seconds and fractions of a second */
+ int hour; /* Number of hours */
+ int iday; /* Number of whole days */
+ int l; /* Length of string remaining */
+ int len; /* Length of string */
+ int match; /* Date/time string has correct form? */
+ int minute; /* Number of minutes */
+ int month; /* Number of months */
+ int nc; /* Number of characters read from string */
+ int stat; /* Status return from SLALIB functions */
+ int year; /* Number of years */
+
+/* Check the global error status. */
+ if ( !astOK ) return AST__BAD;
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Obtain the length of the input string. */
+ len = (int) strlen( value );
+
+/* Attempt to read the string using each recognised format in turn. */
+
+/* Besselian epoch in decimal years (e.g. "B1950.0"). */
+/* ================================================== */
+ if ( nc = 0,
+ ( 1 == astSscanf( value, " %*1[Bb] %lf %n", &epoch, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Convert to Modified Julian Date. */
+ result = palEpb2d( epoch );
+
+/* Julian epoch in decimal years (e.g. "J2000.0"). */
+/* =============================================== */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( value, " %*1[Jj] %lf %n", &epoch, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Convert to Modified Julian Date. */
+ result = palEpj2d( epoch );
+
+/* Decimal years (e.g. "1976.2"). */
+/* ============================== */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( value, " %lf %n", &epoch, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Convert to Modified Julian Date, treating the epoch as Julian or Besselian
+ depending on whether it is 1984.0 or later. */
+ result = ( epoch < 1984.0 ) ? palEpb2d( epoch ) : palEpj2d( epoch );
+
+/* Modified Julian Date (e.g. "MJD 54321.0"). */
+/* ============================================ */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( value, " %*1[Mm] %*1[Jj] %*1[Dd] %lf %n",
+ &mjd, &nc ) ) && ( nc >= len ) ) {
+
+/* Use the result directly. */
+ result = mjd;
+
+/* Julian Date (e.g. "JD 2454321.5"). */
+/* ==================================== */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( value, " %*1[Jj] %*1[Dd] %lf %n",
+ &jd, &nc ) ) && ( nc >= len ) ) {
+
+/* Convert to Modified Julian Date. */
+ result = jd - 2400000.5;
+
+/* Gregorian calendar date (e.g. "1996-10-2" or "1996-Oct-2"). */
+/* =========================================================== */
+/* This format also allows day fractions expressed as decimal days, e.g:
+
+ "1996-Oct-2.5001"
+
+ or as hours, minutes and seconds, e.g:
+
+ "1996-Oct-2 12:14:30.52"
+
+ Various alternative field delimiters are also allowed. */
+ } else {
+
+/* Note that the method used to parse this format relies heavily on
+ conditional execution controlled by "&&" and "||" operators. Initialise
+ the variables used. */
+ v = value;
+ l = len;
+ *cmonth = '\0';
+ year = month = iday = hour = minute = 0;
+ day = sec = 0.0;
+
+/* Identify the year and month. */
+/* ---------------------------- */
+/* Try to match an initial " 1996 - 10 -" or " 1996 10 " or similar. */
+ match =
+ ( nc = 0, ( 4 == astSscanf( v, " %d %1[:/-] %2d %1[:/-]%n",
+ &year, sep1, &month, sep2, &nc ) ) );
+ match = match ||
+ ( nc = 0, ( 4 == astSscanf( v, " %d%1[ ] %2d%1[ ]%n",
+ &year, sep1, &month, sep2, &nc ) ) );
+
+/* If that failed, allow " 1996 - Oct -" or " 1996 Oct " or similar. */
+ match = match ||
+ ( nc = 0, ( 4 == astSscanf( v,
+ " %d %1[:/-] %3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz] %1[:/-]%n",
+ &year, sep1, cmonth, sep2, &nc ) ) );
+ match = match ||
+ ( nc = 0, ( 4 == astSscanf( v,
+ " %d%1[ ] %3[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz]%1[ ]%n",
+ &year, sep1, cmonth, sep2, &nc ) ) );
+
+/* Alternative field separators are permitted above, but ensure that
+ they are both the same. */
+ match = match && ( *sep1 == *sep2 );
+
+/* Identify the day and fraction of day. */
+/*-------------------------------------- */
+/* If the above matched correctly, modify the string pointer "v" to
+ the next character to be interpreted and decrement the remaining
+ string length. */
+ if ( match ) {
+ v += nc;
+ l -= nc;
+
+/* ISO8601 format uses the litter T as a delimiter between the date and time.
+ If there is a T in the remaining string, take a copy and change the T to
+ a space. */
+ p = strchr( v, 'T' );
+ if( p ) {
+ cc = astStore( NULL, v, l + 1 );
+ cc[ p - v ] = ' ';
+ v = cc;
+ } else {
+ cc = NULL;
+ }
+
+/* We now try to match the following characters but without reading
+ any values. This is done to ensure the string has the correct form
+ (e.g. exclude "-" signs and exponents in numbers, which are
+ otherwise hard to detect). */
+
+/* Try to match " 12.3456 " or similar. */
+ match =
+ ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789].%*[0123456789] %n",
+ &nc ) )
+ && ( nc == l ) );
+
+/* If that failed, then try to match " 12. " or similar. */
+ match = match ||
+ ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789]. %n", &nc ) )
+ && ( nc == l ) );
+
+/* If that also failed, then try to match just " 12 " or similar. */
+ match = match ||
+ ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789] %n", &nc ) )
+ && ( nc == l ) );
+
+/* If any of the above patterns matched, now read the data (the day number)
+ as a double value. */
+ if ( match ) {
+ match = ( nc = 0, ( 1 == astSscanf( v, " %lf %n", &day, &nc ) )
+ && ( nc == l ) );
+
+/* If none of the above matched, then look to see if the day fraction has been
+ given in hours, minutes and seconds by trying to match " 12 03 : 45 :" or
+ " 12 13 45 " or similar. */
+ } else {
+ match =
+ ( nc = 0, ( 5 == astSscanf( v,
+ " %2d%*1[ ] %2d %1[:/-] %2d %1[:/-]%n",
+ &iday, &hour, sep3, &minute, sep4,
+ &nc ) ) );
+ match = match ||
+ ( nc = 0, ( 5 == astSscanf( v, " %2d%*1[ ] %2d%1[ ] %2d%1[ ]%n",
+ &iday, &hour, sep3, &minute, sep4,
+ &nc ) ) );
+
+/* Alternative field separators are permitted above, but ensure that
+ they are both the same. */
+ match = match && ( *sep3 == *sep4 );
+
+/* If the day number was read as an integer, convert it to double. */
+ if ( match ) day = (double) iday;
+
+/* If no match, see if we can get a match without a trailing seconds field. */
+ if( !match ) {
+ match =
+ ( nc = 0, ( 4 == astSscanf( v,
+ " %2d%*1[ ] %2d %1[:/-] %2d %n",
+ &iday, &hour, sep3, &minute, &nc ) &&
+ ( nc == l ) ) );
+ match = match ||
+ ( nc = 0, ( 4 == astSscanf( v, " %2d%*1[ ] %2d%1[ ] %2d %n",
+ &iday, &hour, sep3, &minute, &nc ) &&
+ ( nc == l ) ) );
+
+/* If the day number was read as an integer, convert it to double. */
+ if ( match ) day = (double) iday;
+
+/* Otherwise, identify the seconds field. */
+/* -------------------------------------- */
+/* If hours and minutes fields have been matched, now look for the
+ final seconds (and fractions of seconds) field. This is similar to
+ the day/fraction field (see earlier) in that we first check that it
+ has the correct form before reading its value. */
+
+/* Adjust the string pointer and remaining string length. */
+ } else {
+ v += nc;
+ l -= nc;
+
+/* Try to match " 12.3456 " or similar. */
+ match =
+ ( nc = 0, ( 0 == astSscanf( v,
+ " %*2[0123456789].%*[0123456789] %n",
+ &nc ) )
+ && ( nc == l ) );
+
+/* If that failed, then try to match " 12. " or similar. */
+ match = match ||
+ ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789]. %n", &nc ) )
+ && ( nc == l ) );
+
+/* If that also failed, then try to match just " 12 " or similar. */
+ match = match ||
+ ( nc = 0, ( 0 == astSscanf( v, " %*2[0123456789] %n", &nc ) )
+ && ( nc == l ) );
+
+/* If any of the above patterns matched, now read the data (the number of
+ seconds) as a double value. */
+ if ( match ) {
+ match = ( nc = 0, ( 1 == astSscanf( v, " %lf %n", &sec, &nc ) )
+ && ( nc == l ) );
+ }
+ }
+ }
+
+/* Free resources */
+ if( cc ) cc = astFree( cc );
+
+ }
+
+/* Interpret the values that were read. */
+/* ------------------------------------ */
+/* We execute this if all of the above text matching was successful,
+ transferred the required number of data values, and consumed the
+ entire input string. */
+ if ( match ) {
+
+/* See if the month was given as a character string (e.g. "Oct") instead of
+ a number. If so, define local variables for use in converting it. */
+ if ( *cmonth ) {
+ char lcmonth[ 4 ]; /* Lower case copy of month string */
+ const char *ptr; /* Pointer result from look up */
+ const char *table = /* Month look up table */
+ "jan feb mar apr may jun jul aug sep oct nov dec";
+ int i; /* Loop counter for characters */
+
+/* Convert the month string to lower case. */
+ for ( i = 0; cmonth[ i ]; i++ ) {
+ lcmonth[ i ] = tolower( cmonth[ i ] );
+ }
+ lcmonth[ i ] = '\0';
+
+/* Look the month up in the table of months and generate the required month
+ number. */
+ if ( ( ptr = strstr( table, lcmonth ) ) ) {
+ month = 1 + ( ptr - table ) / 4;
+
+/* If the lookup failed, report an error. */
+ } else {
+ astError( AST__DTERR, "Month value \"%s\" is invalid.", status,
+ cmonth );
+ }
+ }
+
+/* If OK, extract the integral day number and convert years, months and days
+ to a Modified Julian Date. */
+ if ( astOK ) {
+ iday = (int) day;
+ palCaldj( year, month, iday, &mjd, &stat );
+
+/* Examine the return status from the conversion and report an appropriate
+ error if necessary. */
+ switch ( stat ) {
+ case 1:
+ astError( AST__DTERR, "Year value (%d) is invalid.", status, year );
+ break;
+ case 2:
+ astError( AST__DTERR, "Month value (%d) is invalid.", status, month );
+ break;
+ case 3:
+ astError( AST__DTERR, "Day value (%.*g) is invalid.", status, AST__DBL_DIG,
+ day );
+ break;
+
+/* If conversion to MJD was successful, add any fractional part of a day to the
+ result. */
+ default:
+ mjd += ( day - (double) iday );
+
+/* Convert hours, minutes and seconds to a fraction of a day (this will give
+ zero if none of these quantities was supplied). */
+ palDtf2d( hour, minute, sec, &hms, &stat );
+
+/* Examine the return status from the conversion and report an appropriate
+ error if necessary. */
+ switch ( stat ) {
+ case 1:
+ astError( AST__DTERR, "Hour value (%d) is invalid.", status, hour );
+ break;
+ case 2:
+ astError( AST__DTERR, "Minute value (%d) is invalid.", status,
+ minute );
+ break;
+ case 3:
+ astError( AST__DTERR, "Seconds value (%.*g) is invalid.", status,
+ AST__DBL_DIG, sec );
+ break;
+
+/* Add the fraction of a day derived from hours, minutes and seconds fields to
+ the result. */
+ default:
+ mjd += hms;
+ break;
+ }
+ break;
+ }
+
+/* Return the result, if no error occurred. */
+ if ( astOK ) result = mjd;
+ }
+
+/* If none of the supported date/time formats matched, then report an error. */
+ } else {
+ astError( AST__DTERR, "Date/time does not have the correct form." , status);
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static void ReportPoints( AstMapping *this_mapping, int forward,
+ AstPointSet *in_points, AstPointSet *out_points, int *status ) {
+/*
+* Name:
+* ReportPoints
+
+* Purpose:
+* Report the effect of transforming a set of points using a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "mapping.h"
+* void ReportPoints( AstMapping *this, int forward,
+* AstPointSet *in_points, AstPointSet *out_points, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the protected astReportPoints
+* method inherited from the Mapping class).
+
+* Description:
+* This function reports the coordinates of a set of points before
+* and after being transformed by a Frame, by writing them to
+* standard output.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* forward
+* A non-zero value indicates that the Frame's forward
+* coordinate transformation has been applied, while a zero
+* value indicates the inverse transformation.
+* in_points
+* Pointer to a PointSet which is associated with the
+* coordinates of a set of points before the Frame was applied.
+* out_points
+* Pointer to a PointSet which is associated with the
+* coordinates of the same set of points after the Frame has
+* been applied.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstFrame *this; /* Pointer to the Frame structure */
+ double **ptr_in; /* Pointer to array of input data pointers */
+ double **ptr_out; /* Pointer to array of output data pointers */
+ int coord; /* Loop counter for coordinates */
+ int ncoord_in; /* Number of input coordinates per point */
+ int ncoord_out; /* Number of output coordinates per point */
+ int npoint; /* Number of points to report */
+ int npoint_in; /* Number of input points */
+ int npoint_out; /* Number of output points */
+ int point; /* Loop counter for points */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_mapping;
+
+/* Obtain the numbers of points and coordinates associated with each
+ PointSet. */
+ npoint_in = astGetNpoint( in_points );
+ npoint_out = astGetNpoint( out_points );
+ ncoord_in = astGetNcoord( in_points );
+ ncoord_out = astGetNcoord( out_points );
+
+/* Obtain the pointers that give access to the coordinate data
+ associated with each PointSet. */
+ ptr_in = astGetPoints( in_points );
+ ptr_out = astGetPoints( out_points );
+
+/* In the event that both PointSets don't contain equal numbers of
+ points (this shouldn't actually happen), simply use the minimum
+ number. */
+ npoint = ( npoint_in < npoint_out ) ? npoint_in : npoint_out;
+
+/* Loop to report the effect of the transformation on each point in
+ turn. */
+ for ( point = 0; point < npoint; point++ ) {
+
+/* Report the input coordinates (in parentheses and separated by
+ commas). Format each value for display using the Frame's astFormat
+ method. */
+ printf( "(" );
+ for ( coord = 0; coord < ncoord_in; coord++ ) {
+ printf( "%s%s", coord ? ", " : "",
+ astFormat( this, coord, ptr_in[ coord ][ point ] ) );
+ }
+
+/* Similarly report the output coordinates. */
+ printf( ") --> (" );
+ for ( coord = 0; coord < ncoord_out; coord++ ) {
+ printf( "%s%s", coord ? ", " : "",
+ astFormat( this, coord, ptr_out[ coord ][ point ] ) );
+ }
+ printf( ")\n" );
+ }
+}
+
+static void Resolve( AstFrame *this, const double point1[],
+ const double point2[], const double point3[],
+ double point4[], double *d1, double *d2, int *status ){
+/*
+*++
+* Name:
+c astResolve
+f AST_RESOLVE
+
+* Purpose:
+* Resolve a vector into two orthogonal components
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c void astResolve( AstFrame *this, const double point1[],
+c const double point2[], const double point3[],
+c double point4[], double *d1, double *d2 );
+f CALL AST_RESOLVE( THIS, POINT1, POINT2, POINT3, POINT4, D1, D2,
+f STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function resolves a vector into two perpendicular components.
+f This routine resolves a vector into two perpendicular components.
+* The vector from point 1 to point 2 is used as the basis vector.
+* The vector from point 1 to point 3 is resolved into components
+* parallel and perpendicular to this basis vector. The lengths of the
+* two components are returned, together with the position of closest
+* aproach of the basis vector to point 3.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c point1
+f POINT1( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This marks the start of the basis vector,
+* and of the vector to be resolved.
+c point2
+f POINT2( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This marks the end of the basis vector.
+c point3
+f POINT3( * ) = DOUBLE PRECISION (Given)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* (Naxes attribute). This marks the end of the vector to be
+* resolved.
+c point4
+f POINT4( * ) = DOUBLE PRECISION (Returned)
+c An array of double, with one element for each Frame axis
+f An array with one element for each Frame axis
+* in which the coordinates of the point of closest approach of the
+* basis vector to point 3 will be returned.
+c d1
+f D1 = DOUBLE PRECISION (Returned)
+c The address of a location at which to return the distance from
+f The distance from
+* point 1 to point 4 (that is, the length of the component parallel
+* to the basis vector). Positive values are in the same sense as
+* movement from point 1 to point 2.
+c d2
+f D2 = DOUBLE PRECISION (Returned)
+c The address of a location at which to return the distance from
+f The distance from
+* point 4 to point 3 (that is, the length of the component
+* perpendicular to the basis vector). The value is always positive.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+c - Each vector used in this function is the path of
+f - Each vector used in this routine is the path of
+* shortest distance between two points, as defined by the
+c astDistance function.
+f AST_DISTANCE function.
+* - This function will return "bad" coordinate values (AST__BAD)
+* if any of the input coordinates has this value, or if the required
+* output values are undefined.
+*--
+*/
+
+/* Local Variables: */
+ double bv; /* Length of basis vector */
+ double c; /* Component length */
+ double dp; /* Dot product */
+ int axis; /* Loop counter for axes */
+ int naxes; /* Number of Frame axes */
+ int ok; /* OK to proceed? */
+
+/* Check the global error status. */
+ *d1 = AST__BAD;
+ *d2 = AST__BAD;
+ if ( !astOK ) return;
+
+/* Determine the number of Frame axes. */
+ naxes = astGetNaxes( this );
+
+/* Initialize bad values, and check if the supplied vectors are good. */
+ ok = 1;
+ for( axis = 0; axis < naxes; axis++ ){
+ point4[ axis ] = AST__BAD;
+ if( point1[ axis ] == AST__BAD ||
+ point2[ axis ] == AST__BAD ||
+ point3[ axis ] == AST__BAD ) ok = 0;
+ }
+
+/* Check the supplied values. */
+ if ( ok ) {
+
+/* Find the dot product of the basis vector with the vector joining point 1
+ and point 3. At the same time form the squared length of the basis
+ vector. */
+ dp = 0.0;
+ bv = 0.0;
+ for( axis = 0; axis < naxes; axis++ ){
+ c = point2[ axis ] - point1[ axis ];
+ dp += c * ( point3[ axis ] - point1[ axis ] );
+ bv += c * c;
+ }
+
+/* Check the basis vector does not have zero length, and convert the
+ squared length into a length. */
+ if( bv > 0.0 ) {
+ bv = sqrt( bv );
+
+/* The dot product is the required distance d1 multiplied by the length
+ of the basis vector. Form the distance d1. */
+ *d1 = dp/bv;
+
+/* Offset away from point 1 towards point 2 by a distance of d1. */
+ for( axis = 0; axis < naxes; axis++ ){
+ point4[ axis ] = point1[ axis ] +
+ (*d1/bv)*( point2[ axis ] - point1[ axis ] );
+ }
+
+/* Finally, form the required length d2. */
+ *d2 = 0.0;
+ for( axis = 0; axis < naxes; axis++ ){
+ c = ( point3[ axis ] - point4[ axis ] );
+ *d2 += c*c;
+ }
+ *d2 = sqrt( *d2 );
+
+ }
+ }
+
+ return;
+
+}
+
+static AstPointSet *ResolvePoints( AstFrame *this, const double point1[],
+ const double point2[], AstPointSet *in,
+ AstPointSet *out, int *status ) {
+/*
+*+
+* Name:
+* astResolvePoints
+
+* Purpose:
+* Resolve a set of vectors into orthogonal components
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* AstPointSet *astResolvePoints( AstFrame *this, const double point1[],
+* const double point2[], AstPointSet *in,
+* AstPointSet *out )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function takes a Frame and a set of vectors encapsulated
+* in a PointSet, and resolves each one into two orthogonal components,
+* returning these two components in another PointSet.
+*
+* This is exactly the same as the public astResolve method, except
+* that this method allows many vectors to be processed in a single call,
+* thus reducing the computational cost of overheads of many
+* individual calls to astResolve.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* point1
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). This marks the start of the basis vector,
+* and of the vectors to be resolved.
+* point2
+* An array of double, with one element for each Frame axis
+* (Naxes attribute). This marks the end of the basis vector.
+* in
+* Pointer to the PointSet holding the ends of the vectors to be
+* resolved.
+* out
+* Pointer to a PointSet which will hold the length of the two
+* resolved components. A NULL value may also be given, in which
+* case a new PointSet will be created by this function.
+
+* Returned Value:
+* Pointer to the output (possibly new) PointSet. The first axis will
+* hold the lengths of the vector components parallel to the basis vector.
+* These values will be signed (positive values are in the same sense as
+* movement from point 1 to point 2. The second axis will hold the lengths
+* of the vector components perpendicular to the basis vector. These
+* values will be signed only if the Frame is 2-dimensional, in which
+* case a positive value indicates that rotation from the basis vector
+* to the tested vector is in the same sense as rotation from the first
+* to the second axis of the Frame.
+
+* Notes:
+* - The number of coordinate values per point in the input
+* PointSet must match the number of axes in the supplied Frame.
+* - If an output PointSet is supplied, it must have space for
+* sufficient number of points and 2 coordinate values per point.
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+* - We assume flat geometry throughout this function. Other classes,
+* (e.g. SkyFrame) will override this method using more appropriate
+* geometry.
+*-
+*/
+
+/* Local Variables: */
+ AstPointSet *result; /* Pointer to output PointSet */
+ double **ptr_in; /* Pointers to input axis values */
+ double **ptr_out; /* Pointers to returned axis values */
+ double *basisv; /* Pointer to array holding basis vector */
+ double *d1; /* Pointer to next parallel component value */
+ double *d2; /* Pointer to next perpendicular component value */
+ double *ip; /* Pointer to next input axis value */
+ double bv; /* Length of basis vector */
+ double c; /* Constant value */
+ double d; /* Component length */
+ double dp; /* Dot product */
+ double x1; /* First axis of basis vector */
+ double x2; /* First axis of test vector */
+ double y1; /* Second axis of basis vector */
+ double y2; /* Second axis of test vector */
+ int axis; /* Loop counter for axes */
+ int ipoint; /* Index of next point */
+ int nax; /* Number of Frame axes */
+ int ncoord_in; /* Number of input PointSet coordinates */
+ int ncoord_out; /* Number of coordinates in output PointSet */
+ int npoint; /* Number of points to transform */
+ int npoint_out; /* Number of points in output PointSet */
+ int ok; /* OK to proceed? */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain the number of axes in the Frame. */
+ nax = astGetNaxes( this );
+
+/* Obtain the number of input vectors to resolve and the number of coordinate
+ values per vector. */
+ npoint = astGetNpoint( in );
+ ncoord_in = astGetNcoord( in );
+
+/* If OK, check that the number of input coordinates matches the number
+ required by the Frame. Report an error if these numbers do not match. */
+ if ( astOK && ( ncoord_in != nax ) ) {
+ astError( AST__NCPIN, "astResolvePoints(%s): Bad number of coordinate "
+ "values (%d) in input %s.", status, astGetClass( this ), ncoord_in,
+ astGetClass( in ) );
+ astError( AST__NCPIN, "The %s given requires %d coordinate value(s) for "
+ "each input point.", status, astGetClass( this ), nax );
+ }
+
+/* If still OK, and a non-NULL pointer has been given for the output PointSet,
+ then obtain the number of points and number of coordinates per point for
+ this PointSet. */
+ if ( astOK && out ) {
+ npoint_out = astGetNpoint( out );
+ ncoord_out = astGetNcoord( out );
+
+/* Check that the dimensions of this PointSet are adequate to accommodate the
+ output coordinate values and report an error if they are not. */
+ if ( astOK ) {
+ if ( npoint_out < npoint ) {
+ astError( AST__NOPTS, "astResolvePoints(%s): Too few points (%d) in "
+ "output %s.", status, astGetClass( this ), npoint_out,
+ astGetClass( out ) );
+ astError( AST__NOPTS, "The %s needs space to hold %d transformed "
+ "point(s).", status, astGetClass( this ), npoint );
+ } else if ( ncoord_out < 2 ) {
+ astError( AST__NOCTS, "astResolvePoints(%s): Too few coordinate "
+ "values per point (%d) in output %s.", status,
+ astGetClass( this ), ncoord_out, astGetClass( out ) );
+ astError( AST__NOCTS, "The %s supplied needs space to store 2 "
+ "coordinate value(s) per transformed point.", status,
+ astGetClass( this ) );
+ }
+ }
+ }
+
+/* If all the validation stages are passed successfully, and a NULL output
+ pointer was given, then create a new PointSet to encapsulate the output
+ coordinate data. */
+ if ( astOK ) {
+ if ( !out ) {
+ result = astPointSet( npoint, 2, "", status );
+
+/* Otherwise, use the PointSet supplied. */
+ } else {
+ result = out;
+ }
+ }
+
+/* Get pointers to the input and output axis values */
+ ptr_in = astGetPoints( in );
+ ptr_out = astGetPoints( result );
+
+/* Store points to the first two axis arrays in the returned PointSet. */
+ d1 = ptr_out[ 0 ];
+ d2 = ptr_out[ 1 ];
+
+/* Allocate work space. */
+ basisv = astMalloc( sizeof( double )*(size_t) nax );
+
+/* If the Frame has only one axis, then the supplied basic vector is
+ irrelevant - the returned perpendicular distances are always zero and
+ the returned parallel distances are just the distances from point1
+ to each input point. */
+ if( nax < 2 && basisv ) {
+ ip = ptr_in[ 0 ];
+ for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++, ip++ ) {
+ *d1 = astAxDistance( this, 1, point1[0], *ip );
+ *d2 = 0.0;
+ }
+
+/* Now deal with Frames which have 2 or more axes */
+ } else if( basisv ){
+
+/* Check if the supplied positions defining the basis vector are good.
+ Store the basis vector, and get its squared length. */
+ ok = 1;
+ bv = 0.0;
+ for( axis = 0; axis < nax; axis++ ){
+ if( point1[ axis ] == AST__BAD ||
+ point2[ axis ] == AST__BAD ) {
+ ok = 0;
+ break;
+ } else {
+ basisv[ axis ] = point2[ axis ] - point1[ axis ];
+ bv += basisv[ axis ]*basisv[ axis ];
+ }
+ }
+
+/* Check the basis vector does not have zero length, and convert the
+ squared length into a length. */
+ if( ok && bv > 0.0 ) {
+ bv = sqrt( bv );
+ } else {
+ ok = 0;
+ }
+
+/* Store points to the first two axis arrays in the returned PointSet. */
+ d1 = ptr_out[ 0 ];
+ d2 = ptr_out[ 1 ];
+
+/* Check supplied values can be used */
+ if( ok ) {
+
+/* Loop round each supplied vector. */
+ for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) {
+
+/* Find the dot product of the basis vector with the vector joining point 1
+ and the end of the current vector. */
+ ok = 1;
+ dp = 0.0;
+ for( axis = 0; axis < nax; axis++ ){
+ d = ptr_in[ axis ][ ipoint ] - point1[ axis ];
+ if( d != AST__BAD ) {
+ dp += basisv[ axis ] * d;
+ } else {
+ ok = 0;
+ break;
+ }
+ }
+
+/* If this input position is good... */
+ if( ok ) {
+
+/* The dot product is the required parallel component length multiplied by the
+ length of the basis vector. Form the distance d1. */
+ *d1 = dp/bv;
+
+/* Offset away from point 1 towards point 2 by a distance of d1, and form the
+ required length d2. */
+ c = *d1/bv;
+ if( nax > 2 ) {
+ *d2 = 0.0;
+ for( axis = 0; axis < nax; axis++ ){
+ d = ptr_in[ axis ][ ipoint ] -
+ ( point1[ axis ] + c*basisv[ axis ] );
+ *d2 += d*d;
+ }
+ *d2 = sqrt( *d2 );
+
+/* If the Frame is 2 dimensional, we can give a sign the the perpendicular
+ component. */
+ } else {
+ x1 = c*basisv[ 0 ];
+ y1 = c*basisv[ 1 ];
+ x2 = ptr_in[ 0 ][ ipoint ] - ( point1[ 0 ] + x1 );
+ y2 = ptr_in[ 1 ][ ipoint ] - ( point1[ 1 ] + y1 );
+ *d2 = sqrt( x2*x2 + y2*y2 );
+ if( x1*y2 - x2*y1 < 0.0 ) *d2 = -(*d2);
+ }
+
+/* If this input vector is bad, put bad values in the output */
+ } else {
+ *d1 = AST__BAD;
+ *d2 = AST__BAD;
+ }
+ }
+
+/* If supplied values cannot be used, fill the returned PointSet with bad
+ values */
+ } else {
+ for( ipoint = 0; ipoint < npoint; ipoint++, d1++, d2++ ) {
+ *d1 = AST__BAD;
+ *d2 = AST__BAD;
+ }
+ }
+ }
+
+/* Free resources */
+ basisv = astFree( basisv );
+
+/* Annul the returned PointSet if an error occurred. */
+ if( !astOK ) result = astAnnul( result );
+
+/* Return a pointer to the output PointSet. */
+ return result;
+}
+
+static void SetActiveUnit( AstFrame *this, int value, int *status ){
+/*
+*++
+* Name:
+c astSetActiveUnit
+f AST_SETACTIVEUNIT
+
+* Purpose:
+* Specify how the Unit attribute should be used.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c void astSetActiveUnit( AstFrame *this, int value )
+f CALL AST_SETACTIVEUNIT( THIS, VALUE, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function
+f This routine
+* sets the current value of the ActiveUnit flag for a Frame, which
+* controls how the Frame behaves when it is used (by
+c astFindFrame or astConvert)
+f AST_FINDFRAME or AST_CONVERT)
+* to match another Frame. If the ActiveUnit flag is set in both
+* template and target Frames then the returned Mapping takes into account
+* any differences in axis units. The default value for simple Frames is
+* zero, which preserves the behaviour of versions of AST prior to
+* version 2.0.
+*
+* If the ActiveUnit flag of either Frame is
+c zero,
+f .FALSE.,
+* then the Mapping will ignore any difference in the Unit attributes of
+* corresponding template and target axes. In this mode, the Unit
+* attributes are purely descriptive commentary for the benefit of
+* human readers and do not influence the Mappings between Frames.
+* This is the behaviour which all Frames had in older version of AST,
+* prior to the introduction of this attribute.
+*
+* If the ActiveUnit flag of both Frames is
+c non-zero,
+f .TRUE.,
+* then the Mapping from template to target will take account of any
+* difference in the axis Unit attributes, where-ever possible. For
+* instance, if corresponding target and template axes have Unit strings of
+* "km" and "m", then the FrameSet class will use a ZoomMap to connect
+* them which introduces a scaling of 1000. If no Mapping can be found
+* between the corresponding units string, then an error is reported.
+* In this mode, it is assumed that values of the Unit attribute conform
+* to the syntax for units strings described in the FITS WCS Paper I
+* "Representations of world coordinates in FITS" (Greisen & Calabretta).
+* Particularly, any of the named unit symbols, functions, operators or
+* standard multiplier prefixes listed within that paper can be used within
+* a units string. A units string may contain symbols for unit which are
+* not listed in the FITS paper, but transformation to any other units
+* will then not be possible (except to units which depend only on the
+* same unknown units - thus "flops" can be transformed to "Mflops"
+* even though "flops" is not a standard FITS unit symbol).
+*
+* A range of common non-standard variations of unit names and multiplier
+* prefixes are also allowed, such as adding an "s" to the end of Angstrom,
+* using a lower case "a" at the start of "angstrom", "micron" instead of
+* "um", "sec" instead of "s", etc.
+*
+c If the ActiveUnit flag is non-zero, setting a new Unit value for an
+f If the ActiveUnit flag is .TRUE., setting a new Unit value for an
+* axis may also change its Label and Symbol attributes. For instance, if
+* an axis has Unit "Hz" and Label "frequency", then changing its Unit to
+* "log(Hz)" will change its Label to "log( frequency )". In addition,
+* the Axis Format attribute will be cleared when-ever a new value
+* is assigned to the Unit attribute.
+*
+c Note, if a non-zero value is set for the ActiveUnit flag, then changing a
+f Note, if a .TRUE. value is set for the ActiveUnit flag, then changing a
+* Unit value for the current Frame within a FrameSet will result in the
+* Frame being re-mapped (that is, the Mappings which define the
+* relationships between Frames within the FrameSet will be modified to
+* take into account the change in Units).
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c value
+f VALUE = LOGICAL (Given)
+* The new value to use.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Applicability:
+* SkyFrame
+c The ActiveUnit flag for a SkyFrame is always 0 (any value
+c supplied using this function is ignored).
+f The ActiveUnit flag for a SkyFrame is always .FALSE. (any value
+f supplied using this routine is ignored).
+* SpecFrame
+c The ActiveUnit flag for a SpecFrame is always 1 (any value
+c supplied using this function is ignored).
+f The ActiveUnit flag for a SpecFrame is always .TRUE. (any value
+f supplied using this routine is ignored).
+* FluxFrame
+c The ActiveUnit flag for a FluxFrame is always 1 (any value
+c supplied using this function is ignored).
+f The ActiveUnit flag for a FluxFrame is always .TRUE. (any value
+f supplied using this routine is ignored).
+* CmpFrame
+c The default ActiveUnit flag for a CmpFrame is 1 if both of the
+c component Frames are using active units, and zero otherwise. When
+f The default ActiveUnit flag for a CmpFrame is .TRUE. if both of the
+f component Frames are using active units, and .FALSE. otherwise. When
+* a new value is set for the ActiveUnit flag, the flag value
+* is propagated to the component Frames. This change will be
+* reflected through all references to the component Frames, not
+* just those encapsulated within the CmpFrame.
+* Region:
+* Regions always use active units if possible.
+
+* Notes:
+* - The ActiveUnit flag resembles a Frame attribute, except that it
+* cannot be tested or cleared, and it cannot be accessed using the
+c generic astGet<X> and astSet<X> functions.
+f generic AST_GET<X> and AST_SET<X> routines.
+c - The astGetActiveUnit function can be used to retrieve the current
+f - The AST_GETACTIVEUNIT routine can be used to retrieve the current
+* value of the ActiveUnit flag.
+
+*--
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Store a value of 1 for the Frame component if the supplied value is
+ non-zero. */
+ this->active_unit = ( value ) ? 1 : 0;
+}
+
+static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
+/*
+* Name:
+* SetAttrib
+
+* Purpose:
+* Set an attribute value for a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* void SetAttrib( AstObject *this, const char *setting, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the astSetAttrib method inherited
+* from the Mapping class).
+
+* Description:
+* This function assigns an attribute value for a Frame, the
+* attribute and its value being specified by means of a string of
+* the form:
+*
+* "attribute= value "
+*
+* Here, "attribute" specifies the attribute name and should be in
+* lower case with no white space present. The value to the right
+* of the "=" should be a suitable textual representation of the
+* value to be assigned and this will be interpreted according to
+* the attribute's data type. White space surrounding the value is
+* only significant for string attributes.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* setting
+* Pointer to a null terminated string specifying the new attribute
+* value.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - This function uses one-based axis numbering so that it is
+* suitable for external (public) use.
+*/
+
+/* Local Vaiables: */
+ AstAxis *ax; /* Pointer to Axis */
+ AstFrame *pfrm; /* Pointer to primary Frame containing axis */
+ AstFrame *this; /* Pointer to the Frame structure */
+ AstSystemType system_code; /* System code */
+ char pfrm_attrib[ 100 ]; /* Primary Frame attribute */
+ char *pfrm_setting; /* Primary Frame attribute */
+ char *axis_setting; /* Pointer to axis attribute setting string */
+ const char *equals; /* Pointer to equals sign */
+ const char *old_setting; /* Pointer to supplied setting string */
+ const char *op; /* Pointer to opening parenthesis */
+ double dval; /* Double attibute value */
+ double mjd; /* Epoch as a Modified Julian Date */
+ int axis; /* Index for the Frame axis */
+ int axis_nc; /* No. characters in axis attribute name */
+ int axis_value; /* Offset of value to be assigned to axis */
+ int digits; /* Number of digits of precision */
+ int direction; /* Axis direction flag */
+ int domain; /* Offset of Domain string */
+ int epoch; /* Offset of Epoch string */
+ int format; /* Offset of axis Format string */
+ int free_axis_setting; /* Should axis_setting be freed? */
+ int has_axis; /* Does setting include an axis specifier? */
+ int ival; /* Integer attribute value */
+ int label; /* Offset of axis Label string */
+ int len; /* Length of setting string */
+ int match_end; /* Match final axes of target? */
+ int max_axes; /* Maximum number of axes matched */
+ int min_axes; /* Minimum number of axes matched */
+ int nc; /* Number of characters read by astSscanf */
+ int off2; /* Modified offset of attribute value */
+ int off; /* Offset of attribute value */
+ int oldrep; /* Original error reporting state */
+ int paxis; /* Axis index within primary frame */
+ int permute; /* Permute axes in order to match? */
+ int preserve_axes; /* Preserve matched target axes? */
+ int sign; /* Sign of longitude value */
+ int symbol; /* Offset of axis Symbol string */
+ int system; /* Offset of System string */
+ int title; /* Offset of Title string */
+ int unit; /* Offset of axis Unit string */
+ int used; /* Could the setting string be used? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_object;
+
+/* Find the offset to the first equal sign in the setting string. */
+ equals = strchr( setting, '=' );
+
+/* Set a flag indicating if the attribute name includes an axis
+ specifier. */
+ op = strchr( setting, '(' );
+ has_axis = ( !op || op > equals ) ? 0 : 1;
+
+/* A flag indicating that we do not need to free the axis_setting memory. */
+ free_axis_setting = 0;
+
+/* Initialise things to avoid compiler warnings. */
+ axis_setting = NULL;
+ old_setting = NULL;
+
+/* Jump back to here if we are trying the same attribute setting but with
+ an explicit axis "(1)" added to the attribute name. */
+L1:
+
+/* Obtain the length of the setting string. */
+ len = strlen( setting );
+
+/* Test for each recognised attribute in turn, using "astSscanf" to parse the
+ setting string and extract the attribute value (or an offset to it in the
+ case of string values). In each case, use the value set in "nc" to check
+ that the entire string was matched. Once a value has been obtained, use the
+ appropriate method to set it. */
+
+/* Digits. */
+/* ------- */
+ if ( nc = 0,
+ ( 1 == astSscanf( setting, "digits= %d %n", &digits, &nc ) )
+ && ( nc >= len ) ) {
+ astSetDigits( this, digits );
+
+/* Digits(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 2 == astSscanf( setting, "digits(%d)= %d %n",
+ &axis, &digits, &nc ) )
+ && ( nc >= len ) ) {
+
+/* There is no function to set the Digits attribute value for an axis
+ directly, so obtain a pointer to the Axis and use this to set the
+ attribute. */
+ (void) astValidateAxis( this, axis - 1, 1, "astSetDigits(axis)" );
+ ax = astGetAxis( this, axis - 1 );
+ astSetAxisDigits( ax, digits );
+ ax = astAnnul( ax );
+
+/* Direction(axis). */
+/* ---------------- */
+ } else if ( nc = 0,
+ ( 2 == astSscanf( setting, "direction(%d)= %d %n",
+ &axis, &direction, &nc ) )
+ && ( nc >= len ) ) {
+ astSetDirection( this, axis - 1, direction );
+
+/* Epoch. */
+/* ------ */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "epoch=%n%*[^\n]%n", &epoch, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Convert the Epoch value to a Modified Julian Date before use. */
+ mjd = astReadDateTime( setting + epoch );
+ if ( astOK ) {
+ astSetEpoch( this, mjd );
+
+/* Report contextual information if the conversion failed. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid epoch value "
+ "\"%s\" given for coordinate system.", status,
+ astGetClass( this ), setting + epoch );
+ }
+
+/* Top(axis). */
+/* ---------- */
+ } else if ( nc = 0,
+ ( 2 == astSscanf( setting, "top(%d)= %lg %n",
+ &axis, &dval, &nc ) )
+ && ( nc >= len ) ) {
+ astSetTop( this, axis - 1, dval );
+
+/* Bottom(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 2 == astSscanf( setting, "bottom(%d)= %lg %n",
+ &axis, &dval, &nc ) )
+ && ( nc >= len ) ) {
+ astSetBottom( this, axis - 1, dval );
+
+/* Domain. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "domain=%n%*[^\n]%n", &domain, &nc ) )
+ && ( nc >= len ) ) {
+ astSetDomain( this, setting + domain );
+
+/* Format(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "format(%d)=%n%*[^\n]%n",
+ &axis, &format, &nc ) )
+ && ( nc >= len ) ) {
+ astSetFormat( this, axis - 1, setting + format );
+
+/* Label(axis). */
+/* ------------ */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "label(%d)=%n%*[^\n]%n",
+ &axis, &label, &nc ) )
+ && ( nc >= len ) ) {
+ astSetLabel( this, axis - 1, setting + label );
+
+/* MatchEnd. */
+/* --------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "matchend= %d %n", &match_end, &nc ) )
+ && ( nc >= len ) ) {
+ astSetMatchEnd( this, match_end );
+
+/* MaxAxes. */
+/* -------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "maxaxes= %d %n", &max_axes, &nc ) )
+ && ( nc >= len ) ) {
+ astSetMaxAxes( this, max_axes );
+
+/* MinAxes. */
+/* -------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "minaxes= %d %n", &min_axes, &nc ) )
+ && ( nc >= len ) ) {
+ astSetMinAxes( this, min_axes );
+
+/* Permute. */
+/* -------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "permute= %d %n", &permute, &nc ) )
+ && ( nc >= len ) ) {
+ astSetPermute( this, permute );
+
+/* PreserveAxes. */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "preserveaxes= %d %n",
+ &preserve_axes, &nc ) )
+ && ( nc >= len ) ) {
+ astSetPreserveAxes( this, preserve_axes );
+
+/* Symbol(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "symbol(%d)=%n%*[^\n]%n",
+ &axis, &symbol, &nc ) )
+ && ( nc >= len ) ) {
+ astSetSymbol( this, axis - 1, setting + symbol );
+
+/* AlignSystem. */
+/* ------------ */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "alignsystem= %n%*s %n", &system, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Convert the string to a System code before use. */
+ system_code = astSystemCode( this, system + setting );
+ if ( system_code != AST__BADSYSTEM ) {
+ astSetAlignSystem( this, system_code );
+
+/* Report an error if the string value wasn't recognised. */
+ } else {
+ astError( AST__ATTIN,
+ "astSetAttrib(%s): Invalid AlignSystem description \"%s\".", status,
+ astGetClass( this ), system + setting );
+ }
+
+/* System. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "system= %n%*s %n", &system, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Convert the string to a System code before use. */
+ system_code = astSystemCode( this, system + setting );
+ if ( system_code != AST__BADSYSTEM ) {
+ astSetSystem( this, system_code );
+
+/* Report an error if the string value wasn't recognised. */
+ } else {
+ astError( AST__ATTIN,
+ "astSetAttrib(%s): Invalid System description \"%s\".", status,
+ astGetClass( this ), system + setting );
+ }
+
+/* Title. */
+/* ------ */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "title=%n%*[^\n]%n", &title, &nc ) )
+ && ( nc >= len ) ) {
+ astSetTitle( this, setting + title );
+
+/* Unit(axis). */
+/* ----------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "unit(%d)=%n%*[^\n]%n",
+ &axis, &unit, &nc ) )
+ & ( nc >= len ) ) {
+ astSetUnit( this, axis - 1, setting + unit );
+
+/* ObsLat. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "obslat=%n%*s %n", &off, &nc ) )
+ && ( nc >= 7 ) ) {
+
+/* If the first character in the value string is "N" or "S", remember the
+ sign of the value and skip over the sign character. Default is north
+ (+ve). */
+ off2 = off;
+ if( setting[ off ] == 'N' || setting[ off ] == 'n' ) {
+ off2++;
+ sign = +1;
+ } else if( setting[ off ] == 'S' || setting[ off ] == 's' ) {
+ off2++;
+ sign = -1;
+ } else {
+ sign = +1;
+ }
+
+/* If not already created, create an FK5 J2000 SkyFrame which will be used
+ for formatting and unformatting ObsLon and ObsLat values. */
+ if( !skyframe ) {
+ astBeginPM;
+ skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status );
+ astEndPM;
+ }
+
+/* Convert the string to a radians value before use. */
+ ival = astUnformat( skyframe, 1, setting + off2, &dval );
+ if ( ival == astChrLen( setting ) - off2 ) {
+ astSetObsLat( this, dval*sign );
+
+/* Report an error if the string value wasn't recognised. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid value for "
+ "ObsLat (observers latitude) \"%s\".", status, astGetClass( this ),
+ setting + off );
+ }
+
+/* ObsLon. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "obslon=%n%*s %n", &off, &nc ) )
+ && ( nc >= 7 ) ) {
+
+/* If the first character in the value string is "E" or "W", remember the
+ sign of the value and skip over the sign character. Default is east
+ (+ve). */
+ off2 = off;
+ if( setting[ off ] == 'E' || setting[ off ] == 'e' ) {
+ off2++;
+ sign = +1;
+ } else if( setting[ off ] == 'W' || setting[ off ] == 'w' ) {
+ off2++;
+ sign = -1;
+ } else {
+ sign = +1;
+ }
+
+/* If not already created, create an FK5 J2000 SkyFrame which will be used
+ for formatting and unformatting ObsLon and ObsLat values. */
+ if( !skyframe ) {
+ astBeginPM;
+ skyframe = astSkyFrame( "system=FK5,equinox=J2000,format(2)=dms.2", status );
+ astEndPM;
+ }
+
+/* Convert the string to a radians value before use. */
+ ival = astUnformat( skyframe, 1, setting + off2, &dval );
+ if ( ival == astChrLen( setting ) - off2 ) {
+ astSetObsLon( this, dval*sign );
+
+/* Report an error if the string value wasn't recognised. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid value for "
+ "ObsLon (observers longitude) \"%s\".", status, astGetClass( this ),
+ setting + off );
+ }
+
+/* ObsAlt. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "obsalt= %lg %n", &dval, &nc ) )
+ && ( nc >= len ) ) {
+ astSetObsAlt( this, dval );
+
+/* Dtai. */
+/* ---- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "dtai= %lg %n", &dval, &nc ) )
+ && ( nc >= len ) ) {
+ astSetDtai( this, dval );
+
+/* Dut1. */
+/* ---- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "dut1= %lg %n", &dval, &nc ) )
+ && ( nc >= len ) ) {
+ astSetDut1( this, dval );
+
+
+/* Read-only attributes. */
+/* --------------------- */
+/* Define a macro to see if the setting string matches any of the
+ read-only attributes of this class. */
+#define MATCH(attrib) \
+ ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \
+ ( nc >= len ) )
+
+/* Use this macro to report an error if a read-only attribute has been
+ specified. */
+ } else if ( MATCH( "naxes" ) ||
+ !strncmp( setting, "normunit", 8 ) ||
+ !strncmp( setting, "internalunit", 12 ) ) {
+ astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status,
+ setting, astGetClass( this ) );
+ astError( AST__NOWRT, "This is a read-only attribute." , status);
+
+/* Other axis attributes. */
+/* ---------------------- */
+/* If the attribute was not identified above, but appears to refer to
+ a Frame axis, then it may refer to an Axis object of a derived type
+ (which has additional attributes not recognised here). */
+ } else if ( !free_axis_setting && ( nc = 0,
+ ( 1 == astSscanf( setting, "%*[^()=]%n(%d)%n=%*[^\n]%n",
+ &axis_nc, &axis, &axis_value, &nc ) )
+ && ( nc >= len ) ) ) {
+
+/* Validate the axis index and copy the attribute setting string. */
+ (void) astValidateAxis( this, axis - 1, 1, "astSet" );
+ axis_setting = astString( setting, len );
+ if ( astOK ) {
+
+/* Over-write the axis index in the copy with the value to be
+ assigned. */
+ (void) strcpy( axis_setting + axis_nc, setting + axis_value );
+
+/* Obtain a pointer to the Axis object. */
+ ax = astGetAxis( this, axis - 1 );
+ if( astOK ) {
+
+/* Assume that we will be able to use the setting. */
+ used = 1;
+
+/* Temporarily switch off error reporting so that if the following attempt
+ to access the axis attribute fails, we can try to interpret the
+ attribute name as an attribute of the primary Frame containing the
+ specified axis. Any errors reported in this context will simply be
+ ignored, in particularly they are not deferred for later delivery. */
+ oldrep = astReporting( 0 );
+
+/* Use the Axis astSetAttrib method
+ to set the value. */
+ astSetAttrib( ax, axis_setting );
+
+/* If the above call failed with a status of AST__BADAT, indicating that
+ the attribute name was not recognised, clear the status so that we can
+ try to interpret the attribute name as an attribute of the primary Frame
+ containing the specified axis. */
+ if( astStatus == AST__BADAT ) {
+ astClearStatus;
+
+/* Find the primary Frame containing the specified axis. */
+ astPrimaryFrame( this, axis - 1, &pfrm, &paxis );
+
+/* Only attempt to use the primary Frame if it is not the same as "this"
+ - otherwise we could end up in an infinite loop. */
+ if( pfrm != this ) {
+
+/* astPrimaryFrame returns the original - unpermuted - axis index within
+ the primary Frame. So we need to take into account any axis permutation
+ which has been applied to the primary Frame when forming the attribute name
+ to use below. Find the permuted (external) axis index which corresponds to
+ the internal (unpermuted) axis index "paxis". */
+ paxis = astValidateAxis( pfrm, paxis, 0, "astSet" );
+
+/* Modify the attribute name to refer to the axis numbering of the
+ primary frame. */
+ sprintf( pfrm_attrib, "%.*s(%d)", axis_nc, setting, paxis + 1 );
+
+/* Create a setting string in which the attribute name refers to the axis
+ numbering of the primary frame. */
+ pfrm_setting = NULL;
+ nc = 0;
+ pfrm_setting = astAppendString( pfrm_setting, &nc, pfrm_attrib );
+ pfrm_setting = astAppendString( pfrm_setting, &nc, setting + axis_value );
+
+/* Attempt to set the attribute within the primary Frame. */
+ astSetAttrib( pfrm, pfrm_setting );
+
+/* Free the memory. */
+ pfrm_setting = astFree( pfrm_setting );
+
+/* If this failed, clear the status and indicate that we have not managed to
+ use the attribute setting. */
+ if( !astOK ) {
+ astClearStatus;
+ used = 0;
+ }
+
+ } else {
+ used = 0;
+ }
+
+/* If not found attempt to set the attribute value in the Axis, omitting
+ the axis index. */
+ if( ! used ) {
+ astSetAttrib( pfrm, axis_setting );
+ if( !astOK ) {
+ astClearStatus;
+ } else {
+ used = 1;
+ }
+ }
+
+/* Free the setting string, and annul the primary Frame pointer. */
+ pfrm = astAnnul( pfrm );
+ }
+
+/* Re-instate the original error reporting state. */
+ astReporting( oldrep );
+
+/* If we could not use the setting, attempt to set the axis attribute again,
+ this time retaining the error report. This is done to ensure the user
+ gets an appropriate error message. */
+ if( !used ) astSetAttrib( ax, axis_setting );
+ }
+
+/* Annul the Axis pointer and free the memory holding the attribute
+ setting. */
+ ax = astAnnul( ax );
+ }
+ axis_setting = astFree( axis_setting );
+
+/* Not recognised. */
+/* --------------- */
+/* If the attribute is still not recognised, and the Frame has only 1 axis,
+ and the attribute name does not already include an axis specifier, try
+ again after appending "(1)" to the end of the attribute name. */
+ } else if( !has_axis && astGetNaxes( this ) == 1 && equals ) {
+
+/* Take a copy of the supplied setting, allowing 3 extra characters for the
+ axis specifier "(1)". */
+ axis_setting = astMalloc( len + 4 );
+ if( axis_setting ) memcpy( axis_setting, setting, len );
+
+/* Indicate we should free the axis_setting memory. */
+ free_axis_setting = 1;
+
+/* Add in the axis specifier. */
+ strcpy( axis_setting + ( equals - setting ), "(1)" );
+
+/* Add in the equals sign and attribute value. */
+ strcpy( axis_setting + ( equals - setting ) + 3, equals );
+
+/* Use the new setting instead of the supplied setting. */
+ old_setting = setting;
+ setting = axis_setting;
+
+/* Indicate the setting now has an axis specifier. */
+ has_axis = 1;
+
+/* Jump back to try interpreting the new setting string. */
+ goto L1;
+
+/* Not recognised. */
+/* --------------- */
+/* If the attribute is still not recognised, pass it on to the parent
+ method for further interpretation. First re-instate the original setting
+ string if it was changed above. */
+ } else {
+ if( free_axis_setting ) {
+ setting = old_setting;
+ axis_setting = astFree( axis_setting );
+ free_axis_setting = 0;
+ }
+ (*parent_setattrib)( this_object, setting, status );
+ }
+
+ if( free_axis_setting ) axis_setting = astFree( axis_setting );
+
+/* Undefine macros local to this function. */
+#undef MATCH
+}
+
+static void SetAxis( AstFrame *this, int axis, AstAxis *newaxis, int *status ) {
+/*
+*+
+* Name:
+* astSetAxis
+
+* Purpose:
+* Set a new Axis for a Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astSetAxis( AstFrame *this, int axis, AstAxis *newaxis )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function allows a new Axis object to be associated with one
+* of the axes of a Frame, replacing the previous one. Each Axis
+* object contains a description of the quantity represented along
+* one of the Frame's axes, so this function allows this
+* description to be exchanged for another one.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The index (zero-based) of the axis whose associated Axis object is to
+* be replaced.
+* newaxis
+* Pointer to the new Axis object.
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Validate and permute the axis index supplied. */
+ axis = astValidateAxis( this, axis, 1, "astSetAxis" );
+
+/* If OK, annul the Frame's pointer to the old Axis object and clone a pointer
+ to the new one to replace it. */
+ if ( astOK ) {
+ this->axis[ axis ] = astAnnul( this->axis[ axis ] );
+ this->axis[ axis ] = astClone( newaxis );
+ }
+}
+
+static void SetFrameFlags( AstFrame *this, int flags, int *status ){
+/*
+*+
+* Name:
+* astSetFrameFlags
+
+* Purpose:
+* Store a new bit mask of flags in a Frame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frame.h"
+* void astSetFrameFlags( astFrame *this, int flags )
+
+* Class Membership:
+* Frame member function.
+
+* Description:
+* This function stores a new set of flags in a Frame. The flags can
+* be retrieved using astGetFrameFlags.
+
+* Parameters:
+* this
+* The Frame.
+* flags
+* A bit mask holding the flags. Currently, the following bits are
+* used:
+*
+* 0 - Used to indicate if the Frame is currently involved in an
+* attempt to restore the integrity of a FrameSet following
+* changes to the attribute values of the Frame.
+
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Assign the new bit mask. */
+ this->flags = flags;
+}
+
+static void SetFrameVariants( AstFrame *this, AstFrameSet *variants, int *status ){
+/*
+*+
+* Name:
+* astSetFrameVariants
+
+* Purpose:
+* Store a FrameSet holding alternative Frame properties.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astSetVariants( AstFrame *this, AstFrameSet *variants )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function adds sets of alternative Frame properties to a Frame.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* variants
+* Pointer to a FrameSet in which each Frame is of the same class
+* and dimensionality as "this" and all Frames have unique Domain
+* names.
+
+* Notes:
+* - A clone of the supplied FrameSet pointer is stored in the Frame.
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Annul any variants FrameSet already stored in the Frame. */
+ if( this->variants ) this->variants = astAnnul( this->variants );
+
+/* Store a clone of ht esupplied FrameSet pointer. */
+ if( variants ) this->variants = astClone( variants );
+
+}
+
+static void SetUnit( AstFrame *this, int axis, const char *unit, int *status ) {
+/*
+* Name:
+* SetUnit
+
+* Purpose:
+* Set a value for the Unit attribute of a Frame.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void SetUnit( AstFrame *this, int axis, const char *unit, int *status )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function sets the Unit value for a Frame.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the axis (zero-based) for which the Unit value is to
+* be set.
+* unit
+* The new value to be set.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* void.
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ char *c; /* Copy of supplied string */
+ const char *oldunit; /* Pointer to old units string */
+ int l; /* Used length of supplied string */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get a copy of the supplied string which excludes trailing spaces. */
+ l = astChrLen( unit );
+ c = astStore( NULL, unit, (size_t) (l + 1) );
+ if( astOK ) {
+ c[ l ] = 0;
+
+/* Validate the axis index and obtain a pointer to the required Axis. */
+ (void) astValidateAxis( this, axis, 1, "astSetUnit" );
+ ax = astGetAxis( this, axis );
+
+/* The new unit may require the Label and/or Symbol to be changed, but
+ only if the Frames ActiveUnit flag is set. */
+ if( astGetActiveUnit( this ) ) {
+
+/* Get the existing Axis unit, using the astGetUnit method (rather than
+ astGetAxisUnit) in order to get any default value in the case where
+ the Unit attribute is not set. */
+ oldunit = astGetUnit( this, axis );
+
+/* Assign the new Unit value. This modifies labels and/or Symbols if
+ necessary. */
+ NewUnit( ax, oldunit, c, "astSetUnit", astGetClass( this ), status );
+ }
+
+/* Set the Axis Unit attribute value. */
+ astSetAxisUnit( ax, c );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+ }
+
+/* Free the string copy */
+ c = astFree( c );
+
+}
+
+static int SubFrame( AstFrame *target, AstFrame *template,
+ int result_naxes, const int *target_axes,
+ const int *template_axes, AstMapping **map,
+ AstFrame **result, int *status ) {
+/*
+*+
+* Name:
+* astSubFrame
+
+* Purpose:
+* Select axes from a Frame and convert to the new coordinate system.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astSubFrame( AstFrame *target, AstFrame *template,
+* int result_naxes, const int *target_axes,
+* const int *template_axes, AstMapping **map,
+* AstFrame **result )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function selects a requested sub-set (or super-set) of the axes from
+* a "target" Frame and creates a new Frame with copies of the selected
+* axes assembled in the requested order. It then optionally overlays the
+* attributes of a "template" Frame on to the result. It returns both the
+* resulting Frame and a Mapping that describes how to convert between the
+* coordinate systems described by the target and result Frames. If
+* necessary, this Mapping takes account of any differences in the Frames'
+* attributes due to the influence of the template.
+
+* Parameters:
+* target
+* Pointer to the target Frame, from which axes are to be selected.
+* template
+* Pointer to the template Frame, from which new attributes for the
+* result Frame are to be obtained. Optionally, this may be NULL, in
+* which case no overlaying of template attributes will be performed.
+* result_naxes
+* Number of axes to be selected from the target Frame. This number may
+* be greater than or less than the number of axes in this Frame (or
+* equal).
+* target_axes
+* Pointer to an array of int with result_naxes elements, giving a list
+* of the (zero-based) axis indices of the axes to be selected from the
+* target Frame. The order in which these are given determines the order
+* in which the axes appear in the result Frame. If any of the values in
+* this array is set to -1, the corresponding result axis will not be
+* derived from the target Frame, but will be assigned default attributes
+* instead.
+* template_axes
+* Pointer to an array of int with result_naxes elements. This should
+* contain a list of the template axes (given as zero-based axis indices)
+* with which the axes of the result Frame are to be associated. This
+* array determines which axes are used when overlaying axis-dependent
+* attributes of the template on to the result. If any element of this
+* array is set to -1, the corresponding result axis will not receive any
+* template attributes.
+*
+* If the template argument is given as NULL, this array is not used and
+* a NULL pointer may also be supplied here.
+* map
+* Address of a location to receive a pointer to the returned Mapping.
+* The forward transformation of this Mapping will describe how to
+* convert coordinates from the coordinate system described by the target
+* Frame to that described by the result Frame. The inverse
+* transformation will convert in the opposite direction.
+* result
+* Address of a location to receive a pointer to the result Frame.
+
+* Returned Value:
+* A non-zero value is returned if coordinate conversion is
+* possible between the target and the result Frame. Otherwise zero
+* is returned and *map and *result are returned as NULL (but this
+* will not in itself result in an error condition). In general,
+* coordinate conversion should always be possible if no template
+* Frame is supplied but may not always be possible otherwise.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+
+* Implementation Deficiencies:
+* - Any axis selection is currently permitted. Probably this
+* should be restricted so that each axis can only be selected
+* once. The astValidateAxisSelection method will do this but
+* currently there are bugs in the CmpFrame class that cause axis
+* selections which will not pass this test. Install the validation
+* when these are fixed.
+*-
+
+* Implementation Notes:
+* - This implementation addresses the selection of axes from a
+* Frame class object. This simply results in another object of the
+* same class and a Mapping which describes an axis permutation (or
+* a unit Mapping as a special case). Changes of Frame attributes
+* have no significance for coordinate values in this class, so do
+* not affect the Mapping returned.
+*/
+
+/* Local Variables: */
+ AstAxis *newaxis; /* Pointer to new Axis object */
+ AstFrame *tempframe; /* Pointer to temporary Frame */
+ AstMapping *aumap; /* A units Mapping for a single axis */
+ AstMapping *numap; /* The new total units Mapping */
+ AstMapping *umap; /* The total units Mapping */
+ int *inperm; /* Pointer to permutation array */
+ int *outperm; /* Pointer to permutation array */
+ int match; /* Coordinate conversion possible? */
+ int result_axis; /* Result Frame axis index */
+ int target_axis; /* Target Frame axis index */
+ int target_naxes; /* Number of target Frame axes */
+ int unit; /* Unit Mapping appropriate? */
+ int uunit; /* Is the "umap" Mapping a UnitMap? */
+
+/* Initialise the returned values. */
+ *map = NULL;
+ *result = NULL;
+ match = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return match;
+
+/* Obtain the number of target Frame axes. */
+ target_naxes = astGetNaxes( target );
+
+/* Ensure we do not attempt to use a negative number of result axes. */
+ if ( result_naxes < 0 ) result_naxes = 0;
+
+/* Create a temporary new Frame with the required number of axes. This will
+ have a default Axis object associated with each of its axes. We will
+ replace these where necessary with copies of the actual Axis objects we
+ require. */
+ tempframe = astFrame( result_naxes, "", status );
+
+/* Allocate memory to store two permutation arrays. These will be used to
+ construct the Mapping that relates the target and result Frames. */
+ inperm = astMalloc( sizeof( int ) * (size_t) target_naxes );
+ outperm = astMalloc( sizeof( int ) * (size_t) result_naxes );
+ if ( astOK ) {
+
+/* Initialise the array that associates each target axis with the corresponding
+ result axis (filling it with the value -1 initially signifies no
+ associations). */
+ for ( target_axis = 0; target_axis < target_naxes; target_axis++ ) {
+ inperm[ target_axis ] = -1;
+ }
+
+/* Loop through each axis in the result Frame and obtain the index of the axis
+ in the target Frame from which it is to be derived. */
+ for ( result_axis = 0; result_axis < result_naxes; result_axis++ ) {
+ target_axis = target_axes[ result_axis ];
+
+/* Check if the resulting axis index is valid. If not, this result axis is not
+ to be derived from any target axis, and it will therefore be left with its
+ default attributes. Make an entry in the appropriate permutation array to
+ indicate that this result axis is unassociated. */
+ if ( ( target_axis < 0 ) || ( target_axis >= target_naxes ) ) {
+ outperm[ result_axis ] = -1;
+
+/* Otherwise, obtain a pointer to the target Axis object and modify the
+ temporary Frame so that its axis is associated with the same Axis object.
+ Annul the Axis pointer afterwards. */
+ } else {
+ newaxis = astGetAxis( target, target_axis );
+ astSetAxis( tempframe, result_axis, newaxis );
+ newaxis = astAnnul( newaxis );
+
+/* Update both permutation arrays to record the association between the target
+ and result axes. */
+ outperm[ result_axis ] = target_axis;
+ inperm[ target_axis ] = result_axis;
+ }
+
+/* Quit looping if an error occurs. */
+ if ( !astOK ) break;
+ }
+
+/* So far, we have only modified pointers in the temporary Frame to refer to
+ the target Frame's Axis objects. Since we will next modify these objects'
+ attributes, we must make a deep copy of the entire temporary Frame so that
+ we do not modify the target's axes. This copy now becomes our result Frame.
+ Annul the temporary one. */
+ if ( astOK ) {
+ *result = astCopy( tempframe );
+ tempframe = astAnnul( tempframe );
+
+/* Invoke the target "astOverlay" method to overlay any remaining
+ attributes from the target Frame which are not associated with
+ individual axes (e.g. the Frame's Title and Domain). */
+ astOverlay( target, target_axes, *result );
+
+/* If a template Frame was supplied, also invoke its astOverlay method to
+ overlay its attributes on the result Frame. (Note that in this particular
+ case this has no effect other than transferring attributes. In general,
+ however, i.e. in derived classes, this process is vital to determining the
+ mapping below, whose main purpose is to convert between the target and
+ result Frames. These will have different attributes as a result of the
+ influence that the template has here.) */
+ if ( template ) astOverlay( template, template_axes, *result );
+
+/* We will next generate the Mapping that relates the target and result
+ Frames. If appropriate this should be a unit Mapping (UnitMap), so test if
+ the number of axes in both Frames is equal. */
+ unit = ( target_naxes == result_naxes );
+
+/* If so, check the contents of one of the permutation arrays to see if all
+ result axes are associated with the corresponding target axis (the converse
+ then also follows). If not, note this fact and quit checking. */
+ if ( unit ) {
+ for ( result_axis = 0; result_axis < result_naxes;
+ result_axis++ ) {
+ if ( outperm[ result_axis ] != result_axis ) {
+ unit = 0;
+ break;
+ }
+ }
+ }
+
+/* If a unit Mapping is appropriate, then construct it. */
+ if ( unit ) {
+ *map = (AstMapping *) astUnitMap( result_naxes, "", status );
+
+/* Otherwise, construct a Mapping describing the axis permutation we have
+ produced. */
+ } else {
+ *map = (AstMapping *) astPermMap( target_naxes, inperm,
+ result_naxes, outperm, NULL,
+ "", status );
+ }
+
+/* Note that coordinate conversion is possible. */
+ match = 1;
+
+/* If the ActiveUnit flag in both template and result Frame is non-zero, we
+ now modify the Mapping to take account of any differences in the Units
+ attributes of the target and results Frames. */
+ if( template && astGetActiveUnit( template ) &&
+ astGetActiveUnit( *result ) ) {
+
+/* Loop round the axes of the results Frame, accumulating a parallel CmpMap
+ ("umap") in which each Mapping is the 1-D Mapping which transforms the
+ Units of the corresponding target axis into the Units of the results
+ axis. */
+ umap = NULL;
+ uunit = 1;
+ for( result_axis = 0; result_axis < result_naxes; result_axis++ ) {
+
+/* Find the index of the corresponding target axis. */
+ if( unit ) {
+ target_axis = result_axis;
+ } else {
+ target_axis = outperm[ result_axis ];
+ }
+
+/* Get the Unit string for both axes, and attempt to find a Mapping which
+ transforms values in the target units into the corresponding value in the
+ results units. If this results axis does not have a corresponding
+ target axis, then indicate that no units mapping can be found. */
+ if( target_axis > -1 ) {
+ aumap = astUnitMapper( astGetUnit( target, target_axis ),
+ astGetUnit( *result, result_axis ),
+ NULL, NULL );
+ } else {
+ aumap = NULL;
+ }
+
+/* If no Mapping could be found, annull the Mapping and leave the loop.
+ Otherwise, see if the Mapping is a UnitMap. If not, set a flag to indicate
+ that we have at least one non-unit map. */
+ if( !aumap ) {
+ if( umap ) umap = astAnnul( umap );
+ match = 0;
+ break;
+ } else {
+ if( !astIsAUnitMap( aumap ) ) uunit = 0;
+ }
+
+/* Add this Mapping into the parallel CmpMap. */
+ if( umap ) {
+ numap = (AstMapping *) astCmpMap( umap, aumap, 0, "", status );
+ umap = astAnnul( umap );
+ aumap = astAnnul( aumap );
+ umap = numap;
+ } else {
+ umap = aumap;
+ }
+ }
+
+/* If the resulting CmpMap is not just a UnitMap, add it in series with
+ the current results mapping, and then simplify it. */
+ if( !uunit && umap ) {
+ numap = (AstMapping *) astCmpMap( *map, umap, 1, "", status );
+ (void) astAnnul( *map );
+ *map = numap;
+ }
+
+/* Annul the CmpMap containing the units Mappings. */
+ if( umap ) umap = astAnnul( umap );
+
+/* If the units could not bve matched annul the returned mapping. */
+ if( !match && *map ) *map = astAnnul( *map );
+ }
+ }
+ }
+
+/* Free the memory used for the permutation arrays. */
+ inperm = astFree( inperm );
+ outperm = astFree( outperm );
+
+/* If an error occurred, annul the returned objects and reset the returned
+ value. */
+ if ( !astOK ) {
+ *map = astAnnul( *map );
+ *result = astAnnul( *result );
+ match = 0;
+ }
+
+/* Return the result. */
+ return match;
+}
+
+static AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) {
+/*
+*+
+* Name:
+* astSystemCode
+
+* Purpose:
+* Convert a string into a coordinate system type code.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* AstSystemType SystemCode( AstFrame *this, const char *system )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function converts a string used for the external description of
+* a coordinate system into a Frame coordinate system type code (System
+* attribute value). It is the inverse of the astSystemString function.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* system
+* Pointer to a constant null-terminated string containing the
+* external description of the coordinate system.
+
+* Returned Value:
+* The System type code.
+
+* Notes:
+* - A value of AST__BADSYSTEM is returned if the coordinate system
+* description was not recognised. This does not produce an error.
+* - A value of AST__BADSYSTEM is also returned if this function
+* is invoked with the global error status set or if it should fail
+* for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstSystemType result; /* Result value to return */
+
+/* Initialise. */
+ result = AST__BADSYSTEM;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Match the "system" string against each possibility and assign the
+ result. The basic Frame class only supports a single system
+ "Cartesian". */
+ if ( astChrMatch( "Cartesian", system ) ) {
+ result = AST__CART;
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *SystemString( AstFrame *this, AstSystemType system, int *status ) {
+/*
+*+
+* Name:
+* astSystemString
+
+* Purpose:
+* Convert a coordinate system type code into a string.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* const char *astSystemString( AstFrame *this, AstSystemType system )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function converts a Frame coordinate system type code
+* (System attribute value) into a string suitable for use as an
+* external representation of the coordinate system type.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* system
+* The coordinate system type code.
+
+* Returned Value:
+* Pointer to a constant null-terminated string containing the
+* textual equivalent of the type code supplied.
+
+* Notes:
+* - A NULL pointer value is returned if the coordinate system
+* code was not recognised. This does not produce an error.
+* - A NULL pointer value is also returned if this function is
+* invoked with the global error status set or if it should fail
+* for any reason.
+*-
+*/
+
+/* Local Variables: */
+ const char *result; /* Pointer value to return */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Match the "system" value against each possibility and convert to a
+ string pointer. (Where possible, return the same string as would be
+ used in the FITS WCS representation of the coordinate system). A basic
+ Frame only allows a single System value, "Cartesian". */
+ switch ( system ) {
+ case AST__CART:
+ result = "Cartesian";
+ break;
+ }
+
+/* Return the result pointer. */
+ return result;
+
+}
+
+static int TestActiveUnit( AstFrame *this, int *status ){
+/*
+*+
+* Name:
+* astTestActiveUnit
+
+* Purpose:
+* Determines if the ActiveUnit flag is set.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astTestActiveUnit( AstFrame *this )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function tests the current value of the ActiveUnit flag for a
+* Frame. See the description of the astSetActiveUnit function for a
+* description of the ActiveUnit flag.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+
+* Returned Value:
+* Non-zero if the flag has been set. Zero otherwise.
+
+* Notes:
+* - A zero value will be returned if this function is
+* invoked with the AST error status set, or if it should fail for
+* any reason.
+*--
+*/
+
+/* Local Variables: */
+ int result; /* The returned value */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Return the result. */
+ return ( this->active_unit != -INT_MAX );
+}
+
+static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* TestAttrib
+
+* Purpose:
+* Test if a specified attribute value is set for a Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* int TestAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the astTestAttrib protected
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns a boolean result (0 or 1) to indicate whether
+* a value has been set for one of a Frame's attributes.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* attrib
+* Pointer to a null terminated string specifying the attribute
+* name. This should be in lower case with no surrounding white
+* space.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* One if a value has been set, otherwise zero.
+
+* Notes:
+* - This function uses one-based axis numbering so that it is
+* suitable for external (public) use.
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis */
+ AstFrame *pfrm; /* Pointer to primary Frame containing axis */
+ AstFrame *this; /* Pointer to the Frame structure */
+ char pfrm_attrib[ 100 ]; /* Primary Frame attribute */
+ char *axis_attrib; /* Pointer to axis attribute name */
+ const char *old_attrib; /* Pointer to supplied attribute name string */
+ int axis; /* Frame axis number */
+ int axis_nc; /* No. characters in axis attribute name */
+ int free_axis_attrib; /* Should axis_attrib be freed? */
+ int has_axis; /* Does attrib name include axis specifier? */
+ int len; /* Length of attrib string */
+ int nc; /* No. characters read by astSscanf */
+ int oldrep; /* Original error reporting state */
+ int paxis; /* Axis index within primary frame */
+ int result; /* Result value to return */
+ int used; /* Could the setting string be used? */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_object;
+
+/* Set a flag indicating if the attribute name includes an axis
+ specifier. */
+ has_axis = ( strchr( attrib, '(' ) != NULL );
+
+/* A flag indicating that we do not need to free the axis_attrib memory. */
+ free_axis_attrib = 0;
+
+/* Initialise things to avoid compiler warnings. */
+ axis_attrib = NULL;
+ old_attrib = NULL;
+
+/* Jump back to here if we are trying the same attribute but with an explicit
+ axis "(1)" added to the end of the name. */
+L1:
+
+/* Obtain the length of the attrib string. */
+ len = strlen( attrib );
+
+/* Check the attribute name and test the appropriate attribute. */
+
+/* Digits. */
+/* ------- */
+ if ( !strcmp( attrib, "digits" ) ) {
+ result = astTestDigits( this );
+
+/* Digits(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "digits(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+
+/* There is no function to test the Digits attribute for an axis
+ directly, so obtain a pointer to the Axis and use this to test the
+ attribute. */
+ (void) astValidateAxis( this, axis - 1, 1, "astTestDigits(axis)" );
+ ax = astGetAxis( this, axis - 1 );
+ result = astTestAxisDigits( ax );
+ ax = astAnnul( ax );
+
+/* Direction(axis). */
+/* ---------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "direction(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astTestDirection( this, axis - 1 );
+
+/* Epoch. */
+/* ------ */
+ } else if ( !strcmp( attrib, "epoch" ) ) {
+ result = astTestEpoch( this );
+
+/* Bottom(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "bottom(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astTestBottom( this, axis - 1 );
+
+/* Top(axis). */
+/* ---------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "top(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astTestTop( this, axis - 1 );
+
+/* Domain. */
+/* ------- */
+ } else if ( !strcmp( attrib, "domain" ) ) {
+ result = astTestDomain( this );
+
+/* Format(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "format(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astTestFormat( this, axis - 1 );
+
+/* Label(axis). */
+/* ------------ */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "label(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astTestLabel( this, axis - 1 );
+
+/* MatchEnd. */
+/* --------- */
+ } else if ( !strcmp( attrib, "matchend" ) ) {
+ result = astTestMatchEnd( this );
+
+/* MaxAxes. */
+/* -------- */
+ } else if ( !strcmp( attrib, "maxaxes" ) ) {
+ result = astTestMaxAxes( this );
+
+/* MinAxes. */
+/* -------- */
+ } else if ( !strcmp( attrib, "minaxes" ) ) {
+ result = astTestMinAxes( this );
+
+/* Permute. */
+/* -------- */
+ } else if ( !strcmp( attrib, "permute" ) ) {
+ result = astTestPermute( this );
+
+/* PreserveAxes. */
+/* ------------- */
+ } else if ( !strcmp( attrib, "preserveaxes" ) ) {
+ result = astTestPreserveAxes( this );
+
+/* Symbol(axis). */
+/* ------------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "symbol(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astTestSymbol( this, axis - 1 );
+
+/* AlignSystem. */
+/* ------------ */
+ } else if ( !strcmp( attrib, "alignsystem" ) ) {
+ result = astTestAlignSystem( this );
+
+/* System. */
+/* ------- */
+ } else if ( !strcmp( attrib, "system" ) ) {
+ result = astTestSystem( this );
+
+/* Title. */
+/* ------ */
+ } else if ( !strcmp( attrib, "title" ) ) {
+ result = astTestTitle( this );
+
+/* Unit(axis). */
+/* ----------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( attrib, "unit(%d)%n", &axis, &nc ) )
+ && ( nc >= len ) ) {
+ result = astTestUnit( this, axis - 1 );
+
+/* ObsLat. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obslat" ) ) {
+ result = astTestObsLat( this );
+
+/* ObsLon. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obslon" ) ) {
+ result = astTestObsLon( this );
+
+/* ObsAlt. */
+/* ------- */
+ } else if ( !strcmp( attrib, "obsalt" ) ) {
+ result = astTestObsAlt( this );
+
+/* Dtai. */
+/* ---- */
+ } else if ( !strcmp( attrib, "dtai" ) ) {
+ result = astTestDtai( this );
+
+/* Dut1. */
+/* ---- */
+ } else if ( !strcmp( attrib, "dut1" ) ) {
+ result = astTestDut1( this );
+
+/* Read-only attributes. */
+/* --------------------- */
+/* Test if the attribute name matches any of the read-only attributes
+ of this class. If it does, then return zero. */
+ } else if ( !strcmp( attrib, "naxes" ) ||
+ !strncmp( attrib, "normunit", 8 ) ||
+ !strncmp( attrib, "internalunit", 12 ) ) {
+ result = 0;
+
+/* Other axis attributes. */
+/* ---------------------- */
+/* If the attribute was not identified above, but appears to refer to
+ a Frame axis, then it may refer to an Axis object of a derived type
+ (which has additional attributes not recognised here). */
+ } else if ( !free_axis_attrib && ( nc = 0,
+ ( 1 == astSscanf( attrib, "%*[^()]%n(%d)%n",
+ &axis_nc, &axis, &nc ) )
+ && ( nc >= len ) ) ) {
+
+/* Validate the axis index and extract the attribute name. */
+ (void) astValidateAxis( this, axis - 1, 1, "astTest" );
+ axis_attrib = astString( attrib, axis_nc );
+
+/* Obtain a pointer to the Axis object. */
+ ax = astGetAxis( this, axis - 1 );
+ if( astOK ) {
+
+/* Assume that we will be able to use the attribute name. */
+ used = 1;
+
+/* Temporarily switch off error reporting so that if the following attempt
+ to access the axis attribute fails, we can try to interpret the
+ attribute name as an attribute of the primary Frame containing the
+ specified axis. Any errors reported in this context will simply be
+ ignored, in particularly they are not deferred for later delivery. */
+ oldrep = astReporting( 0 );
+
+/* Use the Axis astTestAttrib method to test the attribute value. */
+ result = astTestAttrib( ax, axis_attrib );
+
+/* If the above call failed with a status of AST__BADAT, indicating that
+ the attribute name was not recognised, clear the status so that we can
+ try to interpret the attribute name as an attribute of the primary Frame
+ containing the specified axis. */
+ if( astStatus == AST__BADAT ) {
+ astClearStatus;
+
+/* Find the primary Frame containing the specified axis. */
+ astPrimaryFrame( this, axis - 1, &pfrm, &paxis );
+
+/* Only attempt to use the primary Frame if it is not the same as "this"
+ - otherwise we could end up in an infinite loop. */
+ if( pfrm != this ) {
+
+/* astPrimaryFrame returns the original - unpermuted - axis index within
+ the primary Frame. So we need to take into account any axis permutation
+ which has been applied to the primary Frame when forming the attribute name
+ to use below. Find the permuted (external) axis index which corresponds to
+ the internal (unpermuted) axis index "paxis". */
+ paxis = astValidateAxis( pfrm, paxis, 0, "astTest" );
+
+/* Modify the attribute name to refer to the axis numbering of the
+ primary frame. */
+ sprintf( pfrm_attrib, "%s(%d)", axis_attrib, paxis + 1 );
+
+/* Attempt to test the attribute as an attribute of the primary Frame. */
+ result = astTestAttrib( pfrm, pfrm_attrib );
+
+/* If this failed, clear the status and indicate that we have not managed to
+ use the attribute name. */
+ if( !astOK ) {
+ astClearStatus;
+ used = 0;
+ }
+
+ } else {
+ used = 0;
+ }
+
+/* If not found attempt to test the attribute value in the Axis, omitting
+ the axis index. */
+ if( ! used ) {
+ result = astTestAttrib( pfrm, axis_attrib );
+ if( !astOK ) {
+ astClearStatus;
+ } else {
+ used = 1;
+ }
+ }
+
+/* Annul the primary Frame pointer. */
+ pfrm = astAnnul( pfrm );
+ }
+
+/* Re-instate the original error reporting state. */
+ astReporting( oldrep );
+
+/* If we could not use the attribute name, attempt to test the axis
+ attribute again, this time retaining the error report. This is done
+ to ensure the user gets an appropriate error message. */
+ if( !used ) result = astTestAttrib( ax, axis_attrib );
+ }
+
+/* Annul the Axis pointer and free the memory holding the attribute
+ name. */
+ ax = astAnnul( ax );
+ axis_attrib = astFree( axis_attrib );
+
+/* Not recognised. */
+/* --------------- */
+/* If the attribute is still not recognised, and the Frame has only 1 axis,
+ and the attribute name does not already include an axis specifier, try
+ again after appending "(1)" to the end of the attribute name. */
+ } else if( !has_axis && astGetNaxes( this ) == 1 ) {
+
+/* Take a copy of the supplied name, allowing 3 extra characters for the
+ axis specifier "(1)". */
+ axis_attrib = astMalloc( len + 4 );
+ if( axis_attrib ) memcpy( axis_attrib, attrib, len );
+
+/* Indicate we should free the axis_attrib memory. */
+ free_axis_attrib = 1;
+
+/* Add in the axis specifier. */
+ strcpy( axis_attrib + len, "(1)" );
+
+/* Use the new attribute name instead of the supplied name. */
+ old_attrib = attrib;
+ attrib = axis_attrib;
+
+/* Indicate the attribute name now has an axis specifier. */
+ has_axis = 1;
+
+/* Jump back to try interpreting the new attribute name. */
+ goto L1;
+
+/* Not recognised. */
+/* --------------- */
+/* If the attribute name is still not recognised, pass it on to the parent
+ method for further interpretation. First re-instate the original attrib
+ name string if it was changed above. */
+ } else {
+ if( free_axis_attrib ) {
+ attrib = old_attrib;
+ axis_attrib = astFree( axis_attrib );
+ }
+ result = (*parent_testattrib)( this_object, attrib, status );
+ }
+
+/* Return the result, */
+ return result;
+}
+
+static AstPointSet *Transform( AstMapping *this_mapping, AstPointSet *in,
+ int forward, AstPointSet *out, int *status ) {
+/*
+* Name:
+* Transform
+
+* Purpose:
+* Use a Frame to transform a set of points.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "frame.h"
+* AstPointSet *Transform( AstMapping *this, AstPointSet *in,
+* int forward, AstPointSet *out, int *status )
+
+* Class Membership:
+* Frame member function (over-rides the astTransform method inherited
+* from the Mapping class).
+
+* Description:
+* This function takes a Frame and a set of points encapsulated in a
+* PointSet and transforms the points so as to perform the identity
+* transformation (i.e. simply copies the coordinate values).
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* in
+* Pointer to the PointSet holding the input coordinate data.
+* forward
+* A non-zero value indicates that the forward coordinate transformation
+* should be applied, while a zero value requests the inverse
+* transformation. In this case, both transformations are equivalent.
+* out
+* Pointer to a PointSet which will hold the transformed (output)
+* coordinate values. A NULL value may also be given, in which case a
+* new PointSet will be created by this function.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the output (possibly new) PointSet.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+* - The number of coordinate values per point in the input PointSet must
+* match the number of coordinates for the Frame being applied. This number
+* will be equal to the number of Frame axes.
+* - If an output PointSet is supplied, it must have space for sufficient
+* number of points and coordinate values per point to accommodate the
+* result. Any excess space will be ignored.
+*/
+
+/* Local Variables: */
+ AstFrame *this; /* Pointer to the Frame structure */
+ AstPointSet *result; /* Pointer value to be returned */
+ AstUnitMap *unitmap; /* Pointer to temporary UnitMap */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_mapping;
+
+/* Create a unit Mapping with one coordinate for each Frame axis. */
+ unitmap = astUnitMap( astGetNaxes( this ), "", status );
+
+/* Use the Mapping to transform (i.e. copy) the coordinate values. */
+ result = astTransform( unitmap, in, forward, out );
+
+/* Annul the Mapping. */
+ unitmap = astAnnul( unitmap );
+
+/* If an error occurred and a new PointSet may have been created, then annul
+ the result. In any case, ensure that a NULL pointer is returned. */
+ if ( !astOK ) {
+ if ( !out ) result = astAnnul( result );
+ result = NULL;
+ }
+
+/* Return the result pointer. */
+ return result;
+}
+
+static int Unformat( AstFrame *this, int axis, const char *string,
+ double *value, int *status ) {
+/*
+*+
+* Name:
+* astUnformat
+
+* Purpose:
+* Read a formatted coordinate value for a Frame axis.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astUnformat( AstFrame *this, int axis, const char *string,
+* double *value )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function reads a formatted coordinate value for a Frame
+* axis (supplied as a string) and returns the equivalent numerical
+* value as a double. It also returns the number of characters read
+* from the string.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the Frame axis for which the coordinate value
+* is to be read (axis numbering starts at zero for the first
+* axis).
+* string
+* Pointer to a constant null-terminated string containing the
+* formatted coordinate value.
+* value
+* Pointer to a double in which the coordinate value read will be
+* returned.
+
+* Returned Value:
+* The number of characters read from the string to obtain the
+* coordinate value.
+
+* Notes:
+* - Any white space at the beginning of the string will be
+* skipped, as also will any trailing white space following the
+* coordinate value read. The function's return value will reflect
+* this.
+* - A function value of zero (and no coordinate value) will be
+* returned, without error, if the string supplied does not contain
+* a suitably formatted value.
+* - The string "<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.
+*-
+
+* Implementation Notes:
+* - This function implements the basic astUnformat method
+* available via the protected interface to the Frame class. The
+* public interface to this method is provided by the
+* astUnformatId_ function.
+*/
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis object */
+ const char *label; /* Pointer to axis label string */
+ double coord; /* Coordinate value read */
+ int digits_set; /* Axis Digits attribute set? */
+ int nc; /* Number of characters read */
+ int status_value; /* AST error status */
+
+/* Initialise. */
+ nc = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return nc;
+
+/* Validate the axis index and obtain a pointer to the required Axis. */
+ (void) astValidateAxis( this, axis, 1, "astUnformat" );
+ ax = astGetAxis( this, axis );
+
+/* Test if any Axis attributes which may affect the result are
+ undefined (i.e. have not been explicitly set). If so, we over-ride
+ them, giving them temporary values dictated by the Frame. Only the
+ Digits attribute is potentially relevant here. */
+ digits_set = astTestAxisDigits( ax );
+ if ( !digits_set ) astSetAxisDigits( ax, astGetDigits( this ) );
+
+/* Read the coordinate value. */
+ if ( astOK ) {
+ nc = astAxisUnformat( ax, string, &coord );
+
+/* If an error occurred, save and temporarily clear the global error
+ status while the axis Label string is obtained. Then restore the
+ original error status value afterwards. */
+ if ( !astOK ) {
+ status_value = astStatus;
+ astClearStatus;
+ label = astGetLabel( this, axis );
+ astSetStatus( status_value );
+
+/* Report a contextual error message containing the axis label. */
+ astError( status_value, "%s(%s): Unable to read \"%s\" value.", status,
+ "astUnformat", astGetClass( this ), label );
+ }
+ }
+
+/* Clear any Axis attributes that were temporarily over-ridden. */
+ if ( !digits_set ) astClearAxisDigits( ax );
+
+/* Annul the Axis pointer. */
+ ax = astAnnul( ax );
+
+/* If an error occurred, clear the count of characters read. */
+ if ( !astOK ) {
+ nc = 0;
+
+/* Otherwise, if characters were read, return the coordinate value. */
+ } else if ( nc ) {
+ *value = coord;
+ }
+
+/* Return the number of characters read. */
+ return nc;
+}
+
+static int ValidateAxis( AstFrame *this, int axis, int fwd, const char *method,
+ int *status ) {
+/*
+*+
+* Name:
+* astValidateAxis
+
+* Purpose:
+* Validate and permute a Frame's axis index.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astValidateAxis( AstFrame *this, int axis, int fwd,
+* const char *method )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function checks the validity of an index (zero-based) which
+* is to be used to address one of the coordinate axes of a
+* Frame. If the index is valid, it is permuted using the axis
+* permutation array associated with the Frame and the (zero-based)
+* permuted axis index is returned. This gives the location of the
+* required axis information within the Frame's internal arrays. If
+* the axis index supplied is not valid, an error is reported and
+* the global error status is set.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The axis index (zero-based) to be checked. To be valid, it
+* must lie between zero and (naxes-1) inclusive, where "naxes"
+* is the number of coordinate axes associated with the Frame.
+* fwd
+* If non-zero, the suppplied axis index is assumed to be an
+* "external" axis index, and the corresponding "internal" axis index
+* is returned as the function value. Otherwise, the suppplied axis
+* index is assumed to be an "internal" axis index, and the
+* corresponding "external" axis index is returned as the function
+* value.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate an axis index. This method name is used solely
+* for constructing error messages.
+
+* Returned Value:
+* The permuted axis index - either "internal" or "external" as
+* specified by "fwd".
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+* - Error messages issued by this function refer to the public
+* numbering system used for axes which is one-based (zero-based axis
+* indices are used internally).
+*-
+*/
+
+/* Local Variables: */
+ const int *perm; /* Pointer to axis permutation array */
+ int naxes; /* Number of Frame axes */
+ int result; /* Permuted axis index */
+
+/* Initialise. */
+ result = 0;
+
+/* Determine the number of Frame axes. */
+ naxes = astGetNaxes( this );
+ if ( astOK ) {
+
+/* If the Frame has no axes, report an error (note we convert to
+ one-based axis numbering in the error message). */
+ if ( naxes == 0 ) {
+ astError( AST__AXIIN, "%s(%s): Invalid attempt to use an axis index "
+ "(%d) for a %s which has no axes.", status, method,
+ astGetClass( this ), axis + 1, astGetClass( this ) );
+
+/* Otherwise, check the axis index for validity and report an error if
+ it is not valid (again, use one-based axis numbering). */
+ } else if ( ( axis < 0 ) || ( axis >= naxes ) ) {
+ astError( AST__AXIIN, "%s(%s): Axis index (%d) invalid - it should "
+ "be in the range 1 to %d.", status, method, astGetClass( this ),
+ axis + 1, naxes );
+
+/* If the axis index was valid, obtain the axis permutation array and
+ use this to generate the permuted axis value. */
+ } else {
+ perm = astGetPerm( this );
+ if( perm ) {
+
+/* External to internal is a simple look-up. */
+ if( fwd ) {
+ result = perm[ axis ];
+
+/* Internal to external requires a search through the permutation array. */
+ } else {
+ for( result = 0; result < naxes; result++ ) {
+ if( perm[ result ] == axis ) break;
+ }
+ }
+ }
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static void ValidateAxisSelection( AstFrame *this, int naxes, const int *axes,
+ const char *method, int *status ) {
+/*
+*+
+* Name:
+* astValidateAxisSelection
+
+* Purpose:
+* Check that a set of axes selected from a Frame is valid.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* void astValidateAxisSelection( AstFrame *this, int naxes,
+* const int *axes, const char *method )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function checks the validity of an array of (zero-based)
+* axis indices that specify a set of axes to be selected from a
+* Frame. To be valid, no axis should be selected more than
+* once. In assessing this, any axis indices that do not refer to
+* valid Frame axes (e.g. are set to -1) are ignored.
+*
+* If the axis selection is valid, this function returns without further
+* action. Otherwise, an error is reported and the global error status is
+* set.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* naxes
+* The number of axes to be selected (may be zero).
+* axes
+* Pointer to an array of int with naxes elements that contains the
+* (zero based) axis indices to be checked.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate an axis selection. This method name is used
+* solely for constructing error messages.
+*-
+*/
+
+/* Local Variables: */
+ int *count; /* Pointer to temporary array of counts */
+ int axis; /* Loop counter for selected axes */
+ int frame_axis; /* Loop counter for Frame axes */
+ int frame_naxes; /* Number of Frame axes */
+ int valid; /* Axis selection valid? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Check to see if no axes have been selected. If so, there is nothing to
+ do. */
+ if ( naxes ) {
+
+/* Initialise. */
+ valid = 1;
+
+/* Obtain the number of Frame axes and allocate an array of int with
+ one element for each Frame axis. This will store a count of the
+ number of times each axis is selected. */
+ frame_naxes = astGetNaxes( this );
+ count = astMalloc( sizeof( int ) * (size_t) frame_naxes );
+ if ( astOK ) {
+
+/* Initialise the array of counts to zero. */
+ for ( frame_axis = 0; frame_axis < frame_naxes; frame_axis++ ) {
+ count[ frame_axis ] = 0;
+ }
+
+/* Loop through each selected axis. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+ frame_axis = axes[ axis ];
+
+/* Check if the selected axis index is valid for the Frame. If so, increment
+ the selection count for that Frame axis. */
+ if ( ( frame_axis >= 0 ) && ( frame_axis < frame_naxes ) ) {
+ count[ frame_axis ]++;
+ }
+ }
+
+/* Loop through the count array and check that no Frame axis was selected
+ more than once. If it was, clear the "valid" flag and quit checking. */
+ for ( frame_axis = 0; frame_axis < frame_naxes; frame_axis++ ) {
+ if ( count[ frame_axis ] > 1 ) {
+ valid = 0;
+ break;
+ }
+ }
+ }
+
+/* Free the temporary count array. */
+ count = astFree( count );
+
+/* If no error has occurred, but the axis selection is not valid, then report
+ an error. */
+ if ( astOK && !valid ) {
+ astError( AST__SELIN, "%s(%s): Invalid axis selection - each axis "
+ "may be selected only once.", status, method, astGetClass( this ) );
+ }
+ }
+}
+
+static int ValidateSystem( AstFrame *this, AstSystemType system, const char *method, int *status ) {
+/*
+*+
+* Name:
+* astValidateSystem
+
+* Purpose:
+* Validate a value for a Frame's System attribute.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int astValidateSystem( AstFrame *this, AstSystemType system,
+* const char *method )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function checks the validity of the supplied system value.
+* If the value is valid, it is returned unchanged. Otherwise, an
+* error is reported and a value of AST__BADSYSTEM is returned.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* system
+* The system value to be checked.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate an axis index. This method name is used solely
+* for constructing error messages.
+
+* Returned Value:
+* The validated system value.
+
+* Notes:
+* - A value of AST_BADSYSTEM will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ AstSystemType result; /* Validated system value */
+
+/* Initialise. */
+ result = AST__BADSYSTEM;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* If the value is out of bounds, report an error. */
+ if ( system < FIRST_SYSTEM || system > LAST_SYSTEM ) {
+ astError( AST__AXIIN, "%s(%s): Bad value (%d) given for the System "
+ "or AlignSystem attribute of a %s.", status, method,
+ astGetClass( this ), (int) system, astGetClass( this ) );
+
+/* Otherwise, return the supplied value. */
+ } else {
+ result = system;
+ }
+
+/* Return the result. */
+ return result;
+}
+
+/* Functions which access class attributes. */
+/* ---------------------------------------- */
+/* Implement member functions to access the attributes associated with
+ the axes of a Frame using the private macros defined for this
+ purpose at the start of this file. */
+
+/*
+*att++
+* Name:
+* Naxes
+
+* Purpose:
+* Number of Frame axes.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer, read-only.
+
+* Description:
+* This is a read-only attribute giving the number of axes in a
+* Frame (i.e. the number of dimensions of the coordinate space
+* which the Frame describes). This value is determined when the
+* Frame is created.
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+* FrameSet
+* The Naxes attribute of a FrameSet is the same as that of its
+* current Frame (as specified by the Current attribute).
+* CmpFrame
+* The Naxes attribute of a CmpFrame is equal to the sum of the
+* Naxes values of its two component Frames.
+*att--
+*/
+
+
+/*
+*att++
+* Name:
+* Direction(axis)
+
+* Purpose:
+* Display axis in conventional direction?
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer (boolean).
+
+* Description:
+* This attribute is a boolean value which suggests how the axes of
+* a Frame should be displayed (e.g.) in graphical output. By
+* default, it has the value one, indicating that they should be
+* shown in the conventional sense (increasing left to right for an
+* abscissa, and bottom to top for an ordinate). If set to zero,
+* this attribute indicates that the direction should be reversed,
+* as would often be done for an astronomical magnitude or a right
+* ascension axis.
+
+* Applicability:
+* Frame
+* The default Direction value supplied by the Frame class is 1,
+* indicating that all axes should be displayed in the
+* conventional direction.
+* SkyFrame
+* The SkyFrame class re-defines the default Direction value to
+* suggest that certain axes (e.g. right ascension) should be
+* plotted in reverse when appropriate.
+* FrameSet
+* The Direction attribute of a FrameSet axis is the same as
+* that of its current Frame (as specified by the Current
+* attribute).
+* Plot
+* The Direction attribute of the base Frame in a Plot is set to
+* indicate the sense of the two graphics axes, as implied by the
+* graphics bounding box supplied when the Plot was created.
+
+* Notes:
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+* - The Direction attribute does not directly affect the behaviour
+* of the AST library. Instead, it serves as a hint to applications
+* programs about the orientation in which they may wish to display
+* any data associated with the Frame. Applications are free to
+* ignore this hint if they wish.
+*att--
+*/
+/* This simply provides an interface to the Axis methods for accessing
+ the Direction flag. */
+MAKE_CLEAR(Direction)
+MAKE_GET(Direction,int,0,0,0)
+MAKE_SET(Direction,int)
+MAKE_TEST(Direction)
+
+/*
+*att++
+* Name:
+* Dtai
+
+* Purpose:
+* The TAI-UTC correction.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Floating point.
+
+* Description:
+* This attribute specifies the difference between TAI and UTC (i.e.
+* the number of leap seconds) at the moment corresponding to the
+* Frame's Epoch value. The default value of AST__BAD causes the
+* number of leap seconds to be determined from an internal look-up
+* table, which is kept up-to-date manually by the AST development team.
+* Therefore it is only necessary to assign a value to this attribute
+* if the version of AST in use is so old that it does not include all
+* leap seconds that occurred prior to the time represented by the
+* Frame's Epoch value.
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+
+*att--
+*/
+/* The TAI-UTC correction, in seconds. Has a value of AST__BAD when not set. */
+astMAKE_CLEAR(Frame,Dtai,dtai,AST__BAD)
+astMAKE_GET(Frame,Dtai,double,AST__BAD,(this->dtai))
+astMAKE_SET(Frame,Dtai,double,dtai,value)
+astMAKE_TEST(Frame,Dtai,( this->dtai != AST__BAD ))
+
+/*
+*att++
+* Name:
+* Dut1
+
+* Purpose:
+* The UT1-UTC correction.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Floating point.
+
+* Description:
+* This attribute is used when calculating the Local Apparent Sidereal
+* Time corresponding to SkyFrame's Epoch value (used when converting
+* positions to or from the "AzEl" system). It should be set to the
+* difference, in seconds, between the UT1 and UTC timescales at the
+* moment in time represented by the SkyFrame's Epoch attribute. The
+* value to use is unpredictable and depends on changes in the earth's
+* rotation speed. Values for UT1-UTC can be obtained from the
+* International Earth Rotation and Reference Systems Service
+* (IERS) at http://www.iers.org/.
+*
+* Currently, the correction is always less than 1 second. This is
+* ensured by the occasional introduction of leap seconds into the UTC
+* timescale. Therefore no great error will usually result if no value
+* is assigned to this attribute (in which case a default value of
+* zero is used). However, it is possible that a decision may be taken
+* at some time in the future to abandon the introduction of leap
+* seconds, in which case the DUT correction could grow to significant
+* sizes.
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+
+*att--
+*/
+/* The UT1-UTC correction, in seconds. Has a value of AST__BAD when not set
+ yielding a default value of 0.0. */
+astMAKE_CLEAR(Frame,Dut1,dut1,AST__BAD)
+astMAKE_GET(Frame,Dut1,double,0.0,(this->dut1 == AST__BAD ? 0.0 : this->dut1))
+astMAKE_SET(Frame,Dut1,double,dut1,value)
+astMAKE_TEST(Frame,Dut1,( this->dut1 != AST__BAD ))
+
+
+
+/*
+*att++
+* Name:
+* Epoch
+
+* Purpose:
+* Epoch of observation.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Floating point.
+
+* Description:
+* This attribute is used to qualify the coordinate systems described by
+* a Frame, by giving the moment in time when the coordinates are known
+* to be correct. Often, this will be the date of observation, and is
+* important in cases where coordinates systems move with respect to each
+* other over the course of time.
+*
+* The Epoch attribute is stored as a Modified Julian Date, but
+* when setting its value it may be given in a variety of
+* formats. See the "Input Formats" section (below) for details.
+* Strictly, the Epoch value should be supplied in the TDB timescale,
+* but for some purposes (for instance, for converting sky positions
+* between different types of equatorial system) the timescale is not
+* significant, and UTC may be used.
+
+* Input Formats:
+* The formats accepted when setting an Epoch value are listed
+* below. They are all case-insensitive and are generally tolerant
+* of extra white space and alternative field delimiters:
+*
+* - Besselian Epoch: Expressed in decimal years, with or without
+* decimal places ("B1950" or "B1976.13" for example).
+*
+* - Julian Epoch: Expressed in decimal years, with or without
+* decimal places ("J2000" or "J2100.9" for example).
+*
+* - Year: Decimal years, with or without decimal places ("1996.8"
+* for example). Such values are interpreted as a Besselian epoch
+* (see above) if less than 1984.0 and as a Julian epoch otherwise.
+*
+* - Julian Date: With or without decimal places ("JD 2454321.9" for
+* example).
+*
+* - Modified Julian Date: With or without decimal places
+* ("MJD 54321.4" for example).
+*
+* - Gregorian Calendar Date: With the month expressed either as an
+* integer or a 3-character abbreviation, and with optional decimal
+* places to represent a fraction of a day ("1996-10-2" or
+* "1996-Oct-2.6" for example). If no fractional part of a day is
+* given, the time refers to the start of the day (zero hours).
+*
+* - Gregorian Date and Time: Any calendar date (as above) but with
+* a fraction of a day expressed as hours, minutes and seconds
+* ("1996-Oct-2 12:13:56.985" for example). The date and time can be
+* separated by a space or by a "T" (as used by ISO8601 format).
+
+* Output Format:
+* When enquiring Epoch values, the format used is the "Year"
+* format described under "Input Formats". This is a value in
+* decimal years which will be a Besselian epoch if less than
+* 1984.0 and a Julian epoch otherwise. By omitting any character
+* prefix, this format allows the Epoch value to be obtained as
+* either a character string or a floating point value.
+
+* Applicability:
+* Frame
+* All Frames have this attribute. The basic Frame class provides
+* a default of J2000.0 (Julian) but makes no use of the Epoch value.
+* This is because the Frame class does not distinguish between
+* different Cartesian coordinate systems (see the System attribute).
+* CmpFrame
+* The default Epoch value for a CmpFrame is selected as follows;
+* if the Epoch attribute has been set in the first component Frame
+* then the Epoch value from the first component Frame is used as
+* the default for the CmpFrame. Otherwise, if the Epoch attribute has
+* been set in the second component Frame then the Epoch value from the
+* second component Frame is used as the default for the CmpFrame.
+* Otherwise, the default Epoch value from the first component
+* Frame is used as the default for the CmpFrame. When the Epoch
+* attribute of a CmpFrame is set or cleared, it is also set or
+* cleared in the two component Frames.
+* FrameSet
+* The Epoch attribute of a FrameSet is the same as that of its current
+* Frame (as specified by the Current attribute).
+* SkyFrame
+* The coordinates of sources within a SkyFrame can change with time
+* for various reasons, including: (i) changing aberration of light
+* caused by the observer's velocity (e.g. due to the Earth's motion
+* around the Sun), (ii) changing gravitational deflection by the Sun
+* due to changes in the observer's position with time, (iii) fictitious
+* motion due to rotation of non-inertial coordinate systems (e.g. the
+* old FK4 system), and (iv) proper motion of the source itself (although
+* this last effect is not handled by the SkyFrame class because it
+* affects individual sources rather than the coordinate system as
+* a whole).
+*
+* The default Epoch value in a SkyFrame is B1950.0 (Besselian) for the
+* old FK4-based coordinate systems (see the System attribute) and
+* J2000.0 (Julian) for all others.
+*
+* Care must be taken to distinguish the Epoch value, which relates to
+* motion (or apparent motion) of the source, from the superficially
+* similar Equinox value. The latter is used to qualify a coordinate
+* system which is itself in motion in a (notionally) predictable way
+* as a result of being referred to a slowly moving reference plane
+* (e.g. the equator).
+*
+* See the description of the System attribute for details of which
+* qualifying attributes apply to each celestial coordinate system.
+* TimeFrame
+* A TimeFrame describes a general time axis and so cannot be completely
+* characterised by a single Epoch value. For this reason the TimeFrame
+* class makes no use of the Epoch attribute. However, user code can
+* still make use of the attribute if necessary to represent a "typical"
+* time spanned by the TimeFrame. The default Epoch value for a TimeFrame
+* will be the TDB equivalent of the current value of the TimeFrame's
+* TimeOrigin attribute. If no value has been set for TimeOrigin,
+* then the default Epoch value is J2000.0.
+*att--
+*/
+/* Clear the Epoch value by setting it to AST__BAD. */
+astMAKE_CLEAR(Frame,Epoch,epoch,AST__BAD)
+
+/* Provide a default value of J2000.0 setting. */
+astMAKE_GET(Frame,Epoch,double,AST__BAD,(
+ ( this->epoch != AST__BAD ) ? this->epoch : palEpj2d( 2000.0 )))
+
+/* Allow any Epoch value to be set. */
+astMAKE_SET(Frame,Epoch,double,epoch,value)
+
+/* An Epoch value is set if it is not equal to AST__BAD. */
+astMAKE_TEST(Frame,Epoch,( this->epoch != AST__BAD ))
+
+/*
+*att++
+* Name:
+* Top(axis)
+
+* Purpose:
+* Highest axis value to display
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Floating point.
+
+* Description:
+* This attribute gives the highest axis value to be displayed (for
+c instance, by the astGrid method).
+f instance, by the AST_GRID method).
+
+* Applicability:
+* Frame
+* The default supplied by the Frame class is to display all axis
+* values, without any limit.
+* SkyFrame
+* The SkyFrame class re-defines the default Top value to +90 degrees
+* for latitude axes, and 180 degrees for co-latitude axes. The
+* default for longitude axes is to display all axis values.
+
+* Notes:
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+*att--
+*/
+/* This simply provides an interface to the Axis methods for accessing
+ the Top value. */
+MAKE_CLEAR(Top)
+MAKE_GET(Top,double,DBL_MAX,0,DBL_MAX)
+MAKE_SET(Top,double)
+MAKE_TEST(Top)
+
+/*
+*att++
+* Name:
+* Bottom(axis)
+
+* Purpose:
+* Lowest axis value to display
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Floating point.
+
+* Description:
+* This attribute gives the lowest axis value to be displayed (for
+c instance, by the astGrid method).
+f instance, by the AST_GRID method).
+
+* Applicability:
+* Frame
+* The default supplied by the Frame class is to display all axis
+* values, without any limit.
+* SkyFrame
+* The SkyFrame class re-defines the default Bottom value to -90 degrees
+* for latitude axes, and 0 degrees for co-latitude axes. The
+* default for longitude axes is to display all axis values.
+
+* Notes:
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+*att--
+*/
+/* This simply provides an interface to the Axis methods for accessing
+ the Bottom value. */
+MAKE_CLEAR(Bottom)
+MAKE_GET(Bottom,double,-DBL_MAX,0,-DBL_MAX)
+MAKE_SET(Bottom,double)
+MAKE_TEST(Bottom)
+
+/*
+*att++
+* Name:
+* Format(axis)
+
+* Purpose:
+* Format specification for axis values.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute specifies the format to be used when displaying
+* coordinate values associated with a particular Frame axis
+* (i.e. to convert values from binary to character form). It is
+c interpreted by the astFormat function and determines the
+f interpreted by the AST_FORMAT function and determines the
+* formatting which it applies.
+*
+* If no Format value is set for a Frame axis, a default value is
+* supplied instead. This is based on the value of the Digits, or
+* Digits(axis), attribute and is chosen so that it displays the
+* requested number of digits of precision.
+
+* Applicability:
+* Frame
+* The Frame class interprets this attribute as a format
+* specification string to be passed to the C "printf" function
+* (e.g. "%1.7G") in order to format a single coordinate value
+* (supplied as a double precision number).
+c
+c When supplying a value for this attribute, beware that the
+c "%" character may be interpreted directly as a format
+c specification by some printf-like functions (such as
+c astSet). You may need to double it (i.e. use "%%") to avoid
+c this.
+* SkyFrame
+* The SkyFrame class re-defines the syntax and default value of
+* the Format string to allow the formatting of sexagesimal
+* values as appropriate for the particular celestial coordinate
+* system being represented. The syntax of SkyFrame Format
+* strings is described (below) in the "SkyFrame Formats"
+* section.
+* FrameSet
+* The Format attribute of a FrameSet axis is the same as that
+* of its current Frame (as specified by the Current
+* attribute). Note that the syntax of the Format string is also
+* determined by the current Frame.
+* TimeFrame
+* The TimeFrame class extends the syntax of the Format string to
+* allow the formatting of TimeFrame axis values as Gregorian calendar
+* dates and times. The syntax of TimeFrame Format strings is described
+* (below) in the "TimeFrame Formats" section.
+
+* SkyFrame Formats:
+* The Format string supplied for a SkyFrame should contain zero or
+* more of the following characters. These may occur in any order,
+* but the following is recommended for clarity:
+*
+* - "+": Indicates that a plus sign should be prefixed to positive
+* values. By default, no plus sign is used.
+*
+* - "z": Indicates that leading zeros should be prefixed to the
+* value so that the first field is of constant width, as would be
+* required in a fixed-width table (leading zeros are always
+* prefixed to any fields that follow). By default, no leading
+* zeros are added.
+*
+* - "i": Use the standard ISO field separator (a colon) between
+* fields. This is the default behaviour.
+*
+* - "b": Use a blank to separate fields.
+*
+* - "l": Use a letter ("h"/"d", "m" or "s" as appropriate) to
+* separate fields.
+*
+* - "g": Use a letter and symbols to separate fields ("h"/"d", "m" or "s",
+* etc, as appropriate), but include escape sequences in the formatted
+* value so that the Plot class will draw the separators as small
+* super-scripts.
+c The default escape sequences are optimised for the pgplot graphics
+c package, but new escape sequences may be specified using function
+c astSetSkyDelim.
+*
+* - "d": Include a degrees field. Expressing the angle purely in
+* degrees is also the default if none of "h", "m", "s" or "t" are
+* given.
+*
+* - "h": Express the angle as a time and include an hours field
+* (where 24 hours correspond to 360 degrees). Expressing the angle
+* purely in hours is also the default if "t" is given without
+* either "m" or "s".
+*
+* - "m": Include a minutes field. By default this is not included.
+*
+* - "s": Include a seconds field. By default this is not included.
+* This request is ignored if "d" or "h" is given, unless a minutes
+* field is also included.
+*
+* - "t": Express the angle as a time (where 24 hours correspond to
+* 360 degrees). This option is ignored if either "d" or "h" is
+* given and is intended for use where the value is to be expressed
+* purely in minutes and/or seconds of time (with no hours
+* field). If "t" is given without "d", "h", "m" or "s" being
+* present, then it is equivalent to "h".
+*
+* - ".": Indicates that decimal places are to be given for the
+* final field in the formatted string (whichever field this
+* is). The "." should be followed immediately by an unsigned
+* integer which gives the number of decimal places required, or by an
+* asterisk. If an asterisk is supplied, a default number of decimal
+* places is used which is based on the value of the Digits
+* attribute.
+*
+* All of the above format specifiers are case-insensitive. If
+* several characters make conflicting requests (e.g. if both "i"
+* and "b" appear), then the character occurring last takes
+* precedence, except that "d" and "h" always override "t".
+*
+* If the format string starts with a percentage sign (%), then the
+* whole format string is assumed to conform to the syntax defined by
+* the Frame class, and the axis values is formated as a decimal
+* radians value.
+
+* TimeFrame Formats:
+* The Format string supplied for a TimeFrame should either use the
+* syntax defined by the base Frame class (i.e. a C "printf" format
+* string), or the extended "iso" syntax described below (the default
+* value is inherited from the Frame class):
+*
+* - C "printf" syntax: If the Format string is a C "printf" format
+* description such as "%1.7G", the TimeFrame axis value will be
+* formatted without change as a floating point value using this format.
+* The formatted string will thus represent an offset from the zero point
+* specified by the TimeFrame's TimeOrigin attribute, measured in
+* units given by the TimeFrame's Unit attribute.
+*
+* - "iso" syntax: This is used to format a TimeFrame axis value as a
+* Gregorian date followed by an optional time of day. If the Format
+* value commences with the string "iso" then the TimeFrame axis value
+* will be converted to an absolute MJD, including the addition of the
+* current TimeOrigin value, and then formatted as a Gregorian date
+* using the format "yyyy-mm-dd". Optionally, the Format value may
+* include an integer precision following the "iso" specification (e.g.
+* "iso.2"), in which case the time of day will be appended to the
+* formatted date (if no time of day is included, the date field is
+* rounded to the nearest day). The integer value in the Format string
+* indicates the number of decimal places to use in the seconds field. For
+* instance, a Format value of "iso.0" produces a time of day of the form
+* "hh:mm:ss", and a Format value of "iso.2" produces a time of day of the
+* form "hh:mm:ss.ss". The date and time fields will be separated by a
+* space unless 'T' is appended to the end of string, in which case
+* the letter T (upper case) will be used as the separator. The value of
+* the Digits attribute is ignored when using this "iso" format.
+
+* Notes:
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+*att--
+*/
+/* This simply provides an interface to the Axis methods for accessing
+ the Format string. */
+MAKE_CLEAR(Format)
+MAKE_GET(Format,const char *,NULL,0,0)
+MAKE_SET(Format,const char *)
+MAKE_TEST(Format)
+
+/*
+*att++
+* Name:
+* Label(axis)
+
+* Purpose:
+* Axis label.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute specifies a label to be attached to each axis of
+* a Frame when it is represented (e.g.) in graphical output.
+*
+* If a Label value has not been set for a Frame axis, then a
+* suitable default is supplied.
+
+* Applicability:
+* Frame
+* The default supplied by the Frame class is the string "Axis
+* <n>", where <n> is 1, 2, etc. for each successive axis.
+* SkyFrame
+* The SkyFrame class re-defines the default Label value
+* (e.g. to "Right ascension" or "Galactic latitude") as
+* appropriate for the particular celestial coordinate system
+* being represented.
+* TimeFrame
+* The TimeFrame class re-defines the default Label value as
+* appropriate for the particular time system being represented.
+* FrameSet
+* The Label attribute of a FrameSet axis is the same as that of
+* its current Frame (as specified by the Current attribute).
+
+* Notes:
+* - Axis labels are intended purely for interpretation by human
+* readers and not by software.
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+*att--
+*/
+/* This provides an interface to the Axis methods for accessing the
+ Label string, but provides an alternative default Label based on
+ the axis number. This default string is written to the static
+ "label_buff" buffer and a pointer to this is returned if
+ required. */
+MAKE_CLEAR(Label)
+MAKE_GET(Label,const char *,NULL,1,GetDefaultLabel( axis, status ))
+MAKE_SET(Label,const char *)
+MAKE_TEST(Label)
+
+/*
+*att++
+* Name:
+* Symbol(axis)
+
+* Purpose:
+* Axis symbol.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute specifies a short-form symbol to be used to
+* represent coordinate values for a particular axis of a
+* Frame. This might be used (e.g.) in algebraic expressions where
+* a full description of the axis would be inappropriate. Examples
+* include "RA" and "Dec" (for Right Ascension and Declination).
+*
+* If a Symbol value has not been set for a Frame axis, then a
+* suitable default is supplied.
+
+* Applicability:
+* Frame
+* The default Symbol value supplied by the Frame class is the
+* string "<Domain><n>", where <n> is 1, 2, etc. for successive
+* axes, and <Domain> is the value of the Frame's Domain
+* attribute (truncated if necessary so that the final string
+* does not exceed 15 characters). If no Domain value has been
+* set, "x" is used as the <Domain> value in constructing this
+* default string.
+* SkyFrame
+* The SkyFrame class re-defines the default Symbol value
+* (e.g. to "RA" or "Dec") as appropriate for the particular
+* celestial coordinate system being represented.
+* TimeFrame
+* The TimeFrame class re-defines the default Symbol value as
+* appropriate for the particular time system being represented.
+* FrameSet
+* The Symbol attribute of a FrameSet axis is the same as that
+* of its current Frame (as specified by the Current attribute).
+
+* Notes:
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+*att--
+*/
+/* This provides an interface to the Axis methods for accessing the
+ Symbol string, but provides an alternative default Symbol based on
+ the axis number and the Frame's Domain (if defined, otherwise "x"
+ is used). This default string is written to the static
+ "symbol_buff" buffer and a pointer to this is returned if
+ required. */
+MAKE_CLEAR(Symbol)
+MAKE_GET(Symbol,const char *,NULL,1,GetDefaultSymbol( this, axis, status ) )
+MAKE_SET(Symbol,const char *)
+MAKE_TEST(Symbol)
+
+/*
+*att++
+* Name:
+* Unit(axis)
+
+* Purpose:
+* Physical units for formatted axis values
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute contains a textual representation of the physical
+* units used to represent formatted coordinate values on a particular
+* axis of a Frame.
+c The astSetActiveUnit function controls how the Unit values
+f The AST_SETACTIVEUNIT routine controls how the Unit values
+* are used.
+
+* Applicability:
+* Frame
+* The default supplied by the Frame class is an empty string.
+* SkyFrame
+* The SkyFrame class re-defines the default Unit value (e.g. to
+* "hh:mm:ss.sss") to describe the character string returned by
+c the astFormat function when formatting coordinate values.
+f the AST_FORMAT function when formatting coordinate values.
+* SpecFrame
+* The SpecFrame class re-defines the default Unit value so that it
+* is appropriate for the current System value. See the System
+* attribute for details. An error will be reported if an attempt
+* is made to use an inappropriate Unit.
+* TimeFrame
+* The TimeFrame class re-defines the default Unit value so that it
+* is appropriate for the current System value. See the System
+* attribute for details. An error will be reported if an attempt
+* is made to use an inappropriate Unit (e.g. "km").
+* FrameSet
+* The Unit attribute of a FrameSet axis is the same as that of
+* its current Frame (as specified by the Current attribute).
+
+* Notes:
+* - This attribute described the units used when an axis value is
+* formatted into a string using
+c astFormat.
+f AST_FORMAT.
+* In some cases these units may be different to those used to represent
+* floating point axis values within application code (for instance a
+* SkyFrame always uses radians to represent floating point axis values).
+* The InternalUnit attribute described the units used for floating
+* point values.
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+*att--
+*/
+/* This simply provides an interface to the Axis methods for accessing
+ the Unit string. */
+MAKE_GET(Unit,const char *,NULL,0,0)
+MAKE_TEST(Unit)
+
+/*
+*att++
+* Name:
+* NormUnit(axis)
+
+* Purpose:
+* Normalised physical units for formatted axis values
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String, read-only.
+
+* Description:
+* The value of this read-only attribute is derived from the current
+* value of the Unit attribute. It will represent an equivalent system
+* of units to the Unit attribute, but will potentially be simplified.
+* For instance, if Unit is set to "s*(m/s)", the NormUnit value will
+* be "m". If no simplification can be performed, the value of the
+* NormUnit attribute will equal that of the Unit attribute.
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+
+* Notes:
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+*att--
+*/
+/* This simply provides an interface to the Axis methods for accessing
+ the NormUnit string. */
+MAKE_GET(NormUnit,const char *,NULL,0,0)
+
+/*
+*att++
+* Name:
+* InternalUnit(axis)
+
+* Purpose:
+* Physical units for unformated axis values
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String, read-only.
+
+* Description:
+* This read-only attribute contains a textual representation of the
+* physical units used to represent unformatted (i.e. floating point)
+* values on a particular axis of a Frame, typically handled internally
+* within application code. In most cases, the value of the InternalUnit
+* attribute will be the same as Unit attribute (i.e. formatted and
+* unformatted axis values will normally use the same system of units).
+* The main exception to this is the SkyFrame class, which represents
+* unformatted axis values in radians, regardless of the current
+* setting of the Unit attribute.
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+
+* Notes:
+* - When specifying this attribute by name, it should be
+* subscripted with the number of the Frame axis to which it
+* applies.
+*att--
+*/
+/* If the Axis structure provides a value for InternalUnit, then use
+ that value. Otherwise, use a default equal to the value of the Unit
+ attribute for the axis. */
+MAKE_GET(InternalUnit,const char *,NULL,1,astGetUnit(this,axis))
+
+/* Implement member functions to access the attributes associated with
+ the Frame as a whole using the macros defined for this purpose in
+ the "object.h" file. */
+
+/*
+*att++
+* Name:
+* Digits/Digits(axis)
+
+* Purpose:
+* Number of digits of precision.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer.
+
+* Description:
+* This attribute specifies how many digits of precision are
+* required by default when a coordinate value is formatted for a
+c Frame axis (e.g. using astFormat). Its value may be set either
+f Frame axis (e.g. using AST_FORMAT). Its value may be set either
+* for a Frame as a whole, or (by subscripting the attribute name
+* with the number of an axis) for each axis individually. Any
+* value set for an individual axis will over-ride the value for
+* the Frame as a whole.
+*
+* Note that the Digits value acts only as a means of determining a
+* default Format string. Its effects are over-ridden if a Format
+* string is set explicitly for an axis. However, if the Format
+* attribute specifies the precision using the string ".*", then
+* the Digits attribute is used to determine the number of decimal
+* places to produce.
+
+* Applicability:
+* Frame
+* The default Digits value supplied by the Frame class is 7. If
+* a value less than 1 is supplied, then 1 is used instead.
+* FrameSet
+* The Digits attribute of a FrameSet (or one of its axes) is
+* the same as that of its current Frame (as specified by the
+* Current attribute).
+* Plot
+* The default Digits value used by the Plot class when drawing
+* annotated axis labels is the smallest value which results in all
+* adjacent labels being distinct.
+* TimeFrame
+* The Digits attribute is ignored when a TimeFrame formats a value
+* as a date and time string (see the Format attribute).
+*att--
+*/
+/* Clear the Digits value by setting it to -INT_MAX. */
+astMAKE_CLEAR(Frame,Digits,digits,-INT_MAX)
+
+/* Supply a default of 7 digits if no value has been set. */
+astMAKE_GET(Frame,Digits,int,0,( ( this->digits != -INT_MAX ) ? this->digits :
+ 7 ))
+
+/* Constrain the Digits value being set to be at least 1. */
+astMAKE_SET(Frame,Digits,int,digits,( value > 1 ? value : 1 ))
+
+/* The Digits value is set if it is not -INT_MAX. */
+astMAKE_TEST(Frame,Digits,( this->digits != -INT_MAX ))
+
+/*
+*att++
+* Name:
+* MatchEnd
+
+* Purpose:
+* Match trailing axes?
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer (boolean).
+
+* Description:
+* This attribute is a boolean value which controls how a Frame
+c behaves when it is used (by astFindFrame) as a template to match
+f behaves when it is used (by AST_FINDFRAME) as a template to match
+* another (target) Frame. It applies only in the case where a
+* match occurs between template and target Frames with different
+* numbers of axes.
+*
+* If the MatchEnd value of the template Frame is zero, then the
+* axes which occur first in the target Frame will be matched and
+* any trailing axes (in either the target or template) will be
+* disregarded. If it is non-zero, the final axes in each Frame
+* will be matched and any un-matched leading axes will be
+* disregarded instead.
+
+* Applicability:
+* Frame
+* The default MatchEnd value for a Frame is zero, so that
+* trailing axes are disregarded.
+* FrameSet
+* The MatchEnd attribute of a FrameSet is the same as that of
+* its current Frame (as specified by the Current attribute).
+*att--
+*/
+/* Clear the MatchEnd value by setting it to -INT_MAX. */
+astMAKE_CLEAR(Frame,MatchEnd,match_end,-INT_MAX)
+
+/* Supply a default of 0 if no MatchEnd value has been set. */
+astMAKE_GET(Frame,MatchEnd,int,0,( ( this->match_end != -INT_MAX ) ?
+ this->match_end : 0 ))
+
+/* Set a MatchEnd value of 1 if any non-zero value is supplied. */
+astMAKE_SET(Frame,MatchEnd,int,match_end,( value != 0 ))
+
+/* The MatchEnd value is set if it is not -INT_MAX. */
+astMAKE_TEST(Frame,MatchEnd,( this->match_end != -INT_MAX ))
+
+/*
+*att++
+* Name:
+* MaxAxes
+
+* Purpose:
+* Maximum number of Frame axes to match.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer.
+
+* Description:
+* This attribute controls how a Frame behaves when it is used (by
+c astFindFrame) as a template to match another (target) Frame. It
+f AST_FINDFRAME) as a template to match another (target) Frame. It
+* specifies the maximum number of axes that the target Frame may
+* have in order to match the template.
+*
+* Normally, this value will equal the number of Frame axes, so
+* that a template Frame will only match another Frame with the
+* same number of axes as itself. By setting a different value,
+* however, the matching process may be used to identify Frames
+* with specified numbers of axes.
+
+* Applicability:
+* Frame
+* The default MaxAxes value for a Frame is equal to the number
+* of Frame axes (Naxes attribute).
+* CmpFrame
+* The MaxAxes attribute of a CmpFrame defaults to a large number
+* (1000000) which is much larger than any likely number of axes in
+* a Frame. Combined with the MinAxes default of zero (for a
+* CmpFrame), this means that the default behaviour for a CmpFrame
+* is to match any target Frame that consists of a subset of the
+* axes in the template CmpFrame. To change this so that a CmpFrame
+* will only match Frames that have the same number of axes, you
+* should set the CmpFrame MaxAxes and MinAxes attributes to the
+* number of axes in the CmpFrame.
+* FrameSet
+* The MaxAxes attribute of a FrameSet is the same as that of
+* its current Frame (as specified by the Current attribute).
+
+* Notes:
+* - When setting a MaxAxes value, the value of the MinAxes
+* attribute may also be silently changed so that it remains
+* consistent with (i.e. does not exceed) the new value. The
+* default MaxAxes value may also be reduced to remain consistent
+* with the MinAxes value.
+* - If a template Frame is used to match a target with a different
+* number of axes, the MatchEnd attribute of the template is used
+* to determine how the individual axes of each Frame should match.
+*att--
+*/
+/* Clear the MaxAxes value by setting it to -INT_MAX. */
+astMAKE_CLEAR(Frame,MaxAxes,max_axes,-INT_MAX)
+
+/* Use the DefaultMaxAxes and ConsistentMaxAxes functions (defined earlier) for
+ the Get and Set operations to ensure that MinAxes and MaxAxes values remain
+ consistent. */
+astMAKE_GET(Frame,MaxAxes,int,0,DefaultMaxAxes( this, status ))
+astMAKE_SET(Frame,MaxAxes,int,max_axes,ConsistentMaxAxes( this, value, status ))
+
+/* The MaxAxes value is set if it is not -INT_MAX. */
+astMAKE_TEST(Frame,MaxAxes,( this->max_axes != -INT_MAX ))
+
+/*
+*att++
+* Name:
+* MinAxes
+
+* Purpose:
+* Minimum number of Frame axes to match.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer.
+
+* Description:
+* This attribute controls how a Frame behaves when it is used (by
+c astFindFrame) as a template to match another (target) Frame. It
+f AST_FINDFRAME) as a template to match another (target) Frame. It
+* specifies the minimum number of axes that the target Frame may
+* have in order to match the template.
+*
+* Normally, this value will equal the number of Frame axes, so
+* that a template Frame will only match another Frame with the
+* same number of axes as itself. By setting a different value,
+* however, the matching process may be used to identify Frames
+* with specified numbers of axes.
+
+* Applicability:
+* Frame
+* The default MinAxes value for a Frame is equal to the number
+* of Frame axes (Naxes attribute).
+* CmpFrame
+* The MinAxes attribute of a CmpFrame defaults to zero. Combined
+* with the MaxAxes default of 1000000 (for a CmpFrame), this means
+* that the default behaviour for a CmpFrame is to match any target
+* Frame that consists of a subset of the axes in the template
+* CmpFrame. To change this so that a CmpFrame will only match Frames
+* that have the same number of axes, you should set the CmpFrame
+* MinAxes and MaxAxes attributes to the number of axes in the CmpFrame.
+* FrameSet
+* The MinAxes attribute of a FrameSet is the same as that of
+* its current Frame (as specified by the Current attribute).
+
+* Notes:
+* - When setting a MinAxes value, the value of the MaxAxes
+* attribute may also be silently changed so that it remains
+* consistent with (i.e. is not less than) the new value. The
+* default MinAxes value may also be reduced to remain consistent
+* with the MaxAxes value.
+* - If a template Frame is used to match a target with a different
+* number of axes, the MatchEnd attribute of the template is used
+* to determine how the individual axes of each Frame should match.
+*att--
+*/
+/* Clear the MinAxes value by setting it to -INT_MAX. */
+astMAKE_CLEAR(Frame,MinAxes,min_axes,-INT_MAX)
+
+/* Use the DefaultMinAxes and ConsistentMinAxes functions (defined earlier) for
+ the Get and Set operations to ensure that MinAxes and MaxAxes values remain
+ consistent. */
+astMAKE_GET(Frame,MinAxes,int,0,DefaultMinAxes( this, status ))
+astMAKE_SET(Frame,MinAxes,int,min_axes,ConsistentMinAxes( this, value, status ))
+
+/* The MinAxes value is set if it is not -INT_MAX. */
+astMAKE_TEST(Frame,MinAxes,( this->min_axes != -INT_MAX ))
+
+/*
+*att++
+* Name:
+* Domain
+
+* Purpose:
+* Coordinate system domain.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute contains a string which identifies the physical
+* domain of the coordinate system that a Frame describes.
+*
+* The Domain attribute also controls how a Frame behaves when it is
+c used (by astFindFrame) as a template to match another (target)
+f used (by AST_FINDFRAME) as a template to match another (target)
+* Frame. It does this by specifying the Domain that the target
+* Frame should have in order to match the template. If the Domain
+* value in the template Frame is set, then only targets with the
+* same Domain value will be matched. If the template's Domain
+* value is not set, however, then the target's Domain will be
+* ignored.
+
+* Applicability:
+* Frame
+* The default Domain value supplied by the Frame class is an
+* empty string.
+* SkyFrame
+* The SkyFrame class re-defines the default Domain value to be
+* "SKY".
+* CmpFrame
+* The CmpFrame class re-defines the default Domain value to be
+* of the form "<dom1>-<dom2>", where <dom1> and <dom2> are the
+* Domains of the two component Frames. If both these Domains are
+* blank, then the string "CMP" is used as the default Domain name.
+* FrameSet
+* The Domain attribute of a FrameSet is the same as that of its
+* current Frame (as specified by the Current attribute).
+* SpecFrame
+* The SpecFrame class re-defines the default Domain value to be
+* "SPECTRUM".
+* DSBSpecFrame
+* The DSBSpecFrame class re-defines the default Domain value to be
+* "DSBSPECTRUM".
+* FluxFrame
+* The FluxFrame class re-defines the default Domain value to be
+* "FLUX".
+* SpecFluxFrame
+* The FluxFrame class re-defines the default Domain value to be
+* "SPECTRUM-FLUX".
+* TimeFrame
+* The TimeFrame class re-defines the default Domain value to be
+* "TIME".
+
+* Notes:
+* - All Domain values are converted to upper case and white space
+* is removed before use.
+*att--
+*/
+/* Clear the Domain value by freeing the allocated memory and
+ assigning a NULL pointer. */
+astMAKE_CLEAR(Frame,Domain,domain,astFree( this->domain ))
+
+/* If the Domain value is not set, supply a default in the form of a
+ pointer to the constant string "". */
+astMAKE_GET(Frame,Domain,const char *,NULL,( this->domain ? this->domain :
+ "" ))
+
+/* Set a Domain value by freeing any previously allocated memory,
+ allocating new memory, storing the string, removing white space,
+ converting to upper case and saving the pointer to the cleaned
+ copy. */
+astMAKE_SET(Frame,Domain,const char *,domain,CleanDomain(
+ astStore( this->domain,
+ value, strlen( value ) + (size_t) 1 ), status ))
+
+/* The Domain value is set if the pointer to it is not NULL. */
+astMAKE_TEST(Frame,Domain,( this->domain != NULL ))
+
+/*
+*att++
+* Name:
+* Permute
+
+* Purpose:
+* Permute axis order?
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute is a boolean value which controls how a Frame
+c behaves when it is used (by astFindFrame) as a template to match
+f behaves when it is used (by AST_FINDFRAME) as a template to match
+* another (target) Frame. It specifies whether the axis order of
+* the target Frame may be permuted in order to obtain a match.
+*
+* If the template's Permute value is zero, it will match a target
+* only if it can do so without changing the order of its
+* axes. Otherwise, it will attempt to permute the target's axes as
+* necessary.
+*
+* The default value is 1, so that axis permutation will be attempted.
+
+* Applicability:
+* Frame
+* All Frames have this attribute. However, the Frame class
+* effectively ignores this attribute and behaves as if it has
+* the value 1. This is because the axes of a basic Frame are
+* not distinguishable and will always match any other Frame
+* whatever their order.
+* SkyFrame
+* Unlike a basic Frame, the SkyFrame class makes use of this
+* attribute.
+* FrameSet
+* The Permute attribute of a FrameSet is the same as that of
+* its current Frame (as specified by the Current attribute).
+*att--
+*/
+/* Clear the Permute value by setting it to -INT_MAX. */
+astMAKE_CLEAR(Frame,Permute,permute,-INT_MAX)
+
+/* Supply a default of 1 if no Permute value has been set. */
+astMAKE_GET(Frame,Permute,int,0,( ( this->permute != -INT_MAX ) ?
+ this->permute : 1 ))
+
+/* Set a Permute value of 1 if any non-zero value is supplied. */
+astMAKE_SET(Frame,Permute,int,permute,( value != 0 ))
+
+/* The Permute value is set if it is not -INT_MAX. */
+astMAKE_TEST(Frame,Permute,( this->permute != -INT_MAX ))
+
+/*
+*att++
+* Name:
+* PreserveAxes
+
+* Purpose:
+* Preserve axes?
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer (boolean).
+
+* Description:
+* This attribute controls how a Frame behaves when it is used (by
+c astFindFrame) as a template to match another (target) Frame. It
+f AST_FINDFRAME) as a template to match another (target) Frame. It
+* determines which axes appear (and in what order) in the "result"
+* Frame produced.
+*
+* If PreserveAxes is zero in the template Frame, then the result
+* Frame will have the same number (and order) of axes as the
+* template. If it is non-zero, however, the axes of the target
+* Frame will be preserved, so that the result Frame will have the
+* same number (and order) of axes as the target.
+*
+* The default value is zero, so that target axes are not preserved
+* and the result Frame resembles the template.
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+* FrameSet
+* The PreserveAxes attribute of a FrameSet is the same as that
+* of its current Frame (as specified by the Current attribute).
+*att--
+*/
+/* Clear the PreserveAxes value by setting it to -INT_MAX. */
+astMAKE_CLEAR(Frame,PreserveAxes,preserve_axes,-INT_MAX)
+
+/* Supply a default of 0 if no PreserveAxes value has been set. */
+astMAKE_GET(Frame,PreserveAxes,int,0,( ( this->preserve_axes != -INT_MAX ) ?
+ this->preserve_axes : 0 ))
+
+/* Set a PreserveAxes value of 1 if any non-zero value is supplied. */
+astMAKE_SET(Frame,PreserveAxes,int,preserve_axes,( value != 0 ))
+
+/* The PreserveAxes value is set if it is not -INT_MAX. */
+astMAKE_TEST(Frame,PreserveAxes,( this->preserve_axes != -INT_MAX ))
+
+/*
+*att++
+* Name:
+* AlignSystem
+
+* Purpose:
+* Coordinate system in which to align the Frame.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute controls how a Frame behaves when it is used (by
+c astFindFrame or astConvert) as a template to match another (target)
+f AST_FINDFRAME or AST_CONVERT) as a template to match another (target)
+* Frame. It identifies the coordinate system in which the two Frames
+* will be aligned by the match.
+*
+* The values which may be assigned to this attribute, and its default
+* value, depend on the class of Frame and are described in the
+* "Applicability" section below. In general, the AlignSystem attribute
+* will accept any of the values which may be assigned to the System
+* attribute.
+*
+c The Mapping returned by AST_FINDFRAME or AST_CONVERT will use the
+f The Mapping returned by astFindFrame or astConvert will use the
+* coordinate system specified by the AlignSystem attribute as an
+* intermediate coordinate system. The total returned Mapping will first
+* map positions from the first Frame into this intermediate coordinate
+* system, using the attributes of the first Frame. It will then map
+* these positions from the intermediate coordinate system into the
+* second Frame, using the attributes of the second Frame.
+
+* Applicability:
+* Frame
+* The AlignSystem attribute for a basic Frame always equals "Cartesian",
+* and may not be altered.
+* CmpFrame
+* The AlignSystem attribute for a CmpFrame always equals "Compound",
+* and may not be altered.
+* FrameSet
+* The AlignSystem attribute of a FrameSet is the same as that of its
+* current Frame (as specified by the Current attribute).
+* SkyFrame
+* The default AlignSystem attribute for a SkyFrame is "ICRS".
+* SpecFrame
+* The default AlignSystem attribute for a SpecFrame is "Wave"
+* (wavelength).
+* TimeFrame
+* The default AlignSystem attribute for a TimeFrame is "MJD".
+*att--
+*/
+/* Clear the AlignSystem value by setting it to AST__BADSYSTEM. */
+astMAKE_CLEAR(Frame,AlignSystem,alignsystem,AST__BADSYSTEM)
+
+/* Provide a default AlignSystem of AST__CART. */
+astMAKE_GET(Frame,AlignSystem,AstSystemType,AST__BADSYSTEM,(
+ ( this->alignsystem == AST__BADSYSTEM ) ? AST__CART : this->alignsystem ) )
+
+/* Validate the AlignSystem value being set and retain the original if the
+ supplied value is not recognized. */
+astMAKE_SET(Frame,AlignSystem,AstSystemType,alignsystem,(
+ (astValidateSystem( this, value, "astSetAlignSystem" ) != AST__BADSYSTEM) ?
+ value : this->alignsystem ))
+
+/* The AlignSystem value is set if it is not AST__BADSYSTEM. */
+astMAKE_TEST(Frame,AlignSystem,( this->alignsystem != AST__BADSYSTEM ))
+
+/*
+*att++
+* Name:
+* System
+
+* Purpose:
+* Coordinate system used to describe positions within the domain
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* In general it is possible for positions within a given physical
+* domain to be described using one of several different coordinate
+* systems. For instance, the SkyFrame class can use galactic
+* coordinates, equatorial coordinates, etc, to describe positions on
+* the sky. As another example, the SpecFrame class can use frequency,
+* wavelength, velocity, etc, to describe a position within an
+* electromagnetic spectrum. The System attribute identifies the particular
+* coordinate system represented by a Frame. Each class of Frame
+* defines a set of acceptable values for this attribute, as listed
+* below (all are case insensitive). Where more than one alternative
+* System value is shown, the first of will be returned when an
+* enquiry is made.
+
+* Applicability:
+* Frame
+* The System attribute for a basic Frame always equals "Cartesian",
+* and may not be altered.
+* CmpFrame
+* The System attribute for a CmpFrame always equals "Compound",
+* and may not be altered. In addition, the CmpFrame class allows
+* the System attribute to be referenced for a component Frame by
+* including the index of an axis within the required component
+* Frame. For instance, "System(3)" refers to the System attribute
+* of the component Frame which includes axis 3 of the CmpFrame.
+* FrameSet
+* The System attribute of a FrameSet is the same as that of its
+* current Frame (as specified by the Current attribute).
+* SkyFrame
+* The SkyFrame class supports the following System values and
+* associated celestial coordinate systems:
+*
+* - "AZEL": Horizon coordinates. The longitude axis is azimuth
+* such that geographic north has an azimuth of zero and geographic
+* east has an azimuth of +PI/2 radians. The zenith has elevation
+* +PI/2. When converting to and from other celestial coordinate
+* systems, no corrections are applied for atmospheric refraction
+* or polar motion (however, a correction for diurnal aberattion is
+* applied). Note, unlike most other
+* celestial coordinate systems, this system is right handed. Also,
+* unlike other SkyFrame systems, the AzEl system is sensitive to
+* the timescale in which the Epoch value is supplied. This is
+* because of the gross diurnal rotation which this system undergoes,
+* causing a small change in time to translate to a large rotation.
+* When converting to or from an AzEl system, the Epoch value for
+* both source and destination SkyFrames should be supplied in the
+* TDB timescale. The difference between TDB and TT is between 1
+* and 2 milliseconds, and so a TT value can usually be supplied in
+* place of a TDB value. The TT timescale is related to TAI via
+* TT = TAI + 32.184 seconds.
+*
+* - "ECLIPTIC": Ecliptic coordinates (IAU 1980), referred to the
+* ecliptic and mean equinox specified by the qualifying Equinox
+* value.
+*
+* - "FK4": The old FK4 (barycentric) equatorial coordinate system,
+* which should be qualified by an Equinox value. The underlying
+* model on which this is based is non-inertial and rotates slowly
+* with time, so for accurate work FK4 coordinate systems should
+* also be qualified by an Epoch value.
+*
+* - "FK4-NO-E" or "FK4_NO_E": The old FK4 (barycentric) equatorial
+* system but without the "E-terms of aberration" (e.g. some radio
+* catalogues). This coordinate system should also be qualified by
+* both an Equinox and an Epoch value.
+*
+* - "FK5" or "EQUATORIAL": The modern FK5 (barycentric) equatorial
+* coordinate system. This should be qualified by an Equinox value.
+*
+* - "GALACTIC": Galactic coordinates (IAU 1958).
+*
+* - "GAPPT", "GEOCENTRIC" or "APPARENT": The geocentric apparent
+* equatorial coordinate system, which gives the apparent positions
+* of sources relative to the true plane of the Earth's equator and
+* the equinox (the coordinate origin) at a time specified by the
+* qualifying Epoch value. (Note that no Equinox is needed to
+* qualify this coordinate system because no model "mean equinox"
+* is involved.) These coordinates give the apparent right
+* ascension and declination of a source for a specified date of
+* observation, and therefore form an approximate basis for
+* pointing a telescope. Note, however, that they are applicable to
+* a fictitious observer at the Earth's centre, and therefore
+* ignore such effects as atmospheric refraction and the (normally
+* much smaller) aberration of light due to the rotational velocity
+* of the Earth's surface. Geocentric apparent coordinates are
+* derived from the standard FK5 (J2000.0) barycentric coordinates
+* by taking account of the gravitational deflection of light by
+* the Sun (usually small), the aberration of light caused by the
+* motion of the Earth's centre with respect to the barycentre
+* (larger), and the precession and nutation of the Earth's spin
+* axis (normally larger still).
+*
+* - "HELIOECLIPTIC": Ecliptic coordinates (IAU 1980), referred to the
+* ecliptic and mean equinox of J2000.0, in which an offset is added to
+* the longitude value which results in the centre of the sun being at
+* zero longitude at the date given by the Epoch attribute. Attempts to
+* set a value for the Equinox attribute will be ignored, since this
+* system is always referred to J2000.0.
+*
+* - "ICRS": The Internation Celestial Reference System, realised
+* through the Hipparcos catalogue. Whilst not an equatorial system
+* by definition, the ICRS is very close to the FK5 (J2000) system
+* and is usually treated as an equatorial system. The distinction
+* between ICRS and FK5 (J2000) only becomes important when accuracies
+* of 50 milli-arcseconds or better are required. ICRS need not be
+* qualified by an Equinox value.
+*
+* - "J2000": An equatorial coordinate system based on the mean
+* dynamical equator and equinox of the J2000 epoch. The dynamical
+* equator and equinox differ slightly from those used by the FK5
+* model, and so a "J2000" SkyFrame will differ slightly from an
+* "FK5(Equinox=J2000)" SkyFrame. The J2000 System need not be
+* qualified by an Equinox value
+*
+* - "SUPERGALACTIC": De Vaucouleurs Supergalactic coordinates.
+*
+* - "UNKNOWN": Any other general spherical coordinate system. No
+* Mapping can be created between a pair of SkyFrames if either of the
+* SkyFrames has System set to "Unknown".
+*
+* Currently, the default System value is "ICRS". However, this
+* default may change in future as new astrometric standards
+* evolve. The intention is to track the most modern appropriate
+* standard. For this reason, you should use the default only if
+* this is what you intend (and can tolerate any associated slight
+* change in future). If you intend to use the ICRS system
+* indefinitely, then you should specify it explicitly.
+* SpecFrame
+* The SpecFrame class supports the following System values and
+* associated spectral coordinate systems (the default is "WAVE" -
+* wavelength). They are all defined in FITS-WCS paper III:
+*
+* - "FREQ": Frequency (GHz)
+* - "ENER" or "ENERGY": Energy (J)
+* - "WAVN" or "WAVENUM": Wave-number (1/m)
+* - "WAVE" or "WAVELEN": Vacuum wave-length (Angstrom)
+* - "AWAV" or "AIRWAVE": Wave-length in air (Angstrom)
+* - "VRAD" or "VRADIO": Radio velocity (km/s)
+* - "VOPT" or "VOPTICAL": Optical velocity (km/s)
+* - "ZOPT" or "REDSHIFT": Redshift (dimensionless)
+* - "BETA": Beta factor (dimensionless)
+* - "VELO" or "VREL": Apparent radial ("relativistic") velocity (km/s)
+*
+* The default value for the Unit attribute for each system is shown
+* in parentheses. Note that the default value for the ActiveUnit flag
+c is non-zero
+f is .TRUE.
+* for a SpecFrame, meaning that changes to the Unit attribute for
+* a SpecFrame will result in the SpecFrame being re-mapped within
+* its enclosing FrameSet in order to reflect the change in units
+c (see astSetActiveUnit function for further information).
+f (see AST_SETACTIVEUNIT routine for further information).
+* TimeFrame
+* The TimeFrame class supports the following System values and
+* associated coordinate systems (the default is "MJD"):
+*
+* - "MJD": Modified Julian Date (d)
+* - "JD": Julian Date (d)
+* - "JEPOCH": Julian epoch (yr)
+* - "BEPOCH": Besselian (yr)
+*
+* The default value for the Unit attribute for each system is shown
+* in parentheses. Strictly, these systems should not allow changes
+* to be made to the units. For instance, the usual definition of
+* "MJD" and "JD" include the statement that the values will be in
+* units of days. However, AST does allow the use of other units
+* with all the above supported systems (except BEPOCH), on the
+* understanding that conversion to the "correct" units involves
+* nothing more than a simple scaling (1 yr = 365.25 d, 1 d = 24 h,
+* 1 h = 60 min, 1 min = 60 s). Besselian epoch values are defined
+* in terms of tropical years of 365.2422 days, rather than the
+* usual Julian year of 365.25 days. Therefore, to avoid any
+* confusion, the Unit attribute is automatically cleared to "yr" when
+* a System value of BEPOCH System is selected, and an error is
+* reported if any attempt is subsequently made to change the Unit
+* attribute.
+*
+* Note that the default value for the ActiveUnit flag
+c is non-zero
+f is .TRUE.
+* for a TimeFrame, meaning that changes to the Unit attribute for
+* a TimeFrame will result in the TimeFrame being re-mapped within
+* its enclosing FrameSet in order to reflect the change in units
+c (see astSetActiveUnit function for further information).
+f (see AST_SETACTIVEUNIT routine for further information).
+* FluxFrame
+* The FluxFrame class supports the following System values and
+* associated systems for measuring observed value:
+*
+* - "FLXDN": Flux per unit frequency (W/m^2/Hz)
+* - "FLXDNW": Flux per unit wavelength (W/m^2/Angstrom)
+* - "SFCBR": Surface brightness in frequency units (W/m^2/Hz/arcmin**2)
+* - "SFCBRW": Surface brightness in wavelength units (W/m^2/Angstrom/arcmin**2)
+*
+* The above lists specified the default units for each System. If an
+* explicit value is set for the Unit attribute but no value is set
+* for System, then the default System value is determined by the Unit
+* string (if the units are not appropriate for describing any of the
+* supported Systems then an error will be reported when an attempt is
+* made to access the System value). If no value has been specified for
+* either Unit or System, then System=FLXDN and Unit=W/m^2/Hz are
+* used.
+*att--
+*/
+/* Clear the System value by setting it to AST__BADSYSTEM. */
+astMAKE_CLEAR(Frame,System,system,AST__BADSYSTEM)
+
+/* Provide a default coordinate system of AST__CART. */
+astMAKE_GET(Frame,System,AstSystemType,AST__BADSYSTEM,(
+ ( this->system == AST__BADSYSTEM ) ? AST__CART : this->system ) )
+
+/* Validate the System value being set and retain the original if the
+ supplied value is not recognized. */
+astMAKE_SET(Frame,System,AstSystemType,system,(
+ (astValidateSystem( this, value, "astSetSystem" ) != AST__BADSYSTEM) ?
+ value : this->system ))
+
+/* The System value is set if it is not AST__BADSYSTEM. */
+astMAKE_TEST(Frame,System,( this->system != AST__BADSYSTEM ))
+
+/*
+*att++
+* Name:
+* Title
+
+* Purpose:
+* Frame title.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute holds a string which is used as a title in (e.g.)
+* graphical output to describe the coordinate system which a Frame
+* represents. Examples might be "Detector Coordinates" or
+* "Galactic Coordinates".
+*
+* If a Title value has not been set for a Frame, then a suitable
+* default is supplied, depending on the class of the Frame.
+
+* Applicability:
+* Frame
+* The default supplied by the Frame class is "<n>-d coordinate
+* system", where <n> is the number of Frame axes (Naxes
+* attribute).
+* CmpFrame
+* The CmpFrame class re-defines the default Title value to be
+* "<n>-d compound coordinate system", where <n> is the number
+* of CmpFrame axes (Naxes attribute).
+* FrameSet
+* The Title attribute of a FrameSet is the same as that of its
+* current Frame (as specified by the Current attribute).
+
+* Notes:
+* - A Frame's Title is intended purely for interpretation by human
+* readers and not by software.
+*att--
+*/
+/* Clear the Title value by freeing the allocated memory and assigning
+ a NULL pointer. */
+astMAKE_CLEAR(Frame,Title,title,astFree( this->title ))
+
+/* If the Title value is not set, write a default based on the number of Frame
+ axes into the static "title_buff" buffer, and return a pointer to this
+ buffer. */
+astMAKE_GET(Frame,Title,const char *,NULL,( this->title ?
+ this->title : GetDefaultTitle( this, status ) ))
+
+/* Set a Title value by freeing any previously allocated memory, allocating
+ new memory, storing the string and saving the pointer to the copy. */
+astMAKE_SET(Frame,Title,const char *,title,astStore( this->title, value,
+ strlen( value ) + (size_t) 1 ))
+
+/* The Title value is set if the pointer to it is not NULL. */
+astMAKE_TEST(Frame,Title,( this->title != NULL ))
+
+/*
+*att++
+* Name:
+* ObsLat
+
+* Purpose:
+* The geodetic latitude of the observer
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute specifies the geodetic latitude of the observer, in
+* degrees, relative to the IAU 1976 reference ellipsoid. The basic Frame
+* class makes no use of this attribute, but specialised subclasses of
+* Frame may use it. For instance, the SpecFrame, SkyFrame and TimeFrame
+* classes use it. The default value is zero.
+*
+* The value is stored internally in radians, but is converted to and
+* from a degrees string for access. Some example input formats are:
+* "22:19:23.2", "22 19 23.2", "22:19.387", "22.32311", "N22.32311",
+* "-45.6", "S45.6". As indicated, the sign of the latitude can
+* optionally be indicated using characters "N" and "S" in place of the
+* usual "+" and "-". When converting the stored value to a string, the
+* format "[s]dd:mm:ss.ss" is used, when "[s]" is "N" or "S".
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+* SpecFrame
+* Together with the ObsLon, Epoch, RefRA and RefDec attributes,
+* it defines the Doppler shift introduced by the observers diurnal
+* motion around the earths axis, which is needed when converting to
+* or from the topocentric standard of rest. The maximum velocity
+* error which can be caused by an incorrect value is 0.5 km/s. The
+* default value for the attribute is zero.
+* TimeFrame
+* Together with the ObsLon attribute, it is used when converting
+* between certain time scales (TDB, TCB, LMST, LAST)
+
+*att--
+*/
+/* The geodetic latitude of the observer (radians). Clear the ObsLat value by
+ setting it to AST__BAD, returning zero as the default value. Any value is
+ acceptable. */
+astMAKE_CLEAR(Frame,ObsLat,obslat,AST__BAD)
+astMAKE_GET(Frame,ObsLat,double,0.0,((this->obslat!=AST__BAD)?this->obslat:0.0))
+astMAKE_SET(Frame,ObsLat,double,obslat,value)
+astMAKE_TEST(Frame,ObsLat,(this->obslat!=AST__BAD))
+
+
+/*
+*att++
+* Name:
+* ObsAlt
+
+* Purpose:
+* The geodetic altitude of the observer
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Floating point.
+
+* Description:
+* This attribute specifies the geodetic altitude of the observer, in
+* metres, relative to the IAU 1976 reference ellipsoid. The basic Frame
+* class makes no use of this attribute, but specialised subclasses of
+* Frame may use it. For instance, the SpecFrame, SkyFrame and TimeFrame
+* classes use it. The default value is zero.
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+* SpecFrame
+* Together with the ObsLon, Epoch, RefRA and RefDec attributes,
+* it defines the Doppler shift introduced by the observers diurnal
+* motion around the earths axis, which is needed when converting to
+* or from the topocentric standard of rest. The maximum velocity
+* error which can be caused by an incorrect value is 0.5 km/s. The
+* default value for the attribute is zero.
+* TimeFrame
+* Together with the ObsLon attribute, it is used when converting
+* between certain time scales (TDB, TCB, LMST, LAST)
+
+*att--
+*/
+/* The geodetic altitude of the observer (metres). Clear the ObsAlt value by
+ setting it to AST__BAD, returning zero as the default value. Any value is
+ acceptable. */
+astMAKE_CLEAR(Frame,ObsAlt,obsalt,AST__BAD)
+astMAKE_GET(Frame,ObsAlt,double,0.0,((this->obsalt!=AST__BAD)?this->obsalt:0.0))
+astMAKE_SET(Frame,ObsAlt,double,obsalt,value)
+astMAKE_TEST(Frame,ObsAlt,(this->obsalt!=AST__BAD))
+
+
+/*
+*att++
+* Name:
+* ObsLon
+
+* Purpose:
+* The geodetic longitude of the observer
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute specifies the geodetic (or equivalently, geocentric)
+* longitude of the observer, in degrees, measured positive eastwards.
+* See also attribute ObsLat. The basic Frame class makes no use of this
+* attribute, but specialised subclasses of Frame may use it. For instance,
+* the SpecFrame, SkyFrame and TimeFrame classes use it. The default value
+* is zero.
+*
+* The value is stored internally in radians, but is converted to and
+* from a degrees string for access. Some example input formats are:
+* "155:19:23.2", "155 19 23.2", "155:19.387", "155.32311", "E155.32311",
+* "-204.67689", "W204.67689". As indicated, the sign of the longitude can
+* optionally be indicated using characters "E" and "W" in place of the
+* usual "+" and "-". When converting the stored value to a string, the
+* format "[s]ddd:mm:ss.ss" is used, when "[s]" is "E" or "W" and the
+* numerical value is chosen to be less than 180 degrees.
+
+* Applicability:
+* Frame
+* All Frames have this attribute.
+* SpecFrame
+* Together with the ObsLon, Epoch, RefRA and RefDec attributes,
+* it defines the Doppler shift introduced by the observers diurnal
+* motion around the earths axis, which is needed when converting to
+* or from the topocentric standard of rest. The maximum velocity
+* error which can be caused by an incorrect value is 0.5 km/s. The
+* default value for the attribute is zero.
+* TimeFrame
+* Together with the ObsLon attribute, it is used when converting
+* between certain time scales (TDB, TCB, LMST, LAST)
+
+*att--
+*/
+/* The geodetic longitude of the observer (radians). Clear the ObsLon value by
+ setting it to AST__BAD, returning zero as the default value. Any value is
+ acceptable. */
+astMAKE_CLEAR(Frame,ObsLon,obslon,AST__BAD)
+astMAKE_GET(Frame,ObsLon,double,0.0,((this->obslon!=AST__BAD)?this->obslon:0.0))
+astMAKE_SET(Frame,ObsLon,double,obslon,value)
+astMAKE_TEST(Frame,ObsLon,(this->obslon!=AST__BAD))
+
+
+/* Copy constructor. */
+/* ----------------- */
+static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
+/*
+* Name:
+* Copy
+
+* Purpose:
+* Copy constructor for Frame objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Copy( const AstObject *objin, AstObject *objout, int *status )
+
+* Description:
+* This function implements the copy constructor for Frame objects.
+
+* Parameters:
+* objin
+* Pointer to the object to be copied.
+* objout
+* Pointer to the object being constructed.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - This constructor makes a deep copy.
+*/
+
+/* Local Variables: */
+ AstFrame *in; /* Pointer to input Frame */
+ AstFrame *out; /* Pointer to output Frame */
+ int axis; /* Loop counter for axes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain pointers to the input and output Frames. */
+ in = (AstFrame *) objin;
+ out = (AstFrame *) objout;
+
+/* For safety, first clear any references to the input memory from
+ the output Frame. */
+ out->axis = NULL;
+ out->domain = NULL;
+ out->perm = NULL;
+ out->title = NULL;
+ out->variants = NULL;
+
+/* If necessary, allocate memory in the output Frame and store a copy of the
+ input Title and Domain strings. */
+ if ( in->title ) out->title = astStore( NULL, in->title,
+ strlen( in->title ) + (size_t) 1 );
+ if ( in->domain ) out->domain = astStore( NULL, in->domain,
+ strlen( in->domain ) +
+ (size_t) 1 );
+
+/* Allocate memory to hold the output Frame's Axis object pointers and its axis
+ permutation array. */
+ out->axis = astMalloc( sizeof( AstAxis * ) * (size_t) in->naxes );
+ out->perm = astMalloc( sizeof( int ) * (size_t) in->naxes );
+
+/* Make a copy of each of the input Frame's Axis objects, storing the pointer
+ to each new Axis in the memory just allocated. Also copy the axis
+ permutation array. */
+ if ( astOK ) {
+ for ( axis = 0; axis < in->naxes; axis++ ) {
+ out->axis[ axis ] = astCopy( in->axis[ axis ] );
+ out->perm[ axis ] = in->perm[ axis ];
+ }
+
+/* If an error occurred while copying the Axis objects, then loop through the
+ resulting array of pointers and make sure that all of them are properly
+ annulled. */
+ if ( !astOK ) {
+ for ( axis = 0; axis < in->naxes; axis++ ) {
+ out->axis[ axis ] = astAnnul( out->axis[ axis ] );
+ }
+ }
+ }
+
+/* Other remaining objects */
+ if( in->variants ) out->variants = astCopy( in->variants );
+
+/* If an error occurred, free any allocated memory. */
+ if ( !astOK ) {
+ out->axis = astFree( out->axis );
+ out->domain = astFree( out->domain );
+ out->perm = astFree( out->perm );
+ out->title = astFree( out->title );
+ }
+}
+
+/* Destructor. */
+/* ----------- */
+static void Delete( AstObject *obj, int *status ) {
+/*
+* Name:
+* Delete
+
+* Purpose:
+* Destructor for Frame objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Delete( AstObject *obj, int *status )
+
+* Description:
+* This function implements the destructor for Frame objects.
+
+* Parameters:
+* obj
+* Pointer to the object to be deleted.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* This function attempts to execute even if the global error status is
+* set.
+*/
+
+/* Local Variables: */
+ AstFrame *this; /* Pointer to Frame */
+ int axis; /* Loop counter for Frame axes */
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) obj;
+
+/* Free the memory used for the Title and Domain strings if necessary. */
+ this->title = astFree( this->title );
+ this->domain = astFree( this->domain );
+
+/* If memory has been allocated to store pointers to the Frame's Axis objects,
+ annul each of these pointers and then free the memory. */
+ if ( this->axis ) {
+ for ( axis = 0; axis < this->naxes; axis++ ) {
+ this->axis[ axis ] = astAnnul( this->axis[ axis ] );
+ }
+ this->axis = astFree( this->axis );
+ }
+
+/* Free memory used for the axis permutation array if necessary. */
+ this->perm = astFree( this->perm );
+
+/* Other objects. */
+ if( this->variants ) this->variants = astAnnul( this->variants );
+}
+
+/* Dump function. */
+/* -------------- */
+static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
+/*
+* Name:
+* Dump
+
+* Purpose:
+* Dump function for Frame objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Dump( AstObject *this, AstChannel *channel, int *status )
+
+* Description:
+* This function implements the Dump function which writes out data
+* for the Frame class to an output Channel.
+
+* Parameters:
+* this
+* Pointer to the Frame whose data are being written.
+* channel
+* Pointer to the Channel to which the data are being written.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Constants: */
+#define COMMENT_LEN 150 /* Maximum length of a comment string */
+#define KEY_LEN 50 /* Maximum length of a keyword */
+
+/* Local Variables: */
+ AstAxis *ax; /* Pointer to Axis */
+ AstFrame *cfrm; /* Pointer to FrameSet's current Frame */
+ AstFrame *this; /* Pointer to the Frame structure */
+ AstSystemType system; /* System code */
+ char comment[ COMMENT_LEN + 1 ]; /* Buffer for comment strings */
+ char key[ KEY_LEN + 1 ]; /* Buffer for keywords */
+ const char *sval; /* Pointer to string value */
+ const char *lab; /* Pointer to unit label */
+ const int *perm; /* Pointer to axis permutation array */
+ double dval; /* Double attibute value */
+ int *invperm; /* Pointer to inverse permutation array */
+ int axis; /* Loop counter for Frame axes */
+ int bessyr; /* Format as Besselian years (else Julian) */
+ int digits_set; /* Digits set explicitly for any axis? */
+ int full; /* Full attribute value */
+ int full_set; /* Full attribute set? */
+ int helpful; /* Helpful to show value even if not set? */
+ int isFrame; /* Is this a simple Frame? */
+ int ival; /* Integer value */
+ int naxes; /* Number of Frame axes */
+ int set; /* Attribute value set? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the Frame structure. */
+ this = (AstFrame *) this_object;
+
+/* Determine the number of Frame axes and a pointer to the Frame's
+ axis permutation array (using methods, to allow for any over-ride
+ by a derived class). */
+ naxes = astGetNaxes( this );
+ perm = astGetPerm( this );
+
+/* Some default attribute values are not helpful for a simple Frame. Note
+ if this is a simple Frame, or if it is a FrameSet with a simple Frame
+ as its current Frame., or if it is a CmpFrame. */
+ if( !strcmp( astGetClass( this ), "Frame" ) ) {
+ isFrame = 1;
+ } else if( astIsAFrameSet( this ) ) {
+ cfrm = astGetFrame( (AstFrameSet *) this, AST__CURRENT );
+ isFrame = !strcmp( astGetClass( cfrm ), "Frame" );
+ cfrm = astAnnul( cfrm );
+ } else if( astIsACmpFrame( this ) ) {
+ isFrame = 1;
+ } else {
+ isFrame = 0;
+ }
+
+/* Allocate memory to hold an inverse axis permutation array and
+ generate this array from the forward permutation values. This will
+ be used to determine which axis should be enquired about (using
+ possibly over-ridden methods) to obtain data to correspond with a
+ particular internal value (i.e. instance variable) relating to an
+ axis. This step is needed so that the effect of any axis
+ permutation can be un-done before values are written out, as output
+ values are written by this function in un-permuted order. */
+ invperm = astMalloc( sizeof( int ) * (size_t) naxes );
+ if ( astOK ) {
+ for ( axis = 0; axis < naxes; axis++ ) invperm[ perm[ axis ] ] = axis;
+
+/* Write out values representing the instance variables for the Frame
+ class. Accompany these with appropriate comment strings, possibly
+ depending on the values being written.*/
+
+/* In the case of attributes, we first use the appropriate (private)
+ Test... member function to see if they are set. If so, we then use
+ the (private) Get... function to obtain the value to be written
+ out.
+
+ For attributes which are not set, we use the astGet... method to
+ obtain the value instead. This will supply a default value
+ (possibly provided by a derived class which over-rides this method)
+ which is more useful to a human reader as it corresponds to the
+ actual default attribute value. Since "set" will be zero, these
+ values are for information only and will not be read back. */
+
+/* Title. */
+/* ------ */
+ set = TestTitle( this, status );
+ sval = set ? GetTitle( this, status ) : astGetTitle( this );
+ astWriteString( channel, "Title", set, 1, sval,
+ "Title of coordinate system" );
+
+/* Naxes. */
+/* ------ */
+ set = ( this->naxes != 0 );
+ ival = set ? this->naxes : naxes;
+ astWriteInt( channel, "Naxes", set, 1, ival,
+ "Number of coordinate axes" );
+
+/* Domain. */
+/* ------- */
+ set = TestDomain( this, status );
+ sval = set ? GetDomain( this, status ) : astGetDomain( this );
+
+/* Don't show an un-set Domain value if it is blank. */
+ helpful = ( sval && *sval );
+ astWriteString( channel, "Domain", set, helpful, sval,
+ "Coordinate system domain" );
+
+/* Epoch. */
+/* ------ */
+ set = TestEpoch( this, status );
+ dval = set ? GetEpoch( this, status ) : astGetEpoch( this );
+
+/* Convert MJD to Besselian or Julian years, depending on the value. */
+ bessyr = ( dval < palEpj2d( 1984.0 ) );
+ dval = bessyr ? palEpb( dval ) : palEpj( dval );
+ astWriteDouble( channel, "Epoch", set, !isFrame, dval,
+ bessyr ? "Besselian epoch of observation" :
+ "Julian epoch of observation" );
+
+/* Label. */
+/* ------ */
+/* This, and some other, attributes are stored internally by the
+ Frame's Axis objects, but are "re-packaged" by the Frame class to
+ appear as Frame attributes. We treat them here like Frame
+ attributes that are "un-set". There is a Label value for each Frame
+ axis. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+
+/* The inverse axis permutation array is used to obtain the axis index
+ for astGetLabel. This reverses the effect of the Frame's axis
+ permutation array and yields a default value appropriate to the
+ axis with internal index "axis". */
+ sval = astGetLabel( this, invperm[ axis ] );
+
+/* Create keyword and comment strings appropriate to each axis
+ (converting to 1-based axis numbering) and write out the Label
+ values. */
+ (void) sprintf( key, "Lbl%d", axis + 1 );
+ (void) sprintf( comment, "Label for axis %d", axis + 1 );
+ astWriteString( channel, key, 0, 1, sval, comment );
+ }
+
+/* Symbol. */
+/* ------- */
+/* There is a Symbol value for each Frame axis. These are handled in
+ the same way as the Label values. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+ sval = astGetSymbol( this, invperm[ axis ] );
+ (void) sprintf( key, "Sym%d", axis + 1 );
+ (void) sprintf( comment, "Symbol for axis %d", axis + 1 );
+ astWriteString( channel, key, 0, 0, sval, comment );
+ }
+
+/* System. */
+/* ------- */
+ set = TestSystem( this, status );
+ system = set ? GetSystem( this, status ) : astGetSystem( this );
+
+/* If set, convert explicitly to a string for the external representation. */
+ if ( set ) {
+ if ( astOK ) {
+ sval = astSystemString( this, system );
+
+/* Report an error if the System value was not recognised. */
+ if ( !sval ) {
+ astError( AST__SCSIN,
+ "astWrite(%s): Corrupt %s contains invalid "
+ "System identification code (%d).", status,
+ astGetClass( channel ), astGetClass( this ),
+ (int) system );
+ }
+ }
+
+/* If not set, use astGetAttrib which returns a string value using
+ (possibly over-ridden) methods. */
+ } else {
+ sval = astGetAttrib( this_object, "system" );
+ }
+
+/* Write out the value. */
+ astWriteString( channel, "System", set, !isFrame, sval,
+ "Coordinate system type" );
+
+/* AlignSystem. */
+/* ------------ */
+ set = TestAlignSystem( this, status );
+ system = set ? GetAlignSystem( this, status ) : astGetAlignSystem( this );
+
+/* If set, convert explicitly to a string for the external representation. */
+ if ( set ) {
+ if ( astOK ) {
+ sval = astSystemString( this, system );
+
+/* Report an error if the AlignSystem value was not recognised. */
+ if ( !sval ) {
+ astError( AST__SCSIN,
+ "astWrite(%s): Corrupt %s contains invalid "
+ "AlignSystem identification code (%d).", status,
+ astGetClass( channel ), astGetClass( this ),
+ (int) system );
+ }
+ }
+
+/* If not set, use astGetAttrib which returns a string value using
+ (possibly over-ridden) methods. */
+ } else {
+ sval = astGetAttrib( this_object, "alignsystem" );
+ }
+
+/* Write out the value. */
+ astWriteString( channel, "AlSys", set, 0, sval,
+ "Alignment coordinate system" );
+
+/* Unit. */
+/* ----- */
+/* There is a Unit value for each axis. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+ sval = astGetUnit( this, invperm[ axis ] );
+
+/* Get any label associated with the unit string. */
+ lab = astUnitLabel( sval );
+
+/* Construct a comment including the above label (but only if it is not
+ the same as the unit string) . */
+ if( lab && strcmp( lab, sval ) ) {
+ (void) sprintf( comment, "Units for axis %d (%s)", axis + 1, lab );
+ } else {
+ (void) sprintf( comment, "Units for axis %d", axis + 1 );
+ }
+
+/* Show the Unit value if it is not blank. */
+ helpful = ( sval && *sval );
+ (void) sprintf( key, "Uni%d", axis + 1 );
+ astWriteString( channel, key, 0, helpful, sval, comment );
+ }
+
+/* Digits. */
+/* ------- */
+/* There is a Digits value for each axis... */
+ digits_set = 0;
+ for ( axis = 0; axis < naxes; axis++ ) {
+
+/* Obtain the axis Digits value, using the Frame's Digits value as a
+ default. */
+ ax = astGetAxis( this, invperm[ axis ] );
+ set = astTestAxisDigits( ax );
+ ival = set ? astGetAxisDigits( ax ) : astGetDigits( this );
+ ax = astAnnul( ax );
+
+/* Show the value if it is set for the axis (i.e. if it differs from
+ the default for the whole Frame) and note if any such value is
+ set. */
+ helpful = set;
+ if ( set ) digits_set = 1;
+ (void) sprintf( key, "Dig%d", axis + 1 );
+ (void) sprintf( comment, "Individual precision for axis %d",
+ axis + 1 );
+ astWriteInt( channel, key, 0, helpful, ival, comment );
+ }
+
+/* There is also a Digits value for the Frame as a whole... */
+ set = TestDigits( this, status );
+
+/* Show the value (even if not set) if an explicit Digits value has
+ been set for any axis (above). */
+ helpful = digits_set;
+ ival = set ? GetDigits( this, status ) : astGetDigits( this );
+ astWriteInt( channel, "Digits", set, helpful, ival,
+ "Default formatting precision" );
+
+/* Format. */
+/* ------- */
+/* There is a Format value for each axis. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+ sval = astGetFormat( this, invperm[ axis ] );
+
+/* Show the Format value if the Digits value is set for an individual
+ axis. */
+ ax = astGetAxis( this, invperm[ axis ] );
+ helpful = astTestAxisDigits( ax );
+ ax = astAnnul( ax );
+ (void) sprintf( key, "Fmt%d", axis + 1 );
+ (void) sprintf( comment, "Format specifier for axis %d", axis + 1 );
+ astWriteString( channel, key, 0, helpful, sval, comment );
+ }
+
+/* Direction. */
+/* ---------- */
+/* There is a Direction value for each axis. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+ ival = astGetDirection( this, invperm[ axis ] );
+
+/* Show the value if it is zero. */
+ helpful = ( ival == 0 );
+ (void) sprintf( key, "Dir%d", axis + 1 );
+ (void) sprintf( comment,
+ ival ? "Plot axis %d in conventional direction" :
+ "Plot axis %d in reverse direction",
+ axis + 1 );
+ astWriteInt( channel, key, 0, helpful, ival, comment );
+ }
+
+/* Bottom. */
+/* ------- */
+/* There is a Bottom value for each axis. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+ dval = astGetBottom( this, invperm[ axis ] );
+
+/* Show the value if it is zero. */
+ helpful = ( dval != -DBL_MAX );
+ (void) sprintf( key, "Bot%d", axis + 1 );
+ astWriteDouble( channel, key, 0, helpful, dval, "Lowest legal axis value");
+ }
+
+/* Top. */
+/* ------- */
+/* There is a Top value for each axis. */
+ for ( axis = 0; axis < naxes; axis++ ) {
+ dval = astGetTop( this, invperm[ axis ] );
+
+/* Show the value if it is zero. */
+ helpful = ( dval != DBL_MAX );
+ (void) sprintf( key, "Top%d", axis + 1 );
+ astWriteDouble( channel, key, 0, helpful, dval, "Highest legal axis value");
+ }
+
+/* PreserveAxes. */
+/* ------------- */
+ set = TestPreserveAxes( this, status );
+ ival = set ? GetPreserveAxes( this, status ) : astGetPreserveAxes( this );
+ astWriteInt( channel, "Presrv", set, 0, ival,
+ ival ? "Preserve target axes" :
+ "Don't preserve target axes" );
+
+/* Permute. */
+/* -------- */
+ set = TestPermute( this, status );
+ ival = set ? GetPermute( this, status ) : astGetPermute( this );
+ astWriteInt( channel, "Permut", set, 0, ival,
+ ival ? "Axes may be permuted to match" :
+ "Axes may not be permuted match" );
+
+/* MinAxes. */
+/* -------- */
+ set = TestMinAxes( this, status );
+ ival = set ? GetMinAxes( this, status ) : astGetMinAxes( this );
+ astWriteInt( channel, "MinAx", set, 0, ival,
+ "Minimum number of axes to match" );
+
+/* MaxAxes. */
+/* -------- */
+ set = TestMaxAxes( this, status );
+ ival = set ? GetMaxAxes( this, status ) : astGetMaxAxes( this );
+ astWriteInt( channel, "MaxAx", set, 0, ival,
+ "Maximum number of axes to match" );
+
+/* MatchEnd. */
+/* --------- */
+ set = TestMatchEnd( this, status );
+ ival = set ? GetMatchEnd( this, status ) : astGetMatchEnd( this );
+ astWriteInt( channel, "MchEnd", set, 0, ival,
+ ival ? "Match final target axes" :
+ "Match initial target axes" );
+
+/* ObsLat. */
+/* ------- */
+ set = TestObsLat( this, status );
+ dval = set ? GetObsLat( this, status ) : astGetObsLat( this );
+ astWriteDouble( channel, "ObsLat", set, 0, dval, "Observers geodetic latitude (rads)" );
+
+/* ObsLon. */
+/* ------- */
+ set = TestObsLon( this, status );
+ dval = set ? GetObsLon( this, status ) : astGetObsLon( this );
+ astWriteDouble( channel, "ObsLon", set, 0, dval, "Observers geodetic longitude (rads)" );
+
+/* ObsAlt. */
+/* ------- */
+ set = TestObsAlt( this, status );
+ dval = set ? GetObsAlt( this, status ) : astGetObsAlt( this );
+ astWriteDouble( channel, "ObsAlt", set, 0, dval, "Observers geodetic altitude (metres)" );
+
+/* Dtai*/
+/* ---- */
+ set = TestDtai( this, status );
+ dval = set ? GetDtai( this, status ) : astGetDtai( this );
+ astWriteDouble( channel, "Dtai", set, 0, dval, "TAI-UTC in seconds" );
+
+/* Dut1*/
+/* ---- */
+ set = TestDut1( this, status );
+ dval = set ? GetDut1( this, status ) : astGetDut1( this );
+ astWriteDouble( channel, "Dut1", set, 0, dval, "UT1-UTC in seconds" );
+
+
+/* ActiveUnit. */
+/* ----------- */
+ if( astTestActiveUnit( this ) ) {
+ ival = astGetActiveUnit( this );
+ astWriteInt( channel, "ActUnt", 1, 0, ival,
+ ival ? "Unit strings affects alignment" :
+ "Unit strings do not affect alignment" );
+ }
+
+/* Axis permutation array. */
+/* ----------------------- */
+/* Write out the axis permutation array value for each axis,
+ converting to 1-based axis numbering. */
+ for ( axis = 0; axis < this->naxes; axis++ ) {
+ set = ( this->perm[ axis ] != axis );
+ ival = this->perm[ axis ] + 1;
+
+/* Create a keyword and comment appropriate to the axis. */
+ (void) sprintf( key, "Prm%d", axis + 1 );
+ if ( set ) {
+ (void) sprintf( comment,
+ "Axis %d permuted to use internal axis %d",
+ axis + 1, ival );
+ } else {
+ (void) sprintf( comment, "Axis %d not permuted", axis + 1 );
+ }
+ astWriteInt( channel, key, set, 0, ival, comment );
+ }
+
+/* Axis Objects. */
+/* ------------- */
+/* Temporarily set the Channel's Full attribute to -1 (unless it is +1
+ to start with), remembering the original setting. This prevents any
+ unnecessary "un-set" Axis values being output that would otherwise
+ simply duplicate the Frame's attributes which have already been
+ written. "Set" Axis values are still written, however (and all
+ values are written if Full is set to 1). */
+ full_set = astTestFull( channel );
+ full = astGetFull( channel );
+ if ( full <= 0 ) astSetFull( channel, -1 );
+
+/* Handle each axis in turn. */
+ for ( axis = 0; axis < this->naxes; axis++ ) {
+
+/* Create a keyword and comment appropriate to the axis (converting to
+ 1-based axis numbering). */
+ (void) sprintf( key, "Ax%d", axis + 1 );
+ (void) sprintf( comment, "Axis number %d", axis + 1 );
+
+/* Write out the axis Object description. */
+ astWriteObject( channel, key, 1, 0, this->axis[ axis ], comment );
+ }
+
+/* Restore the Channel's original Full attribute setting. */
+ if ( full_set ) {
+ astSetFull( channel, full );
+ } else {
+ astClearFull( channel );
+ }
+
+/* Free the inverse axis permutation array. */
+ invperm = astFree( invperm );
+
+/* Variants */
+/* ------- */
+ if( this->variants ) astWriteObject( channel, "Vrnts", 1, 0,
+ this->variants, "Variant Frames" );
+ }
+
+/* Undefine macros local to this function. */
+#undef COMMENT_LEN
+#undef KEY_LEN
+}
+
+/* Standard class functions. */
+/* ========================= */
+/* Implement the astIsAFrame and astCheckFrame functions using the macros
+ defined for this purpose in the "object.h" header file. */
+astMAKE_ISA(Frame,Mapping)
+astMAKE_CHECK(Frame)
+
+AstFrame *astFrame_( int naxes, const char *options, int *status, ...) {
+/*
+*+
+* Name:
+* astFrame
+
+* Purpose:
+* Create a Frame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frame.h"
+* AstFrame *astFrame( int naxes, const char *options, int *status, ... )
+
+* Class Membership:
+* Frame constructor.
+
+* Description:
+* This function creates a new Frame and optionally initialises its
+* attributes.
+
+* Parameters:
+* naxes
+* The number of Frame axes.
+* options
+* Pointer to a null terminated string containing an optional
+* comma-separated list of attribute assignments to be used for
+* initialising the new Frame. The syntax used is the same as
+* for the astSet method and may include "printf" format
+* specifiers identified by "%" symbols in the normal way.
+* status
+* Pointer to the inherited status variable.
+* ...
+* If the "options" string contains "%" format specifiers, then
+* an optional list of arguments may follow it in order to
+* supply values to be substituted for these specifiers. The
+* rules for supplying these are identical to those for the
+* astSet method (and for the C "printf" function).
+
+* Returned Value:
+* A pointer to the new Frame.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+
+* Implementation Notes:
+* - This function implements the basic Frame constructor which is
+* available via the protected interface to the Frame class. A
+* public interface is provided by the astFrameId_ function.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstFrame *new; /* Pointer to new Frame */
+ va_list args; /* Variable argument list */
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Initialise the Frame, allocating memory and initialising the virtual
+ function table as well if necessary. */
+ new = astInitFrame( NULL, sizeof( AstFrame ), !class_init, &class_vtab,
+ "Frame", naxes );
+
+/* If successful, note that the virtual function table has been initialised. */
+ if ( astOK ) {
+ class_init = 1;
+
+/* Obtain the variable argument list and pass it along with the options string
+ to the astVSet method to initialise the new Frame's attributes. */
+ va_start( args, status );
+ astVSet( new, options, NULL, args );
+ va_end( args );
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return a pointer to the new Frame. */
+ return new;
+}
+
+AstFrame *astInitFrame_( void *mem, size_t size, int init,
+ AstFrameVtab *vtab, const char *name,
+ int naxes, int *status ) {
+/*
+*+
+* Name:
+* astInitFrame
+
+* Purpose:
+* Initialise a Frame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frame.h"
+* AstFrame *astInitFrame( void *mem, size_t size, int init,
+* AstFrameVtab *vtab, const char *name,
+* int naxes )
+
+* Class Membership:
+* Frame initialiser.
+
+* Description:
+* This function is provided for use by class implementations to initialise
+* a new Frame object. It allocates memory (if necessary) to accommodate
+* the Frame plus any additional data associated with the derived class.
+* It then initialises a Frame structure at the start of this memory. If
+* the "init" flag is set, it also initialises the contents of a virtual
+* function table for a Frame at the start of the memory passed via the
+* "vtab" parameter.
+
+* Parameters:
+* mem
+* A pointer to the memory in which the Frame is to be created. This
+* must be of sufficient size to accommodate the Frame data
+* (sizeof(Frame)) plus any data used by the derived class. If a value
+* of NULL is given, this function will allocate the memory itself using
+* the "size" parameter to determine its size.
+* size
+* The amount of memory used by the Frame (plus derived class data).
+* This will be used to allocate memory if a value of NULL is given for
+* the "mem" parameter. This value is also stored in the Frame
+* structure, so a valid value must be supplied even if not required for
+* allocating memory.
+* init
+* A logical flag indicating if the Frame's virtual function table is
+* to be initialised. If this value is non-zero, the virtual function
+* table will be initialised by this function.
+* vtab
+* Pointer to the start of the virtual function table to be associated
+* with the new Frame.
+* name
+* Pointer to a constant null-terminated character string which contains
+* the name of the class to which the new object belongs (it is this
+* pointer value that will subsequently be returned by the astGetClass
+* method).
+* naxes
+* The number of Frame axes.
+
+* Returned Value:
+* A pointer to the new Frame.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstFrame *new; /* Pointer to new Frame */
+ int axis; /* Loop counter for Frame axes */
+
+/* Check the global status. */
+ if ( !astOK ) return NULL;
+
+/* If necessary, initialise the virtual function table. */
+ if ( init ) astInitFrameVtab( vtab, name );
+
+/* Initialise. */
+ new = NULL;
+
+/* Check the number of axes for validity, reporting an error if necessary. */
+ if ( naxes < 0 ) {
+ astError( AST__NAXIN, "astInitFrame(%s): Number of axes (%d) is "
+ "invalid - this number should not be negative.", status, name, naxes );
+
+/* Initialise a Mapping structure (the parent class) as the first
+ component within the Frame structure, allocating memory if
+ necessary. Set the number of input/output coordinates to zero (the
+ astGetNin and astGetNout methods are over-ridden by the Frame class
+ to provide values for these that are equal to the number of Frame
+ axes). */
+ } else {
+ new = (AstFrame *) astInitMapping( mem, size, 0,
+ (AstMappingVtab *) vtab, name,
+ 0, 0, 1, 1 );
+
+ if ( astOK ) {
+
+/* Initialise the Frame data. */
+/* ----------------------------- */
+/* Set the number of Frame axes. */
+ new->naxes = naxes;
+
+/* Initialise all attributes to their "undefined" values. */
+ new->digits = -INT_MAX;
+ new->domain = NULL;
+ new->epoch = AST__BAD;
+ new->match_end = -INT_MAX;
+ new->max_axes = -INT_MAX;
+ new->min_axes = -INT_MAX;
+ new->permute = -INT_MAX;
+ new->preserve_axes = -INT_MAX;
+ new->title = NULL;
+ new->system = AST__BADSYSTEM;
+ new->alignsystem = AST__BADSYSTEM;
+ new->active_unit = -INT_MAX;
+ new->obsalt = AST__BAD;
+ new->obslat = AST__BAD;
+ new->obslon = AST__BAD;
+ new->dtai = AST__BAD;
+ new->dut1 = AST__BAD;
+ new->flags = 0;
+ new->variants = NULL;
+
+/* Allocate memory to store pointers to the Frame's Axis objects and to store
+ its axis permutation array. */
+ new->axis = astMalloc( sizeof( AstAxis * ) * (size_t) naxes );
+ new->perm = astMalloc( sizeof( int ) * (size_t) naxes );
+
+/* Create a new Axis object to describe each axis of the Frame and store the
+ resulting pointers in the memory allocated above. Also initialise the
+ axis permutation array so that the axes appear in their natural order. */
+ if ( astOK ) {
+ for ( axis = 0; axis < naxes; axis++ ) {
+ new->axis[ axis ] = astAxis( "", status );
+ new->perm[ axis ] = axis;
+ }
+
+/* If an error occurred while creating the Axis objects, scan through the array
+ of pointers to them again to ensure that they are all correctly annulled. */
+ if ( !astOK ) {
+ for ( axis = 0; axis < naxes; axis++ ) {
+ new->axis[ axis ] = astAnnul( new->axis[ axis ] );
+ }
+ }
+ }
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+ }
+
+/* Return a pointer to the new object. */
+ return new;
+}
+
+AstFrame *astLoadFrame_( void *mem, size_t size,
+ AstFrameVtab *vtab, const char *name,
+ AstChannel *channel, int *status ) {
+/*
+*+
+* Name:
+* astLoadFrame
+
+* Purpose:
+* Load a Frame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "frame.h"
+* AstFrame *astLoadFrame( void *mem, size_t size,
+* AstFrameVtab *vtab, const char *name,
+* AstChannel *channel )
+
+* Class Membership:
+* Frame loader.
+
+* Description:
+* This function is provided to load a new Frame using data read
+* from a Channel. It first loads the data used by the parent class
+* (which allocates memory if necessary) and then initialises a
+* Frame structure in this memory, using data read from the input
+* Channel.
+*
+* If the "init" flag is set, it also initialises the contents of a
+* virtual function table for a Frame at the start of the memory
+* passed via the "vtab" parameter.
+
+
+* Parameters:
+* mem
+* A pointer to the memory into which the Frame is to be loaded.
+* This must be of sufficient size to accommodate the Frame data
+* (sizeof(Frame)) plus any data used by derived classes. If a
+* value of NULL is given, this function will allocate the
+* memory itself using the "size" parameter to determine its
+* size.
+* size
+* The amount of memory used by the Frame (plus derived class
+* data). This will be used to allocate memory if a value of
+* NULL is given for the "mem" parameter. This value is also
+* stored in the Frame structure, so a valid value must be
+* supplied even if not required for allocating memory.
+*
+* If the "vtab" parameter is NULL, the "size" value is ignored
+* and sizeof(AstFrame) is used instead.
+* vtab
+* Pointer to the start of the virtual function table to be
+* associated with the new Frame. If this is NULL, a pointer to
+* the (static) virtual function table for the Frame class is
+* used instead.
+* name
+* Pointer to a constant null-terminated character string which
+* contains the name of the class to which the new object
+* belongs (it is this pointer value that will subsequently be
+* returned by the astGetClass method).
+*
+* If the "vtab" parameter is NULL, the "name" value is ignored
+* and a pointer to the string "Frame" is used instead.
+
+* Returned Value:
+* A pointer to the new Frame.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Constants: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+#define KEY_LEN 50 /* Maximum length of a keyword */
+
+/* Local Variables: */
+ AstFrame *new; /* Pointer to the new Frame */
+ char *sval; /* Pointer to string value */
+ char key[ KEY_LEN + 1 ]; /* Buffer for keywords */
+ double dval; /* DOuble attribute value */
+ int axis; /* Loop counter for axes */
+ int ival; /* Integer value */
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(channel);
+
+/* Initialise. */
+ new = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return new;
+
+/* If a NULL virtual function table has been supplied, then this is
+ the first loader to be invoked for this Frame. In this case the
+ Frame belongs to this class, so supply appropriate values to be
+ passed to the parent class loader (and its parent, etc.). */
+ if ( !vtab ) {
+ size = sizeof( AstFrame );
+ vtab = &class_vtab;
+ name = "Frame";
+
+/* If required, initialise the virtual function table for this class. */
+ if ( !class_init ) {
+ astInitFrameVtab( vtab, name );
+ class_init = 1;
+ }
+ }
+
+/* Invoke the parent class loader to load data for all the ancestral
+ classes of the current one, returning a pointer to the resulting
+ partly-built Frame. */
+ new = astLoadMapping( mem, size, (AstMappingVtab *) vtab, name,
+ channel );
+
+ if ( astOK ) {
+
+/* Assign values for transient components that are not included in the
+ Frame dump */
+ new->flags = 0;
+
+/* Read input data. */
+/* ================ */
+/* Request the input Channel to read all the input data appropriate to
+ this class into the internal "values list". */
+ astReadClassData( channel, "Frame" );
+
+/* Now read each individual data item from this list and use it to
+ initialise the appropriate instance variable(s) for this class. */
+
+/* In the case of attributes, we first read the "raw" input value,
+ supplying the "unset" value as the default. If a "set" value is
+ obtained, we then use the appropriate (private) Set... member
+ function to validate and set the value properly. */
+
+/* Naxes. */
+/* ------ */
+/* Obtain the number of Frame axes and allocate memory for the arrays
+ which hold axis information. */
+ new->naxes = astReadInt( channel, "naxes", 0 );
+ if ( new->naxes < 0 ) new->naxes = 0;
+ new->perm = astMalloc( sizeof( int ) * (size_t) new->naxes );
+ new->axis = astMalloc( sizeof( AstAxis * ) * (size_t) new->naxes );
+
+/* If an error occurred, ensure that any allocated memory is freed. */
+ if ( !astOK ) {
+ new->perm = astFree( new->perm );
+ new->axis = astFree( new->axis );
+
+/* Otherwise, initialise the array of Axis pointers. */
+ } else {
+ for ( axis = 0; axis < new->naxes; axis++ ) new->axis[ axis ] = NULL;
+
+/* Now obtain those input values which are required for each axis... */
+ for ( axis = 0; axis < new->naxes; axis++ ) {
+
+/* Axis object. */
+/* ------------ */
+/* This must be read first, so that it can hold the other axis values
+ obtained below. */
+
+/* Create a keyword appropriate to this axis. */
+ (void) sprintf( key, "ax%d", axis + 1 );
+
+/* Read the Axis object. If none was read, provide a default Axis
+ instead. */
+ new->axis[ axis ] = astReadObject( channel, key, NULL );
+ if ( !new->axis[ axis ] ) new->axis[ axis ] = astAxis( "", status );
+
+/* Label. */
+/* ------ */
+/* Read the Label string for each axis. If a value is obtained, use
+ it to set the Label attribute for the axis. Free the memory holding
+ the string when no longer needed. */
+ (void) sprintf( key, "lbl%d", axis + 1 );
+ sval = astReadString( channel, key, NULL );
+ if ( sval ) {
+ astSetAxisLabel( new->axis[ axis ], sval );
+ sval = astFree( sval );
+ }
+
+/* Symbol. */
+/* ------- */
+ (void) sprintf( key, "sym%d", axis + 1 );
+ sval = astReadString( channel, key, NULL );
+ if ( sval ) {
+ astSetAxisSymbol( new->axis[ axis ], sval );
+ sval = astFree( sval );
+ }
+
+/* Format. */
+/* ------- */
+ (void) sprintf( key, "fmt%d", axis + 1 );
+ sval = astReadString( channel, key, NULL );
+ if ( sval ) {
+ astSetAxisFormat( new->axis[ axis ], sval );
+ sval = astFree( sval );
+ }
+
+/* Unit. */
+/* ----- */
+ (void) sprintf( key, "uni%d", axis + 1 );
+ sval = astReadString( channel, key, NULL );
+ if ( sval ) {
+ astSetAxisUnit( new->axis[ axis ], sval );
+ sval = astFree( sval );
+ }
+
+/* Direction. */
+/* ---------- */
+ (void) sprintf( key, "dir%d", axis + 1 );
+ ival = astReadInt( channel, key, -INT_MAX );
+ if ( ival != -INT_MAX ) {
+ astSetAxisDirection( new->axis[ axis ], ival );
+ }
+
+/* Top. */
+/*----- */
+ (void) sprintf( key, "top%d", axis + 1 );
+ dval = astReadDouble( channel, key, AST__BAD );
+ if ( dval != AST__BAD ) {
+ astSetAxisTop( new->axis[ axis ], dval );
+ }
+
+/* Bottom. */
+/*----- -- */
+ (void) sprintf( key, "bot%d", axis + 1 );
+ dval = astReadDouble( channel, key, AST__BAD );
+ if ( dval != AST__BAD ) {
+ astSetAxisBottom( new->axis[ axis ], dval );
+ }
+
+/* Digits. */
+/* ------- */
+ (void) sprintf( key, "dig%d", axis + 1 );
+ ival = astReadInt( channel, key, -INT_MAX );
+ if ( ival != -INT_MAX ) {
+ astSetAxisDigits( new->axis[ axis ], ival );
+ }
+
+/* Axis permutation array. */
+/* ----------------------- */
+/* Convert from 1-based to zero-based axis numbering at this
+ point. The default is the "un-permuted" value. */
+ sprintf( key, "prm%d", axis + 1 );
+ new->perm[ axis ] = astReadInt( channel, key, axis + 1 ) - 1;
+
+/* Quit looping if an error occurs. */
+ if ( !astOK ) break;
+ }
+
+/* The remaining values are not associated with particular axes... */
+
+/* Title. */
+/* ------ */
+ new->title = astReadString( channel, "title", NULL );
+
+/* Domain. */
+/* ------- */
+ new->domain = astReadString( channel, "domain", NULL );
+
+/* Epoch. */
+/* ------ */
+/* Interpret this as Besselian or Julian depending on its value. */
+ new->epoch = astReadDouble( channel, "epoch", AST__BAD );
+ if ( TestEpoch( new, status ) ) {
+ SetEpoch( new, ( new->epoch < 1984.0 ) ? palEpb2d( new->epoch ) :
+ palEpj2d( new->epoch ), status );
+ }
+
+/* Digits. */
+/* ------- */
+/* This is the value that applies to the Frame as a whole. */
+ new->digits = astReadInt( channel, "digits", -INT_MAX );
+ if ( TestDigits( new, status ) ) SetDigits( new, new->digits, status );
+
+/* PreserveAxes. */
+/* ------------- */
+ new->preserve_axes = astReadInt( channel, "presrv", -INT_MAX );
+ if ( TestPreserveAxes( new, status ) ) {
+ SetPreserveAxes( new, new->preserve_axes, status );
+ }
+
+/* Permute. */
+/* -------- */
+ new->permute = astReadInt( channel, "permut", -INT_MAX );
+ if ( TestPermute( new, status ) ) SetPermute( new, new->permute, status );
+
+/* MinAxes. */
+/* -------- */
+ new->min_axes = astReadInt( channel, "minax", -INT_MAX );
+ if ( TestMinAxes( new, status ) ) SetMinAxes( new, new->min_axes, status );
+
+/* MaxAxes. */
+/* -------- */
+ new->max_axes = astReadInt( channel, "maxax", -INT_MAX );
+ if ( TestMaxAxes( new, status ) ) SetMaxAxes( new, new->max_axes, status );
+
+/* MatchEnd. */
+/* --------- */
+ new->match_end = astReadInt( channel, "mchend", -INT_MAX );
+ if ( TestMatchEnd( new, status ) ) SetMatchEnd( new, new->match_end, status );
+
+/* ObsLat. */
+/* ------- */
+ new->obslat = astReadDouble( channel, "obslat", AST__BAD );
+ if ( TestObsLat( new, status ) ) SetObsLat( new, new->obslat, status );
+
+/* ObsLon. */
+/* ------- */
+ new->obslon = astReadDouble( channel, "obslon", AST__BAD );
+ if ( TestObsLon( new, status ) ) SetObsLon( new, new->obslon, status );
+
+/* ObsAlt. */
+/* ------- */
+ new->obsalt = astReadDouble( channel, "obsalt", AST__BAD );
+ if ( TestObsAlt( new, status ) ) SetObsAlt( new, new->obsalt, status );
+
+/* Dtai. */
+/* ---- */
+ new->dtai = astReadDouble( channel, "dtai", AST__BAD );
+ if ( TestDtai( new, status ) ) SetDtai( new, new->dtai, status );
+
+/* Dut1. */
+/* ---- */
+ new->dut1 = astReadDouble( channel, "dut1", AST__BAD );
+ if ( TestDut1( new, status ) ) SetDut1( new, new->dut1, status );
+
+/* ActiveUnit. */
+/* ----------- */
+ new->active_unit = astReadInt( channel, "actunt", -INT_MAX );
+ if ( TestActiveUnit( new, status ) ) SetActiveUnit( new, new->active_unit, status );
+
+/* System. */
+/* ------- */
+/* Set the default and read the external representation as a string. */
+ new->system = AST__BADSYSTEM;
+ sval = astReadString( channel, "system", NULL );
+
+/* If a value was read, convert from a string to a System code. */
+ if ( sval ) {
+ if ( astOK ) {
+ new->system = astSystemCode( new, sval );
+
+/* Report an error if the value wasn't recognised. */
+ if ( new->system == AST__BADSYSTEM ) {
+ astError( AST__ATTIN,
+ "astRead(%s): Invalid System description "
+ "\"%s\".", status, astGetClass( channel ), sval );
+ }
+ }
+
+/* Free the string value. */
+ sval = astFree( sval );
+ }
+
+/* AlignSystem. */
+/* ------------ */
+/* Set the default and read the external representation as a string. */
+ new->alignsystem = AST__BADSYSTEM;
+ sval = astReadString( channel, "alsys", NULL );
+
+/* If a value was read, convert from a string to a System code. */
+ if ( sval ) {
+ if ( astOK ) {
+ new->alignsystem = astSystemCode( new, sval );
+
+/* Report an error if the value wasn't recognised. */
+ if ( new->alignsystem == AST__BADSYSTEM ) {
+ astError( AST__ATTIN,
+ "astRead(%s): Invalid AlignSystem description "
+ "\"%s\".", status, astGetClass( channel ), sval );
+ }
+ }
+
+/* Free the string value. */
+ sval = astFree( sval );
+ }
+
+/* Variants. */
+/* -------- */
+ new->variants = astReadObject( channel, "vrnts", NULL );
+ }
+
+/* If an error occurred, clean up by deleting the new Frame. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return the new Frame pointer. */
+ return new;
+
+/* Undefine macros local to this function. */
+#undef KEY_LEN
+}
+
+/* Virtual function interfaces. */
+/* ============================ */
+/* These provide the external interface to the virtual functions defined by
+ this class. Each simply checks the global error status and then locates and
+ executes the appropriate member function, using the function pointer stored
+ in the object's virtual function table (this pointer is located using the
+ astMEMBER macro defined in "object.h").
+
+ Note that the member function may not be the one defined here, as it may
+ have been over-ridden by a derived class. However, it should still have the
+ same interface. */
+const char *astAbbrev_( AstFrame *this, int axis, const char *fmt,
+ const char *str1, const char *str2, int *status ) {
+ if ( !astOK ) return str2;
+ return (**astMEMBER(this,Frame,Abbrev))( this, axis, fmt, str1, str2, status );
+}
+int astFields_( AstFrame *this, int axis, const char *fmt,
+ const char *str, int maxfld, char **fields,
+ int *nc, double *val, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,Fields))( this, axis, fmt, str, maxfld, fields, nc, val, status );
+}
+void astCheckPerm_( AstFrame *this, const int *perm, const char *method, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,CheckPerm))( this, perm, method, status );
+}
+
+AstPointSet *astResolvePoints_( AstFrame *this, const double point1[],
+ const double point2[], AstPointSet *in,
+ AstPointSet *out, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,ResolvePoints))( this, point1, point2, in, out, status );
+}
+AstLineDef *astLineDef_( AstFrame *this, const double start[2],
+ const double end[2], int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,LineDef))( this, start, end, status );
+}
+int astLineCrossing_( AstFrame *this, AstLineDef *l1, AstLineDef *l2,
+ double **cross, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,LineCrossing))( this, l1, l2, cross, status );
+}
+void astLineOffset_( AstFrame *this, AstLineDef *line, double par, double prp,
+ double point[2], int *status ){
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,LineOffset))( this, line, par, prp, point, status );
+}
+int astLineContains_( AstFrame *this, AstLineDef *l, int def, double *point, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,LineContains))( this, l, def, point, status );
+}
+AstFrameSet *astConvert_( AstFrame *from, AstFrame *to,
+ const char *domainlist, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(from,Frame,Convert))( from, to, domainlist, status );
+}
+AstFrameSet *astConvertX_( AstFrame *to, AstFrame *from,
+ const char *domainlist, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(to,Frame,ConvertX))( to, from, domainlist, status );
+}
+double astAngle_( AstFrame *this, const double a[], const double b[],
+ const double c[], int *status ) {
+ if ( !astOK ) return AST__BAD;
+ return (**astMEMBER(this,Frame,Angle))( this, a, b, c, status );
+}
+int astGetActiveUnit_( AstFrame *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,GetActiveUnit))( this, status );
+}
+int astTestActiveUnit_( AstFrame *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,TestActiveUnit))( this, status );
+}
+void astSetActiveUnit_( AstFrame *this, int value, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,SetActiveUnit))( this, value, status );
+}
+double astDistance_( AstFrame *this,
+ const double point1[], const double point2[], int *status ) {
+ if ( !astOK ) return AST__BAD;
+ return (**astMEMBER(this,Frame,Distance))( this, point1, point2, status );
+}
+AstFrameSet *astFindFrame_( AstFrame *target, AstFrame *template,
+ const char *domainlist, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(target,Frame,FindFrame))( target, template, domainlist, status );
+}
+void astMatchAxes_( AstFrame *frm1, AstFrame *frm2, int *axes, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(frm1,Frame,MatchAxes))( frm1, frm2, axes, status );
+}
+void astMatchAxesX_( AstFrame *frm2, AstFrame *frm1, int *axes, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(frm2,Frame,MatchAxesX))( frm2, frm1, axes, status );
+}
+const char *astFormat_( AstFrame *this, int axis, double value, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,Format))( this, axis, value, status );
+}
+double astCentre_( AstFrame *this, int axis, double value, double gap, int *status ) {
+ if ( !astOK ) return 0.0;
+ return (**astMEMBER(this,Frame,Centre))( this, axis, value, gap, status );
+}
+double astGap_( AstFrame *this, int axis, double gap, int *ntick, int *status ) {
+ if ( !astOK ) return 0.0;
+ return (**astMEMBER(this,Frame,Gap))( this, axis, gap, ntick, status );
+}
+AstAxis *astGetAxis_( AstFrame *this, int axis, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,GetAxis))( this, axis, status );
+}
+int astGetNaxes_( AstFrame *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,GetNaxes))( this, status );
+}
+const int *astGetPerm_( AstFrame *this, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,GetPerm))( this, status );
+}
+AstFrameSet *astGetFrameVariants_( AstFrame *this, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,GetFrameVariants))( this, status );
+}
+void astSetFrameVariants_( AstFrame *this, AstFrameSet *variants, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,SetFrameVariants))( this, variants, status );
+}
+
+
+int astMatch_( AstFrame *this, AstFrame *target, int matchsub,
+ int **template_axes, int **target_axes,
+ AstMapping **map, AstFrame **result, int *status ) {
+
+ AstFrame *super_this;
+ const char *dom;
+ int match;
+
+ if ( !astOK ) return 0;
+
+ match = (**astMEMBER(this,Frame,Match))( this, target, matchsub,
+ template_axes, target_axes,
+ map, result, status );
+
+/* If the template ("this") could not be used to probe the target, it may
+ be because the template class is a more specialised form of the target
+ class. E.g. a SkyFrame cannot directly be used to probe a Frame, but a
+ Frame *can* be used to probe a SkyFrame. This means (for instance),
+ that a basic Frame with Domain FRED cannot be aligned (using astConvert)
+ with a CmpFrame with Domain FRED. This sort of alignment is often
+ useful, so we try now to use the supplied template to probe a modified
+ form of the target that has been cast into the same class as the
+ template. This is only possible if the template class is a sub-class of
+ the target class. Attempt to do the cast. */
+ if( ! match && matchsub ) {
+ super_this = (AstFrame *) astCast( this, target );
+
+/* If the cast was possible, fix the template Domain since the parent
+ class may provide a different default Domain, and then invoke the Match
+ method appropriate to the new template class (i.e. the target class). */
+ if( super_this ) {
+ if( astTestDomain( target ) ) {
+ dom = astGetDomain( this );
+ if( astChrLen( dom ) > 0 ) astSetDomain( super_this, dom );
+ }
+ match = (**astMEMBER(super_this,Frame,Match))( super_this, target,
+ matchsub, template_axes,
+ target_axes, map,
+ result, status );
+ super_this = astAnnul( super_this );
+ }
+ }
+
+ return match;
+}
+
+
+int astIsUnitFrame_( AstFrame *this, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,IsUnitFrame))( this, status );
+}
+void astNorm_( AstFrame *this, double value[], int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,Norm))( this, value, status );
+}
+void astNormBox_( AstFrame *this, double lbnd[], double ubnd[], AstMapping *reg, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,NormBox))( this, lbnd, ubnd, reg, status );
+}
+double astAxDistance_( AstFrame *this, int axis, double v1, double v2, int *status ) {
+ if ( !astOK ) return AST__BAD;
+ return (**astMEMBER(this,Frame,AxDistance))( this, axis, v1, v2, status );
+}
+void astAxNorm_( AstFrame *this, int axis, int oper, int nval, double *values,
+ int *status ){
+ if ( !astOK ) return;
+ return (**astMEMBER(this,Frame,AxNorm))( this, axis, oper, nval, values, status );
+}
+double astAxOffset_( AstFrame *this, int axis, double v1, double dist, int *status ) {
+ if ( !astOK ) return AST__BAD;
+ return (**astMEMBER(this,Frame,AxOffset))( this, axis, v1, dist, status );
+}
+
+
+AstPointSet *astFrameGrid_( AstFrame *this, int size, const double *lbnd,
+ const double *ubnd, int *status ){
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,FrameGrid))( this, size, lbnd, ubnd, status );
+}
+
+
+void astOffset_( AstFrame *this, const double point1[], const double point2[],
+ double offset, double point3[], int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,Offset))( this, point1, point2, offset, point3, status );
+}
+double astAxAngle_( AstFrame *this, const double a[2], const double b[2],
+ int axis, int *status ) {
+ if ( !astOK ) return AST__BAD;
+ return (**astMEMBER(this,Frame,AxAngle))( this, a, b, axis, status );
+}
+double astOffset2_( AstFrame *this, const double point1[2], double angle,
+ double offset, double point2[2], int *status ) {
+ if ( !astOK ) return AST__BAD;
+ return (**astMEMBER(this,Frame,Offset2))( this, point1, angle, offset, point2, status );
+}
+void astIntersect_( AstFrame *this, const double a1[2],
+ const double a2[2], const double b1[2],
+ const double b2[2], double cross[2],
+ int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,Intersect))( this, a1, a2, b1, b2, cross, status );
+}
+void astOverlay_( AstFrame *template, const int *template_axes,
+ AstFrame *result, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(template,Frame,Overlay))( template, template_axes, result, status );
+}
+void astPermAxes_( AstFrame *this, const int perm[], int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,PermAxes))( this, perm, status );
+}
+AstFrame *astPickAxes_( AstFrame *this, int naxes, const int axes[],
+ AstMapping **map, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,PickAxes))( this, naxes, axes, map, status );
+}
+void astPrimaryFrame_( AstFrame *this, int axis1,
+ AstFrame **frame, int *axis2, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,PrimaryFrame))( this, axis1, frame, axis2, status );
+}
+void astResolve_( AstFrame *this, const double point1[], const double point2[],
+ const double point3[], double point4[], double *d1,
+ double *d2, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,Resolve))( this, point1, point2, point3, point4, d1, d2, status );
+}
+void astSetAxis_( AstFrame *this, int axis, AstAxis *newaxis, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,SetAxis))( this, axis, newaxis, status );
+}
+void astSetUnit_( AstFrame *this, int axis, const char *value, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,SetUnit))( this, axis, value, status );
+}
+void astClearUnit_( AstFrame *this, int axis, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,ClearUnit))( this, axis, status );
+}
+int astSubFrame_( AstFrame *target, AstFrame *template, int result_naxes,
+ const int *target_axes, const int *template_axes,
+ AstMapping **map, AstFrame **result, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(target,Frame,SubFrame))( target, template, result_naxes,
+ target_axes, template_axes,
+ map, result, status );
+}
+int astUnformat_( AstFrame *this, int axis, const char *string,
+ double *value, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,Unformat))( this, axis, string, value, status );
+}
+int astValidateAxis_( AstFrame *this, int axis, int fwd, const char *method, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,ValidateAxis))( this, axis, fwd, method, status );
+}
+void astValidateAxisSelection_( AstFrame *this, int naxes, const int *axes,
+ const char *method, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,ValidateAxisSelection))( this, naxes, axes,
+ method, status );
+}
+AstSystemType astValidateSystem_( AstFrame *this, AstSystemType system, const char *method, int *status ) {
+ if ( !astOK ) return AST__BADSYSTEM;
+ return (**astMEMBER(this,Frame,ValidateSystem))( this, system, method, status );
+}
+AstSystemType astSystemCode_( AstFrame *this, const char *system, int *status ) {
+ if ( !astOK ) return AST__BADSYSTEM;
+ return (**astMEMBER(this,Frame,SystemCode))( this, system, status );
+}
+const char *astSystemString_( AstFrame *this, AstSystemType system, int *status ) {
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,Frame,SystemString))( this, system, status );
+}
+int astAxIn_( AstFrame *this, int axis, double lo, double hi, double val,
+ int closed, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,AxIn))( this, axis, lo, hi, val, closed, status );
+}
+int astGetFrameFlags_( AstFrame *this, int *status ) {
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,Frame,GetFrameFlags))( this, status );
+}
+void astSetFrameFlags_( AstFrame *this, int value, int *status ) {
+ if ( !astOK ) return;
+ (**astMEMBER(this,Frame,SetFrameFlags))( this, value, status );
+}
+
+
+/* Special public interface functions. */
+/* =================================== */
+/* These provide the public interface to certain special functions
+ whose public interface cannot be handled using macros (such as
+ astINVOKE) alone. In general, they are named after the
+ corresponding protected version of the function, but with "Id"
+ appended to the name. */
+
+/* Public Interface Function Prototypes. */
+/* ------------------------------------- */
+/* The following functions have public prototypes only (i.e. no
+ protected prototypes), so we must provide local prototypes for use
+ within this module. */
+AstFrame *PickAxesId_( AstFrame *, int, const int[], AstMapping **, int * );
+AstFrame *astFrameId_( int, const char *, ... );
+const char *astFormatId_( AstFrame *, int, double, int * );
+int astUnformatId_( AstFrame *, int, const char *, double *, int * );
+void astPermAxesId_( AstFrame *, const int[], int * );
+
+/* Special interface function implementations. */
+/* ------------------------------------------- */
+const char *astFormatId_( AstFrame *this, int axis, double value, int *status ) {
+/*
+*++
+* Name:
+c astFormat
+f AST_FORMAT
+
+* Purpose:
+* Format a coordinate value for a Frame axis.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c const char *astFormat( AstFrame *this, int axis, double value )
+f RESULT = AST_FORMAT( THIS, AXIS, VALUE, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function returns a pointer to a string containing the
+f This function returns a character string containing the
+* formatted (character) version of a coordinate value for a Frame
+* axis. The formatting applied is determined by the Frame's
+* attributes and, in particular, by any Format attribute string
+* that has been set for the axis. A suitable default format (based
+* on the Digits attribute value) will be applied if necessary.
+
+* Parameters:
+c this
+f THIS = INTEGER (given)
+* Pointer to the Frame.
+c axis
+f AXIS = INTEGER (Given)
+* The number of the Frame axis for which formatting is to be
+* performed (axis numbering starts at 1 for the first axis).
+c value
+f VALUE = DOUBLE PRECISION (Given)
+* The coordinate value to be formatted.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astFormat()
+c A pointer to a null-terminated string containing the formatted
+c value.
+f AST_FORMAT = CHARACTER * ( AST__SZCHR )
+f The formatted value.
+
+* Notes:
+c - The returned pointer is guaranteed to remain valid and the
+c string to which it points will not be over-written for a total
+c of 50 successive invocations of this function. After this, the
+c memory containing the string may be re-used, so a copy of the
+c string should be made if it is needed for longer than this.
+c - A formatted value may be converted back into a numerical (double)
+c value using astUnformat.
+f - A formatted value may be converted back into a numerical
+f (double precision) value using AST_UNFORMAT.
+c - A NULL pointer will be returned if this function is invoked
+c with the AST error status set, or if it should fail for any
+c reason.
+f - A blank string will be returned if this function is invoked
+f with STATUS set to an error value, or if it should fail for any
+f reason.
+*--
+
+* Implementation Notes:
+* This function implements the public interface for the astFormat
+* method. It is identical to astFormat_ except that:
+*
+* - The axis index is decremented by 1 before use. This allows the
+* public interface to use 1-based axis numbers (whereas internally
+* axis numbers are zero-based).
+*
+* - The returned string value is buffered in dynamically allocated
+* memory so that it will remain valid for a guaranteed number of
+* function invocations.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Thread-specific global data */
+ const char *fvalue; /* Pointer to formatted value */
+ const char *result; /* Pointer value to return */
+ int i; /* Loop counter for initialisation */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to Thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* If the "astformatid_strings" array has not been initialised, fill it with NULL
+ pointers. */
+ if ( !astformatid_init ) {
+ astformatid_init = 1;
+ for ( i = 0; i < ASTFORMATID_MAX_STRINGS; i++ ) astformatid_strings[ i ] = NULL;
+ }
+
+/* Invoke the normal astFormat_ function to obtain a pointer to the
+ required formatted value, adjusting the axis index to become
+ zero-based. */
+ fvalue = astFormat( this, axis - 1, value );
+
+/* If OK, store a copy of the resulting string in dynamically allocated memory,
+ putting a pointer to the copy into the next element of the "astformatid_strings"
+ array. (This process also de-allocates any previously allocated memory pointed
+ at by this "astformatid_strings" element, so the earlier string is effectively
+ replaced by the new one.) */
+ if ( astOK ) {
+ astBeginPM;
+ astformatid_strings[ astformatid_istr ] = astStore( astformatid_strings[ astformatid_istr ], fvalue,
+ strlen( fvalue ) + (size_t) 1 );
+ astEndPM;
+
+/* If OK, return a pointer to the copy and increment "astformatid_istr" to use
+ the next element of "astformatid_strings" on the next invocation. Recycle
+ "astformatid_istr" to zero when all elements have been used. */
+ if ( astOK ) {
+ result = astformatid_strings[ astformatid_istr++ ];
+ if ( astformatid_istr == ( ASTFORMATID_MAX_STRINGS - 1 ) ) astformatid_istr = 0;
+ }
+ }
+
+/* Return the result. */
+ return result;
+
+}
+
+AstFrame *astFrameId_( int naxes, const char *options, ... ) {
+/*
+*++
+* Name:
+c astFrame
+f AST_FRAME
+
+* Purpose:
+* Create a Frame.
+
+* Type:
+* Public function.
+
+* Synopsis:
+c #include "frame.h"
+c AstFrame *astFrame( int naxes, const char *options, ... )
+f RESULT = AST_FRAME( NAXES, OPTIONS, STATUS )
+
+* Class Membership:
+* Frame constructor.
+
+* Description:
+* This function creates a new Frame and optionally initialises its
+* attributes.
+*
+* A Frame is used to represent a coordinate system. It does this
+* in rather the same way that a frame around a graph describes the
+* coordinate space in which data are plotted. Consequently, a
+* Frame has a Title (string) attribute, which describes the
+* coordinate space, and contains axes which in turn hold
+* information such as Label and Units strings which are used for
+* labelling (e.g.) graphical output. In general, however, the
+* number of axes is not restricted to two.
+*
+* Functions are available for converting Frame coordinate values
+* into a form suitable for display, and also for calculating
+* distances and offsets between positions within the Frame.
+*
+* Frames may also contain knowledge of how to transform to and
+* from related coordinate systems.
+
+* Parameters:
+c naxes
+f NAXES = INTEGER (Given)
+* The number of Frame axes (i.e. the number of dimensions of
+* the coordinate space which the Frame describes).
+c options
+f OPTIONS = CHARACTER * ( * ) (Given)
+c Pointer to a null-terminated string containing an optional
+c comma-separated list of attribute assignments to be used for
+c initialising the new Frame. The syntax used is identical to
+c that for the astSet function and may include "printf" format
+c specifiers identified by "%" symbols in the normal way.
+c If no initialisation is required, a zero-length string may be
+c supplied.
+f A character string containing an optional comma-separated
+f list of attribute assignments to be used for initialising the
+f new Frame. The syntax used is identical to that for the
+f AST_SET routine. If no initialisation is required, a blank
+f value may be supplied.
+c ...
+c If the "options" string contains "%" format specifiers, then
+c an optional list of additional arguments may follow it in
+c order to supply values to be substituted for these
+c specifiers. The rules for supplying these are identical to
+c those for the astSet function (and for the C "printf"
+c function).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astFrame()
+f AST_FRAME = INTEGER
+* A pointer to the new Frame.
+
+* Examples:
+c frame = astFrame( 2, "Title=Energy Spectrum: Plot %d", n );
+c Creates a new 2-dimensional Frame and initialises its Title
+c attribute to the string "Energy Spectrum: Plot <n>", where
+c <n> takes the value of the int variable "n".
+c frame = astFrame( 2, "Label(1)=Energy, Label(2)=Response" );
+c Creates a new 2-dimensional Frame and initialises its axis
+c Label attributes to suitable string values.
+f FRAME = AST_FRAME( 2, 'Title=Energy Spectrum', STATUS );
+f Creates a new 2-dimensional Frame and initialises its Title
+f attribute to the string "Energy Spectrum".
+f FRAME = AST_FRAME( 2, 'Label(1)=Energy, Label(2)=Response', STATUS );
+f Creates a new 2-dimensional Frame and initialises its axis
+f Label attributes to suitable string values.
+
+* Notes:
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+*--
+
+* Implementation Notes:
+* - This function implements the external (public) interface to
+* the astFrame constructor function. It returns an ID value
+* (instead of a true C pointer) to external users, and must be
+* provided because astFrame_ has a variable argument list which
+* cannot be encapsulated in a macro (where this conversion would
+* otherwise occur).
+* - The variable argument list also prevents this function from
+* invoking astFrame_ directly, so it must be a re-implementation
+* of it in all respects, except for the final conversion of the
+* result to an ID value.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstFrame *new; /* Pointer to new Frame */
+ va_list args; /* Variable argument list */
+
+ int *status; /* Pointer to inherited status value */
+
+/* Get a pointer to the inherited status value. */
+ status = astGetStatusPtr;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Initialise the Frame, allocating memory and initialising the virtual
+ function table as well if necessary. */
+ new = astInitFrame( NULL, sizeof( AstFrame ), !class_init, &class_vtab,
+ "Frame", naxes );
+
+/* If successful, note that the virtual function table has been initialised. */
+ if ( astOK ) {
+ class_init = 1;
+
+/* Obtain the variable argument list and pass it along with the options string
+ to the astVSet method to initialise the new Frame's attributes. */
+ va_start( args, options );
+ astVSet( new, options, NULL, args );
+ va_end( args );
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return an ID value for the new Frame. */
+ return astMakeId( new );
+}
+
+void astPermAxesId_( AstFrame *this, const int perm[], int *status ) {
+/*
+*++
+* Name:
+c astPermAxes
+f AST_PERMAXES
+
+* Purpose:
+* Permute the axis order in a Frame.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c void astPermAxes( AstFrame *this, const int perm[] )
+f CALL AST_PERMAXES( THIS, PERM, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function permutes the order in which a Frame's axes occur.
+f This routine permutes the order in which a Frame's axes occur.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c perm
+f PERM( * ) = INTEGER (Given)
+* An array with one element for each axis of the Frame (Naxes
+* attribute). This should list the axes in their new order,
+* using the original axis numbering (which starts at 1 for the
+* first axis).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - Only genuine permutations of the axis order are permitted, so
+c each axis must be referenced exactly once in the "perm" array.
+f each axis must be referenced exactly once in the PERM array.
+* - If successive axis permutations are applied to a Frame, then
+* the effects are cumulative.
+*--
+
+* Implementation Notes:
+* This function implements the public interface for the
+* astPermAxes method. It is identical to astPermAxes_ except that
+* the axis numbers in the "perm" array are decremented by 1 before
+* use. This is to allow the public interface to use one-based axis
+* numbering (internally, zero-based axis numbering is used).
+*/
+
+/* Local Variables: */
+ int *perm1; /* Pointer to modified perm array */
+ int axis; /* Loop counter for Frame axes */
+ int naxes; /* Number of Frame axes */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain the number of Frame axes. */
+ naxes = astGetNaxes( this );
+
+/* Allocate an array to hold a modified version of the "perm"
+ array. */
+ perm1 = astMalloc( sizeof( int ) * (size_t) naxes );
+ if ( astOK ) {
+
+/* Make a modified copy of the "perm" array by subtracting one from
+ each element. This allows the public interface to use one-based
+ axis numbering, whereas all internal code is zero-based. */
+ for ( axis = 0; axis < naxes; axis++ ) perm1[ axis ] = perm[ axis ] - 1;
+
+/* Invoke the normal astPermAxes_ function to permute the Frame's axes. */
+ astPermAxes( this, perm1 );
+ }
+
+/* Free the temporary array. */
+ perm1 = astFree( perm1 );
+}
+
+AstFrame *astPickAxesId_( AstFrame *this, int naxes, const int axes[],
+ AstMapping **map, int *status ) {
+/*
+*++
+* Name:
+c astPickAxes
+f AST_PICKAXES
+
+* Purpose:
+* Create a new Frame by picking axes from an existing one.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c AstFrame *astPickAxes( AstFrame *this, int naxes, const int axes[],
+c AstMapping **map )
+f RESULT = AST_PICKAXES( THIS, NAXES, AXES, MAP, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+* This function creates a new Frame whose axes are copied from an
+* existing Frame along with other Frame attributes, such as its
+* Title. Any number (zero or more) of the original Frame's axes
+* may be copied, in any order, and additional axes with default
+* attributes may also be included in the new Frame.
+*
+c Optionally, a Mapping that converts between the coordinate
+f A Mapping that converts between the coordinate
+* systems described by the two Frames will also be returned.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the original Frame.
+c naxes
+f NAXES = INTEGER (Given)
+* The number of axes required in the new Frame.
+c axes
+f AXES( NAXES ) = INTEGER (Given)
+c An array, with "naxes" elements, which lists the axes to be
+f An array which lists the axes to be
+* copied. These should be given in the order required in the
+* new Frame, using the axis numbering in the original Frame
+* (which starts at 1 for the first axis). Axes may be selected
+* in any order, but each may only be used once. If additional
+* (default) axes are also to be included, the corresponding
+* elements of this array should be set to zero.
+c map
+f MAP = INTEGER (Returned)
+c Address of a location in which to return a pointer to a new
+f A pointer to a new
+* Mapping. This will be a PermMap (or a UnitMap as a special
+* case) that describes the axis permutation that has taken
+* place between the original and new Frames. The Mapping's
+* forward transformation will convert coordinates from the
+* original Frame into the new one, and vice versa.
+c
+c If this Mapping is not required, a NULL value may be supplied
+c for this parameter.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astPickAxes()
+f AST_PICKAXES = INTEGER
+* A pointer to the new Frame.
+
+* Applicability:
+* Frame
+* This function applies to all Frames. The class of Frame returned
+* may differ from that of the original Frame, depending on which
+* axes are selected. For example, if a single axis is picked from a
+* SkyFrame (which must always have two axes) then the resulting
+* Frame cannot be a valid SkyFrame, so will revert to the parent
+* class (Frame) instead.
+* FrameSet
+* Using this function on a FrameSet is identical to using it on
+* the current Frame in the FrameSet. The returned Frame will not
+* be a FrameSet.
+* Region
+* If this function is used on a Region, an attempt is made to
+* retain the bounds information on the selected axes. If
+* succesful, the returned Frame will be a Region of some class.
+* Otherwise, the returned Frame is obtained by calling this
+* function on the Frame represented by the supplied Region (the
+* returned Frame will then not be a Region). In order to be
+* succesful, the selected axes in the Region must be independent
+* of the others. For instance, a Box can be split in this way but
+* a Circle cannot. Another requirement for success is that no
+* default axes are added (that is, the
+c "axes"
+f AXES
+* array must not contain any zero values.
+
+* Notes:
+c - The new Frame will contain a "deep" copy (c.f. astCopy) of all
+f - The new Frame will contain a "deep" copy (c.f. AST_COPY) of all
+* the data selected from the original Frame. Modifying any aspect
+* of the new Frame will therefore not affect the original one.
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+*--
+
+* Implementation Notes:
+* This function implements the public interface for the
+* astPickAxes method. It is identical to astPickAxes_ except for
+* the following:
+*
+* - The axis numbers in the "axes" array are decremented by 1 before
+* use. This is to allow the public interface to use one-based axis
+* numbering (internally, zero-based axis numbering is used).
+*
+* - An ID value is returned via the "map" parameter (if used)
+* instead of a true C pointer. This is required because this
+* conversion cannot be performed by the macro that invokes the
+* function.
+*/
+
+/* Local Variables: */
+ AstFrame *result; /* Pointer to result Frame */
+ int *axes1; /* Pointer to modified axes array */
+ int axis; /* Loop counter for axes */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Allocate an array to hold a modified version of the "axes" array
+ (check that "naxes" is valid first - if not, this error will be
+ reported by astPickAxes_ below). */
+ axes1 = ( naxes >= 0 ) ? astMalloc( sizeof( int ) * (size_t) naxes ) :
+ NULL;
+ if ( astOK ) {
+
+/* Make a modified copy of the "axes" array by subtracting one from
+ each element. This allows the public interface to use one-based
+ axis numbering, whereas all internal code is zero-based. */
+ for ( axis = 0; axis < naxes; axis++ ) axes1[ axis ] = axes[ axis ] - 1;
+
+/* Invoke the normal astPickAxes_ function to select the required axes. */
+ result = astPickAxes( this, naxes, axes1, map );
+ }
+
+/* Free the temporary array. */
+ axes1 = astFree( axes1 );
+
+/* If required, return an ID value for the Mapping. */
+ if ( map ) *map = astMakeId( *map );
+
+/* Return the result. */
+ return result;
+}
+
+int astUnformatId_( AstFrame *this, int axis, const char *string,
+ double *value, int *status ) {
+/*
+*++
+* Name:
+c astUnformat
+f AST_UNFORMAT
+
+* Purpose:
+* Read a formatted coordinate value for a Frame axis.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "frame.h"
+c int astUnformat( AstFrame *this, int axis, const char *string,
+c double *value )
+f RESULT = AST_UNFORMAT( THIS, AXIS, STRING, VALUE, STATUS )
+
+* Class Membership:
+* Frame method.
+
+* Description:
+c This function reads a formatted coordinate value (given as a
+c character string) for a Frame axis and returns the equivalent
+c numerical (double) value. It also returns the number of
+c characters read from the string.
+f This function reads a formatted coordinate value (given as a
+f character string) for a Frame axis and returns the equivalent
+f numerical (double precision) value. It also returns the number
+f of characters read from the string.
+*
+c The principle use of this function is in decoding user-supplied
+c input which contains formatted coordinate values. Free-format
+c input is supported as far as possible. If input is ambiguous, it
+c is interpreted with reference to the Frame's attributes (in
+c particular, the Format string associated with the Frame's
+c axis). This function is, in essence, the inverse of astFormat.
+f The principle use of this function is in decoding user-supplied
+f input which contains formatted coordinate values. Free-format
+f input is supported as far as possible. If input is ambiguous, it
+f is interpreted with reference to the Frame's attributes (in
+f particular, the Format string associated with the Frame's
+f axis). This function is, in essence, the inverse of AST_FORMAT.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the Frame.
+c axis
+f AXIS = INTEGER (Given)
+* The number of the Frame axis for which a coordinate value is to
+* be read (axis numbering starts at 1 for the first axis).
+c string
+f STRING = CHARACTER * ( * ) (Given)
+c Pointer to a null-terminated character string containing the
+c formatted coordinate value.
+f A character string containing the formatted coordinate value.
+* This string may contain additional information following the
+* value to be read, in which case reading stops at the first
+* character which cannot be interpreted as part of the value.
+* Any white space before or after the value is discarded.
+c value
+f VALUE = DOUBLE PRECISION (Returned)
+c Pointer to a double in which the coordinate value read will be
+c returned.
+f The coordinate value read.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astUnformat()
+f AST_UNFORMAT = INTEGER
+* The number of characters read from the string in order to
+* obtain the coordinate value. This will include any white
+* space which occurs before or after the value.
+
+* Applicability:
+* Frame
+* This function applies to all Frames. See the "Frame Input
+* Format" section below for details of the input formats
+* accepted by a basic Frame.
+* SkyFrame
+* The SkyFrame class re-defines the input format to be suitable
+* for representing angles and times, with the resulting
+* coordinate value returned in radians. See the "SkyFrame
+* Input Format" section below for details of the formats
+* accepted.
+* FrameSet
+* The input formats accepted by a FrameSet are determined by
+* its current Frame (as specified by the Current attribute).
+
+* Frame Input Format
+* The input format accepted for a basic Frame axis is as follows:
+* - An optional sign, followed by:
+* - A sequence of one or more digits possibly containing a decimal point,
+* followed by:
+* - An optional exponent field.
+* - The exponent field, if present, consists of "E" or "e"
+* followed by a possibly signed integer.
+*
+* Examples of acceptable Frame input formats include:
+* - 99
+* - 1.25
+* - -1.6
+* - 1E8
+* - -.99e-17
+* - <bad>
+
+* SkyFrame Input Format
+* The input format accepted for a SkyFrame axis is as follows:
+* - An optional sign, followed by between one and three fields
+* representing either degrees, arc-minutes, arc-seconds or hours,
+* minutes, seconds (e.g. "-12 42 03").
+* - Each field should consist of a sequence of one or more digits,
+* which may include leading zeros. At most one field may contain a
+* decimal point, in which case it is taken to be the final field
+* (e.g. decimal degrees might be given as "124.707", while degrees
+* and decimal arc-minutes might be given as "-13 33.8").
+* - The first field given may take any value, allowing angles and
+* times outside the conventional ranges to be
+* represented. However, subsequent fields must have values of less
+* than 60 (e.g. "720 45 31" is valid, whereas "11 45 61" is not).
+* - Fields may be separated by white space or by ":" (colon), but
+* the choice of separator must be used consistently throughout the
+* value. Additional white space may be present around fields and
+* separators (e.g. "- 2: 04 : 7.1").
+* - The following field identification characters may be used as
+* separators to replace either of those above (or may be appended
+* to the final field), in order to identify the field to which
+* they are appended: "d"---degrees; "h"---hours; "m"---minutes of
+* arc or time; "s"---seconds of arc or time; "'" (single
+* quote)---minutes of arc; """ (double quote)---seconds of arc.
+* Either lower or upper case may be used. Fields must be given in
+* order of decreasing significance (e.g. "-11D 3' 14.4"" or
+* "22h14m11.2s").
+* - The presence of any of the field identification characters
+* "d", "'" (single quote) or """ (double quote) indicates that the
+* value is to be interpreted as an angle. Conversely, the presence
+* of "h" indicates that it is to be interpreted as a time (with 24
+* hours corresponding to 360 degrees). Incompatible angle/time
+* identification characters may not be mixed (e.g. "10h14'3"" is
+* not valid). The remaining field identification characters and
+* separators do not specify a preference for an angle or a time
+* and may be used with either.
+c - If no preference for an angle or a time is expressed anywhere
+c within the value, it is interpreted as an angle if the Format
+c attribute string associated with the SkyFrame axis generates an
+c angle and as a time otherwise. This ensures that values produced
+c by astFormat are correctly interpreted by astUnformat.
+f - If no preference for an angle or a time is expressed anywhere
+f within the value, it is interpreted as an angle if the Format
+f attribute string associated with the SkyFrame axis generates an
+f angle and as a time otherwise. This ensures that values produced
+f by AST_FORMAT are correctly interpreted by AST_UNFORMAT.
+* - Fields may be omitted, in which case they default to zero. The
+* remaining fields may be identified by using appropriate field
+* identification characters (see above) and/or by adding extra
+* colon separators (e.g. "-05m13s" is equivalent to "-:05:13"). If
+* a field is not identified explicitly, it is assumed that
+* adjacent fields have been given, after taking account of any
+* extra separator characters (e.g. "14:25.4s" specifies minutes
+* and seconds, while "14::25.4s" specifies degrees and seconds).
+c - If fields are omitted in such a way that the remaining ones
+c cannot be identified uniquely (e.g. "01:02"), then the first
+c field (either given explicitly or implied by an extra leading
+c colon separator) is taken to be the most significant field that
+c astFormat would produce when formatting a value (using the
+c Format attribute associated with the SkyFrame axis). By
+c default, this means that the first field will normally be
+c interpreted as degrees or hours. However, if this does not
+c result in consistent field identification, then the last field
+c (either given explicitly or implied by an extra trailing colon
+c separator) is taken to to be the least significant field that
+c astFormat would produce.
+f - If fields are omitted in such a way that the remaining ones
+f cannot be identified uniquely (e.g. "01:02"), then the first
+f field (either given explicitly or implied by an extra leading
+f colon separator) is taken to be the most significant field that
+f AST_FORMAT would produce when formatting a value (using the
+f Format attribute associated with the SkyFrame axis). By
+f default, this means that the first field will normally be
+f interpreted as degrees or hours. However, if this does not
+f result in consistent field identification, then the last field
+f (either given explicitly or implied by an extra trailing colon
+f separator) is taken to to be the least significant field that
+f AST_FORMAT would produce.
+*
+c This final convention is intended to ensure that values formatted
+c by astFormat which contain less than three fields will be
+c correctly interpreted if read back using astUnformat, even if
+c they do not contain field identification characters.
+f This final convention is intended to ensure that values formatted
+f by AST_FORMAT which contain less than three fields will be
+f correctly interpreted if read back using AST_UNFORMAT, even if
+f they do not contain field identification characters.
+*
+* Examples of acceptable SkyFrame input formats (with
+* interpretation in parentheses) include:
+* - -14d 13m 22.2s (-14d 13' 22.2")
+* - + 12:34:56.7 (12d 34' 56.7" or 12h 34m 56.7s)
+* - 001 : 02 : 03.4 (1d 02' 03.4" or 1h 02m 03.4s)
+* - 22h 30 (22h 30m 00s)
+* - 136::10" (136d 00' 10" or 136h 00m 10s)
+* - -14M 27S (-0d 14' 27" or -0h 14m 27s)
+* - -:14: (-0d 14' 00" or -0h 14m 00s)
+* - -::4.1 (-0d 00' 04.1" or -0h 00m 04.1s)
+* - .9" (0d 00' 00.9")
+* - d12m (0d 12' 00")
+* - H 12:22.3s (0h 12m 22.3s)
+* - <bad> (AST__BAD)
+*
+* Where alternative interpretations are shown, the choice of angle or
+* time depends on the associated Format(axis) attribute.
+
+* Notes:
+* - A function value of zero (and no coordinate value) will be
+* returned, without error, if the string supplied does not contain
+* a suitably formatted value.
+c - Beware that it is possible for a formatting error part-way
+c through an input string to terminate input before it has been
+c completely read, but to yield a coordinate value that appears
+c valid. For example, if a user types "1.5r6" instead of "1.5e6",
+c the "r" will terminate input, giving an incorrect coordinate
+c value of 1.5. It is therefore most important to check the return
+c value of this function to ensure that the correct number of
+c characters have been read.
+f - Beware that it is possible for a formatting error part-way
+f through an input string to terminate input before it has been
+f completely read, but to yield a coordinate value that appears
+f valid. For example, if a user types "1.5R6" instead of "1.5E6",
+f the "R" will terminate input, giving an incorrect coordinate
+f value of 1.5. It is therefore most important to check the return
+f value of this function to ensure that the correct number of
+f characters have been read.
+* - An error will result if a value is read which appears to have
+* the correct format, but which cannot be converted into a valid
+* coordinate value (for instance, because the value of one or more
+* of its fields is invalid).
+* - The string "<bad>" is recognised as a special case and will
+* yield the coordinate value AST__BAD without error. The test for
+* this string is case-insensitive and also permits embedded white
+* space.
+c - A function result of zero will be returned and no coordinate
+c value will be returned via the "value" pointer if this function
+c is invoked with the AST error status set, or if it should fail
+c for any reason.
+f - A function result of zero will be returned and no coordinate
+f value will be returned via the VALUE argument if this function
+f is invoked with the AST error status set, or if it should fail
+f for any reason.
+*--
+
+* Implementation Notes:
+* This function implements the public interface for the
+* astUnformat method. It is identical to astUnformat_ except that:
+*
+* - The axis index is decremented by 1 before use. This allows the
+* public interface to use 1-based axis numbers (whereas internally
+* axis numbers are zero-based).
+*/
+
+/* Invoke the normal astUnformat_ function, adjusting the axis index
+ to become zero-based. */
+ return astUnformat( this, axis - 1, string, value );
+}
+
+
+
+
+
+
+
+
+
+
+
+
+