summaryrefslogtreecommitdiffstats
path: root/ast/timeframe.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2018-01-09 19:06:55 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2018-01-09 19:06:55 (GMT)
commit01e0ebfe59d9028b0246ec4a549bd7528ada94eb (patch)
treea6c5b54db03177a1c8f3e7fb531990dfbc7bae39 /ast/timeframe.c
parentd64cf9c0bd23e752867b149be636d1bbd4501cf4 (diff)
downloadblt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.zip
blt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.tar.gz
blt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.tar.bz2
update ast 8.6.2
Diffstat (limited to 'ast/timeframe.c')
-rw-r--r--ast/timeframe.c7530
1 files changed, 7530 insertions, 0 deletions
diff --git a/ast/timeframe.c b/ast/timeframe.c
new file mode 100644
index 0000000..8d0906a
--- /dev/null
+++ b/ast/timeframe.c
@@ -0,0 +1,7530 @@
+/*
+*class++
+* Name:
+* TimeFrame
+
+* Purpose:
+* Time coordinate system description.
+
+* Constructor Function:
+c astTimeFrame
+f AST_TIMEFRAME
+
+* Description:
+* A TimeFrame is a specialised form of one-dimensional Frame which
+* represents various coordinate systems used to describe positions in
+* time.
+*
+* A TimeFrame represents a moment in time as either an Modified Julian
+* Date (MJD), a Julian Date (JD), a Besselian epoch or a Julian epoch,
+* as determined by the System attribute. Optionally, a zero point can be
+* specified (using attribute TimeOrigin) which results in the TimeFrame
+* representing time offsets from the specified zero point.
+*
+* Even though JD and MJD are defined as being in units of days, the
+* TimeFrame class allows other units to be used (via the Unit attribute)
+* on the basis of simple scalings (60 seconds = 1 minute, 60 minutes = 1
+* hour, 24 hours = 1 day, 365.25 days = 1 year). Likewise, Julian epochs
+* can be described in units other than the usual years. Besselian epoch
+* are always represented in units of (tropical) years.
+*
+* The TimeScale attribute allows the time scale to be specified (that
+* is, the physical process used to define the rate of flow of time).
+* MJD, JD and Julian epoch can be used to represent a time in any
+* supported time scale. However, Besselian epoch may only be used with the
+* "TT" (Terrestrial Time) time scale. The list of supported time scales
+* includes universal time and siderial time. Strictly, these represent
+* angles rather than time scales, but are included in the list since
+* they are in common use and are often thought of as time scales.
+*
+* When a time value is formatted it can be formated either as a simple
+* floating point value, or as a Gregorian date (see the Format
+* attribute).
+
+* Inheritance:
+* The TimeFrame class inherits from the Frame class.
+
+* Attributes:
+* In addition to those attributes common to all Frames, every
+* TimeFrame also has the following attributes:
+*
+* - AlignTimeScale: Time scale in which to align TimeFrames
+* - LTOffset: The offset of Local Time from UTC, in hours.
+* - TimeOrigin: The zero point for TimeFrame axis values
+* - TimeScale: The timescale used by the TimeFrame
+*
+* Several of the Frame attributes inherited by the TimeFrame class
+* refer to a specific axis of the Frame (for instance Unit(axis),
+* Label(axis), etc). Since a TimeFrame is strictly one-dimensional,
+* it allows these attributes to be specified without an axis index.
+* So for instance, "Unit" is allowed in place of "Unit(1)".
+
+* Functions:
+c In addition to those functions applicable to all Frames, the
+c following functions may also be applied to all TimeFrames:
+f In addition to those routines applicable to all Frames, the
+f following routines may also be applied to all TimeFrames:
+*
+c - astCurrentTime: Return the current system time
+f - AST_CURRENTTIME: Return the current system time
+
+* 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:
+* NG: Norman Gray (Starlink)
+* DSB: David Berry (Starlink)
+
+* History:
+* XX-Aug-2003 (NG):
+* Original version, drawing heavily on specframe.c.
+* 20-MAY-2005 (NG):
+* Merged into main AST system.
+* 25-MAY-2005 (DSB):
+* Extensive modifications to add extra timescales, unit support,
+* support for relative times, etc, and to make it more like the
+* other AST Frame classes.
+* 12-AUG-2005 (DSB):
+* Remove ClockLon and ClockLat attributes. Use the new ObsLon and
+* ObsLat attributes in the parent Frame class instead. Note, for
+* backward compatibility the public attribute accessors and the
+* astLoadTimeFrame functions still recogonise ClockLon and ClockLat,
+* but use the ObsLat/ObsLon attributes internally.
+* 1-MAR-2006 (DSB):
+* Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM.
+* 29-JUN-2006 (DSB):
+* - Activate astAbbrev function for abbreviating leading fields in
+* plot labels.
+* - Include TimeOrigin in default Label.
+* 30-JUN-2006 (DSB):
+* When splitting a date/time string into fields, allow each field
+* to include a decimal point.
+* 30-JUN-2006 (DSB):
+* Allow astAbbrev to have a null "str1" value.
+* 16-OCT-2006 (DSB):
+* Allow conversions between UTC and UT1 (using the new Frame attribute
+* 1-NOV-2006 (DSB):
+* Correct sign of longitude passed to TimeMap contrutcorss in
+* function MakeMap.
+* 31-JAN-2007 (DSB):
+* Modified so that a TimeFrame can be used as a template to find a
+* TimeFrame contained within a CmpFrame. This involves changes in
+* Match and the removal of the local versions of SetMaxAxes and
+* SetMinAxes.
+* 3-SEP-2007 (DSB):
+* In SubFrame, since AlignSystem is extended by the TimeFrame class
+* it needs to be cleared before invoking the parent SubFrame
+* method in cases where the result Frame is not a TimeFrame.
+* 2-OCT-2007 (DSB):
+* In Overlay, clear AlignSystem as well as System before calling
+* the parent overlay method.
+* 2-OCT-2007 (DSB):
+* Added "LT" (Local Time) time scale.
+* 9-DEC-2008 (DSB):
+* Ensure Format string pointer is used correctly.
+* 19-JAN-2009 (DSB):
+* Ensure "<bad>" is returned by astFormat if the axis value is bad.
+* 31-MAR-2009 (DSB):
+* Extend TimeFrame "iso" Format to allow it to specify the character to
+* place between the time and date strings.
+* 15-APR-2009 (DSB):
+* Increase the number of nice calendar time axis gaps allowed by
+* the Gap function. Previously, there was a jump from 1 day to 1
+* year making it difficult to plot calendar axes covering time
+* ranges of the order of 0.5 to 2 years. Now, nice numbers of days
+* are allowed as intermediate gaps. Since months do not all have
+* the same number of days, this means that the day number at major
+* ticks will bounce around a bit.
+* 29-APR-2011 (DSB):
+* Prevent astFindFrame from matching a subclass template against a
+* superclass target.
+* 16-APR-2015 (DSB):
+* Add more choices when chosing gaps on time axes.
+* 17-APR-2015 (DSB):
+* - Added Centre.
+* - Remove some "set but unused" variables.
+* 21-APR-2016 (DSB):
+* - Over-ride astFields.
+* 5-APR-2017 (GSB):
+* - Pass DTAI to astAddTime for UTCTOTAI and TAITOUTC conversions and
+* check whether there is a relevant DTAI difference in
+* MakeTimeMapping.
+* 7-APR-2017 (GSB):
+* - Add LT to macro defining scales depending on DTAI.
+* 10-APR-2017 (GSB):
+* - Added macro to test floating point equality and used it for Dtai.
+* 27-APR-2017 (DSB):
+* Conversions between TT and TDB now require DTAI as an argument.
+*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 TimeFrame
+
+/* Define the first and last acceptable System values. */
+#define FIRST_SYSTEM AST__MJD
+#define LAST_SYSTEM AST__BEPOCH
+
+/* Define the first and last acceptable TimeScale values. */
+#define FIRST_TS AST__TAI
+#define LAST_TS AST__LT
+
+/* The supported time scales fall into two groups. Time scales in the
+ first group depend on the clock position. That is, transformation
+ between a time scale in one group and a timescale in the other group
+ requires the clock position, as does transformation between two time
+ scales within the first group. Define a macro which tests if a given
+ timescale belongs to the first group. */
+#define CLOCK_SCALE(ts) \
+ ( ( ts == AST__LMST || \
+ ts == AST__LAST || \
+ ts == AST__TDB || \
+ ts == AST__TCB ) ? 1 : 0 )
+
+
+/* Define a macro which tests if a given timescale requires a Dut1 value
+ in order to convert from the timescale to UTC. */
+#define DUT1_SCALE(ts) \
+ ( ( ts == AST__LMST || \
+ ts == AST__LAST || \
+ ts == AST__GMST || \
+ ts == AST__UT1 ) ? 1 : 0 )
+
+/* Timescales can be divided up into 3 groups such that conversion from a
+ timescale in one group to a timescale in any other group requires the
+ DTAI value, but conversion between timescales in the same group does not
+ require the DTAI value. Define a macro that returns the group number
+ (1, 2 or 3) for a specific timescale. */
+#define DTAI_SCALE(ts) \
+ ( ( ts == AST__LMST || \
+ ts == AST__LAST || \
+ ts == AST__GMST || \
+ ts == AST__UT1 || \
+ ts == AST__UTC || \
+ ts == AST__LT ) ? 1 : \
+ ( ( ts == AST__TAI || ts == AST__TT ) ? 2 : 3 ) )
+
+/* Define a macro which tests if a given timescale requires a LTOffset value
+ in order to convert from the timescale to UTC. */
+#define LTOFFSET_SCALE(ts) \
+ ( ( ts == AST__LT ) ? 1 : 0 )
+
+/* The Unix epoch (00:00:00 UTC 1 January 1970 AD) as an absolute MJD in
+ the UTC timescale. */
+#define UNIX_EPOCH 40587.0
+
+/* Check for floating point equality (within the given tolerance), taking
+ bad values into account. */
+#define EQUAL(aa,bb,tol) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=(tol))))
+
+/* Header files. */
+/* ============= */
+/* Interface definitions. */
+/* ---------------------- */
+
+#include "globals.h" /* Thread-safe global data access */
+#include "error.h" /* Error reporting facilities */
+#include "memory.h" /* Memory allocation facilities */
+#include "unit.h" /* Units management facilities */
+#include "globals.h" /* Thread-safe global data access */
+#include "object.h" /* Base Object class */
+#include "timemap.h" /* Time coordinate Mappings */
+#include "frame.h" /* Parent Frame class */
+#include "timeframe.h" /* Interface definition for this class */
+#include "mapping.h" /* Coordinate Mappings */
+#include "cmpmap.h" /* Compound Mappings */
+#include "unitmap.h" /* Unit Mappings */
+#include "shiftmap.h" /* Shift of origins */
+#include "pal.h" /* SlaLib interface */
+
+
+/* Error code definitions. */
+/* ----------------------- */
+#include "ast_err.h" /* AST error codes */
+
+/* C header files. */
+/* --------------- */
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stddef.h>
+#include <math.h>
+#include <time.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 used or extended by this
+ class. */
+static AstSystemType (* parent_getalignsystem)( AstFrame *, int * );
+static AstSystemType (* parent_getsystem)( AstFrame *, int * );
+static double (* parent_centre)( AstFrame *, int, double, double, int * );
+static double (* parent_gap)( AstFrame *, int, double, int *, int * );
+static const char *(* parent_abbrev)( AstFrame *, int, const char *, const char *, const char *, int * );
+static const char *(* parent_format)( AstFrame *, int, double, int * );
+static const char *(* parent_getattrib)( AstObject *, const char *, int * );
+static const char *(* parent_getdomain)( AstFrame *, int * );
+static const char *(* parent_getlabel)( AstFrame *, int, int * );
+static const char *(* parent_getsymbol)( AstFrame *, int, int * );
+static const char *(* parent_gettitle)( AstFrame *, int * );
+static const char *(* parent_getunit)( AstFrame *, int, int * );
+static double (* parent_getepoch)( AstFrame *, int * );
+static int (* parent_fields)( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * );
+static int (* parent_match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
+static int (* parent_subframe)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
+static int (* parent_testattrib)( AstObject *, const char *, int * );
+static int (* parent_unformat)( AstFrame *, int, const char *, double *, int * );
+static void (* parent_clearattrib)( AstObject *, const char *, int * );
+static void (* parent_clearsystem)( AstFrame *, int * );
+static void (* parent_overlay)( AstFrame *, const int *, AstFrame *, int * );
+static void (* parent_setattrib)( AstObject *, const char *, int * );
+static void (* parent_setsystem)( AstFrame *, AstSystemType, int * );
+static void (* parent_setunit)( AstFrame *, int, const char *, int * );
+
+/* The Unix epoch (00:00:00 UTC 1 January 1970 AD) as an absolute MJD in
+ the TAI timescale. */
+static double tai_epoch;
+
+/* 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->Format_Buff[ 0 ] = 0; \
+ globals->GetAttrib_Buff[ 0 ] = 0; \
+ globals->GetLabel_Buff[ 0 ] = 0; \
+ globals->GetSymbol_Buff[ 0 ] = 0; \
+ globals->GetTitle_Buff[ 0 ] = 0; \
+
+/* Create the function that initialises global data for this module. */
+astMAKE_INITGLOBALS(TimeFrame)
+
+/* Define macros for accessing each item of thread specific global data. */
+#define class_init astGLOBAL(TimeFrame,Class_Init)
+#define class_vtab astGLOBAL(TimeFrame,Class_Vtab)
+#define format_buff astGLOBAL(TimeFrame,Format_Buff)
+#define getattrib_buff astGLOBAL(TimeFrame,GetAttrib_Buff)
+#define getlabel_buff astGLOBAL(TimeFrame,GetLabel_Buff)
+#define getsymbol_buff astGLOBAL(TimeFrame,GetSymbol_Buff)
+#define gettitle_buff astGLOBAL(TimeFrame,GetTitle_Buff)
+
+
+
+static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 );
+#define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 );
+
+/* If thread safety is not needed, declare and initialise globals at static
+ variables. */
+#else
+
+/* Buffers for strings returned by various functions. */
+static char getattrib_buff[ AST__TIMEFRAME_GETATTRIB_BUFF_LEN + 1 ];
+static char format_buff[ AST__TIMEFRAME_FORMAT_BUFF_LEN + 1 ];
+static char getlabel_buff[ AST__TIMEFRAME_GETLABEL_BUFF_LEN + 1 ];
+static char getsymbol_buff[ AST__TIMEFRAME_GETSYMBOL_BUFF_LEN + 1 ];
+static char gettitle_buff[ AST__TIMEFRAME_GETTITLE_BUFF_LEN + 1 ];
+
+
+/* Define the class virtual function table and its initialisation flag
+ as static variables. */
+static AstTimeFrameVtab class_vtab; /* Virtual function table */
+static int class_init = 0; /* Virtual function table initialised? */
+
+#define LOCK_MUTEX2
+#define UNLOCK_MUTEX2
+
+#endif
+
+
+/* Prototypes for Private Member Functions. */
+/* ======================================== */
+static AstMapping *MakeMap( AstTimeFrame *, AstSystemType, AstSystemType, AstTimeScaleType, AstTimeScaleType, double, double, const char *, const char *, const char *, int * );
+static AstSystemType GetAlignSystem( AstFrame *, int * );
+static AstSystemType SystemCode( AstFrame *, const char *, int * );
+static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * );
+static AstTimeScaleType TimeScaleCode( const char *, int * );
+static const char *DefUnit( AstSystemType, const char *, const char *, int * );
+static const char *Format( AstFrame *, int, double, int * );
+static const char *GetDomain( AstFrame *, int * );
+static const char *GetLabel( AstFrame *, int, int * );
+static const char *GetSymbol( AstFrame *, int, int * );
+static const char *GetTitle( AstFrame *, int * );
+static const char *GetUnit( AstFrame *, int, int * );
+static const char *SystemLabel( AstSystemType, int * );
+static const char *SystemString( AstFrame *, AstSystemType, int * );
+static const char *TimeScaleString( AstTimeScaleType, int * );
+static double CurrentTime( AstTimeFrame *, int * );
+static double FromMJD( AstTimeFrame *, double, int * );
+static double GetEpoch( AstFrame *, int * );
+static double GetTimeOriginCur( AstTimeFrame *, int * );
+static double ToMJD( AstSystemType, double, int * );
+static double ToUnits( AstTimeFrame *, const char *, double, const char *, int * );
+static int DateFormat( const char *, int *, char *, int * );
+static int Fields( AstFrame *, int, const char *, const char *, int, char **, int *, double *, int * );
+static int GetActiveUnit( AstFrame *, int * );
+static int MakeTimeMapping( AstTimeFrame *, AstTimeFrame *, AstTimeFrame *, int, AstMapping **, int * );
+static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * );
+static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * );
+static int TestActiveUnit( AstFrame *, int * );
+static void Dump( AstObject *, AstChannel *, int * );
+static void OriginScale( AstTimeFrame *, AstTimeScaleType, const char *, int * );
+static void OriginSystem( AstTimeFrame *, AstSystemType, const char *, int * );
+static void Overlay( AstFrame *, const int *, AstFrame *, int * );
+static void SetUnit( AstFrame *, int, const char *, int * );
+static void VerifyAttrs( AstTimeFrame *, const char *, const char *, const char *, int * );
+static AstMapping *ToMJDMap( AstSystemType, double, int * );
+static int Unformat( AstFrame *, int, const char *, double *, int * );
+static const char *Abbrev( AstFrame *, int, const char *, const char *, const char *, int * );
+static double Centre( AstFrame *, int, double, double, int * );
+static double Gap( AstFrame *, int, double, int *, int * );
+
+static AstSystemType GetSystem( AstFrame *, int * );
+static void SetSystem( AstFrame *, AstSystemType, int * );
+static void ClearSystem( AstFrame *, int * );
+
+static double GetTimeOrigin( AstTimeFrame *, int * );
+static int TestTimeOrigin( AstTimeFrame *, int * );
+static void ClearTimeOrigin( AstTimeFrame *, int * );
+static void SetTimeOrigin( AstTimeFrame *, double, int * );
+
+static double GetLTOffset( AstTimeFrame *, int * );
+static int TestLTOffset( AstTimeFrame *, int * );
+static void ClearLTOffset( AstTimeFrame *, int * );
+static void SetLTOffset( AstTimeFrame *, double, int * );
+
+static const char *GetAttrib( AstObject *, const char *, int * );
+static int TestAttrib( AstObject *, const char *, int * );
+static void ClearAttrib( AstObject *, const char *, int * );
+static void SetAttrib( AstObject *, const char *, int * );
+
+static AstTimeScaleType GetAlignTimeScale( AstTimeFrame *, int * );
+static int TestAlignTimeScale( AstTimeFrame *, int * );
+static void ClearAlignTimeScale( AstTimeFrame *, int * );
+static void SetAlignTimeScale( AstTimeFrame *, AstTimeScaleType, int * );
+
+static AstTimeScaleType GetTimeScale( AstTimeFrame *, int * );
+static int TestTimeScale( AstTimeFrame *, int * );
+static void ClearTimeScale( AstTimeFrame *, int * );
+static void SetTimeScale( AstTimeFrame *, AstTimeScaleType, int * );
+
+/* Member functions. */
+/* ================= */
+static const char *Abbrev( AstFrame *this_frame, int axis, const char *fmt,
+ const char *str1, const char *str2, int *status ) {
+/*
+* Name:
+* Abbrev
+
+* Purpose:
+* Abbreviate a formatted Frame axis value by skipping leading fields.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *Abbrev( AstFrame *this, int axis, const char *fmt,
+* const char *str1, const char *str2, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astAbbrev protected
+* method inherited from the Frame class).
+
+* 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.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer into the "str2" string which locates the first
+* character in the first field that differs between the two
+* formatted values.
+*
+* If the two values have no leading fields in common, the returned
+* value will point at the start of string "str2". If the two
+* values are equal, it will point at the terminating null at the
+* end of this string.
+
+* Notes:
+* - This function assumes that the format specification used was
+* the same when both values were formatted and that they both
+* apply to the same 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: */
+ const char *p1;
+ const char *p2;
+ const char *result;
+ int df;
+ int nc1;
+ int nc2;
+ int ndp;
+
+/* Initialise. */
+ result = str2;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate the axis index. */
+ astValidateAxis( this_frame, axis, 1, "astAbbrev" );
+
+/* Use the parent astAbbrev function unless the Format attribute indicates
+ that axis values are to be formatted as multi-field date/time strings. */
+ df = DateFormat( fmt, &ndp, NULL, status );
+ if( !df ) {
+ result = (*parent_abbrev)( this_frame, axis, fmt, str1, str2, status );
+
+/* Otherwise, if no "str1" string was supplied find the start of the
+ last field in "str2". */
+ } else if( !str1 ){
+
+/* Initialise a pointer to the start of the next field in the "str2" string
+ (skip leading spaces). */
+ p2 = str2;
+ while( *p2 && isspace( *p2 ) ) p2++;
+
+/* Check the entire string, saving the start of the next field as the
+ returned pointer. */
+ while( *p2 ) {
+ result = p2;
+
+/* Each field in a date/time field consists of digits only (and maybe a
+ decimal point). Find the number of leading digits/dots in this field
+ and increment the point to the following character (the first delimiter
+ character). */
+ p2 += strspn( p2, "0123456789." );
+
+/* Skip inter-field (non-numeric) delimiters. */
+ p2 += strcspn( p2, "0123456789." );
+ }
+
+/* Otherwise, if an "str1" string was supplied find the start of the
+ first differing field in "str2". */
+ } else {
+
+/* Initialise pointers to the start of the next field in each string
+ (skip leading spaces). */
+ p1 = str1;
+ p2 = str2;
+ while( *p1 && isspace( *p1 ) ) p1++;
+ while( *p2 && isspace( *p2 ) ) p2++;
+
+/* Check the entire string */
+ result = p2;
+ while( *p1 && *p2 ) {
+
+/* Each field in a date/time field consists of digits only (and maybe a
+ decimal point). Find the number of leading digits/dots in each string */
+ nc1 = strspn( p1, "0123456789." );
+ nc2 = strspn( p2, "0123456789." );
+
+/* If the next field has different lengths in the two strings, or of the
+ content of the fields differ, break out of th eloop, leaving "result"
+ pointing to the start of the current field. */
+ if( nc1 != nc2 || strncmp( p1, p2, nc1 ) ) {
+ break;
+
+/* If the next field is identical in the two strings, skip to the
+ character following the end of the field. */
+ } else {
+ p1 += nc1;
+ p2 += nc2;
+
+/* Skip inter-field (non-numeric) delimiters. */
+ p1 += strcspn( p1, "0123456789." );
+ p2 += strcspn( p2, "0123456789." );
+ }
+
+/* Prepare to check the next field. */
+ result = p2;
+ }
+ }
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = str2;
+
+/* Return the result. */
+ return result;
+}
+
+static double Centre( AstFrame *this_frame, int axis, double value,
+ double gap, int *status ) {
+/*
+* Name:
+* Centre
+
+* Purpose:
+* Find a "nice" central value for tabulating Frame axis values.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* double Centre( AstFrame *this_frame, int axis, double value,
+* double gap, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the protected astCentre method
+* inherited from the Frame class).
+
+* Description:
+* This function returns an axis value which produces a nice formatted
+* value suitable for a major tick mark on a plot axis, close to the
+* supplied axis value.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* axis
+* The number of the axis (zero-based) for which a central value
+* is to be found.
+* value
+* An arbitrary axis value in the section that is being plotted.
+* gap
+* The gap size.
+
+* Returned Value:
+* The nice central axis value.
+
+* Notes:
+* - The supplied axis value is returned if the supplied gap size is
+* zero, or if this function is invoked with the global error status
+* set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstTimeFrame *this;
+ char *date1;
+ char *date2;
+ char *f1;
+ char *f2;
+ char *fres;
+ char *p1;
+ char *p2;
+ char *pres;
+ const char *fmt;
+ const char *date;
+ double result;
+ int df;
+ int fmod;
+ int nc1;
+ int nc2;
+ int ndp;
+ int nres;
+ int v1;
+ int v2;
+
+/* Initialise. */
+ result = value;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate the axis index. */
+ astValidateAxis( this_frame, axis, 1, "astCentre" );
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* Use the parent astCentre function unless the Format attribute indicates
+ that axis values are to be formatted as multi-field date/time strings. */
+ fmt = astGetFormat( this, 0 );
+ df = DateFormat( fmt, &ndp, NULL, status );
+ if( !df ) {
+ result = (*parent_centre)( this_frame, axis, value, gap, status );
+
+/* Otherwise. */
+ } else {
+
+/* Format time values one gap above the supplied axis value and one gap below
+ it. Take copies of each string since the astFormat buffer will be
+ over-written by each call. */
+ date = astFormat( this, 0, value - gap );
+ if( date ) date1 = astStore( NULL, date, strlen( date ) + 1 );
+ date = astFormat( this, 0, value + gap );
+ if( date ) date2 = astStore( NULL, date, strlen( date ) + 1 );
+ if( astOK ) {
+
+/* Initialise a formatted version of the returned central value to be
+ equal to "date1". */
+ nres = strlen( date1 );
+ fres = astStore( NULL, date1, nres + 1 );
+
+/* Loop over all characters within the first date. */
+ fmod = 0;
+ nc1 = 0;
+ f1 = NULL;
+ p1 = date1;
+ nc2 = 0;
+ f2 = NULL;
+ p2 = date2;
+ while( 1 ) {
+
+/* If we have not yet found the length of the next numerical field in
+ date1, continue looking for it. */
+ if( !nc1 ) {
+
+/* If we are currently looking for the start of a numerical field, indicate
+ we have found one if the current character is a digit. */
+ if( !f1 ) {
+ if( isdigit( *p1 ) ) f1 = p1;
+
+/* If we are currently looking for the end of a numeric field, we have
+ found the end if the current character is not a digit. */
+ } else {
+ if( !isdigit( *p1 ) ) {
+ nc1 = p1 - f1;
+ }
+ }
+
+/* Look at the next character */
+ p1++;
+ }
+
+/* If we have not yet found the length of the next numerical field in
+ date2, continue looking for it. */
+ if( !nc2 ) {
+
+/* If we are currently looking for the start of a numerical field, indicate
+ we have found one if the current character is a digit. */
+ if( !f2 ) {
+ if( isdigit( *p2 ) ) f2 = p2;
+
+/* If we are currently looking for the end of a numeric field, we have
+ found the end if the current character is not a digit. */
+ } else {
+ if( !isdigit( *p2 ) ) {
+ nc2 = p2 - f2;
+ }
+ }
+
+/* Look at the next character */
+ p2++;
+ }
+
+/* If we have found the next numerical field in both dates, convert them
+ to integers. */
+ if( nc1 && nc2 ) {
+ v1 = atoi( f1 );
+ v2 = atoi( f2 );
+
+/* If the values are different, replace this field and all subsequent
+ fields with zeros in the formatted version of the returned central
+ value, and leave the loop. */
+ if( v1 != v2 ) {
+
+ pres = fres + ( f1 - date1 ) - 1;
+ while( *(++pres) ) {
+ if( isdigit( *pres ) ) *pres = '0';
+ }
+ fmod = 1;
+
+ break;
+ }
+
+/* Prepare to look for the next numerical field in both strings. */
+ nc1 = nc2 = 0;
+ f1 = f2 = NULL;
+
+/* If either string has been exhausted, leave the loop. */
+ if( !*p1 || !*p2 ) break;
+ }
+ }
+
+/* If the formatted "nice" value was changed, unformatted it to get the
+ returned axis value. Otherwise we rettina the returned value set
+ earlier. */
+ if( fmod ) {
+ if( astUnformat( this, 0, fres, &result ) != nres && astOK ) {
+ astError( AST__INTER, "astCentre(%s): Error unformatting "
+ "the central time axis value '%s' (internal AST "
+ "programming error).", status, astClass( this ), fres );
+ }
+ }
+
+/* Free resources. */
+ fres = astFree( fres );
+ }
+ date1 = astFree( date1 );
+ date2 = astFree( date2 );
+ }
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = 0.0;
+
+/* Return the result. */
+ return result;
+}
+
+static int DateFormat( const char *fmt, int *ndp, char *sep, int *status ){
+/*
+* Name:
+* DateFormat
+
+* Purpose:
+* Determine if TimeFrame values should be formatted as a date.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int DateFormat( const char *fmt, int *ndp, char *sep, int *status )
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function returns a flag indicating if the supplied Format string
+* requires the TimeFrame value to be formatted as a date and/or time of
+* day.
+
+* Parameters:
+* fmt
+* Pointer to Format string.
+* ndp
+* A pointer to an integer in which is returned a value indicating
+* if a time is required as well as a date. A value of -1 will be
+* returned in no time is required, otherwise the returned value will
+* equal the number of decimal places required for the seconds field.
+* sep
+* A pointer to a char in which is returned the character that
+* should be used to separate the date and time fields. Ignored if
+* NULL.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Non-zero if the formatted TimeFrame value should include a date.
+
+*/
+
+/* Local Variables: */
+ const char *c;
+ int nc;
+ int result;
+
+/* Initialise */
+ result = 0;
+ *ndp = -1;
+
+/* Check the Format string */
+ if( fmt ) {
+
+/* Find the first non-white character */
+ c = fmt;
+ while( *c && isspace( *c ) ) c++;
+
+/* If the first non-white character starts the string "iso"
+ assume a date is required. If so see if a time is also required
+ (indicated by 1 dot following) and how many seconds of precision are
+ required (the interegr following the dot). */
+ if( !strncmp( c, "iso", 3 ) ) {
+ result = 1;
+ if( astSscanf( c, "iso.%d%n", ndp, &nc ) == 1 ) {
+
+/* Check the separate character (if any) at the end of the format string.
+ Only "T" is allowed. A space is used if no separator is given. */
+ if( sep ) *sep = ( c[ nc ] == 'T' || c[ nc ] == 't' ) ? 'T' : ' ';
+
+ } else {
+ *ndp = -1;
+ }
+ }
+ }
+
+ return result;
+}
+
+static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* ClearAttrib
+
+* Purpose:
+* Clear an attribute value for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void ClearAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astClearAttrib protected
+* method inherited from the Frame class).
+
+* Description:
+* This function clears the value of a specified attribute for a
+* TimeFrame, so that the default value will subsequently be used.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* 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: */
+ AstTimeFrame *this; /* Pointer to the TimeFrame structure */
+ char *new_attrib; /* Pointer value to new attribute name */
+ int len; /* Length of attrib string */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_object;
+
+/* Obtain the length of the "attrib" string. */
+ len = strlen( attrib );
+
+/* Check the attribute name and clear the appropriate attribute. */
+
+/* First look for axis attributes defined by the Frame class. Since a
+ TimeFrame has only 1 axis, we allow these attributes to be specified
+ without a trailing "(axis)" string. */
+ if ( !strcmp( attrib, "direction" ) ||
+ !strcmp( attrib, "bottom" ) ||
+ !strcmp( attrib, "top" ) ||
+ !strcmp( attrib, "format" ) ||
+ !strcmp( attrib, "label" ) ||
+ !strcmp( attrib, "symbol" ) ||
+ !strcmp( attrib, "unit" ) ) {
+
+/* Create a new attribute name from the original by appending the string
+ "(1)" and then use the parent ClearAttrib method. */
+ new_attrib = astMalloc( len + 4 );
+ if( new_attrib ) {
+ memcpy( new_attrib, attrib, len );
+ memcpy( new_attrib + len, "(1)", 4 );
+ (*parent_clearattrib)( this_object, new_attrib, status );
+ new_attrib = astFree( new_attrib );
+ }
+
+/* AlignTimeScale. */
+/* --------------- */
+ } else if ( !strcmp( attrib, "aligntimescale" ) ) {
+ astClearAlignTimeScale( this );
+
+/* ClockLat. */
+/* --------- */
+/* Retained for backward compatibility with older versions of AST in which
+ TimeFrame had ClockLon/Lat attributes (now ObsLon/Lat are used instead). */
+ } else if ( !strcmp( attrib, "clocklat" ) ) {
+ astClearAttrib( this, "obslat" );
+
+/* ClockLon. */
+/* --------- */
+/* Retained for backward compatibility with older versions of AST in which
+ TimeFrame had ClockLon/Lat attributes (now ObsLon/Lat are used instead). */
+ } else if ( !strcmp( attrib, "clocklon" ) ) {
+ astClearAttrib( this, "obslon" );
+
+/* LTOffset. */
+/* --------- */
+ } else if ( !strcmp( attrib, "ltoffset" ) ) {
+ astClearLTOffset( this );
+
+/* TimeOrigin. */
+/* ---------- */
+ } else if ( !strcmp( attrib, "timeorigin" ) ) {
+ astClearTimeOrigin( this );
+
+/* TimeScale. */
+/* ---------- */
+ } else if ( !strcmp( attrib, "timescale" ) ) {
+ astClearTimeScale( this );
+
+/* If the attribute is not recognised, pass it on to the parent method
+ for further interpretation. */
+ } else {
+ (*parent_clearattrib)( this_object, attrib, status );
+ }
+}
+
+static void ClearSystem( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* ClearSystem
+
+* Purpose:
+* Clear the System attribute for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void ClearSystem( AstFrame *this_frame, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astClearSystem protected
+* method inherited from the Frame class).
+
+* Description:
+* This function clears the System attribute for a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstSystemType oldsys; /* System before clearing */
+ AstTimeFrame *this; /* Pointer to TimeFrame structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* Save the original system */
+ oldsys = astGetSystem( this_frame );
+
+/* Use the parent ClearSystem method to clear the System value. */
+ (*parent_clearsystem)( this_frame, status );
+
+/* Do nothing more if the system has not actually changed. */
+ if( astGetSystem( this_frame ) != oldsys ) {
+
+/* Modify the TimeOrigin value to use the new System */
+ OriginSystem( this, oldsys, "astClearSystem", status );
+
+/* Clear attributes which have system-specific defaults. */
+ astClearLabel( this_frame, 0 );
+ astClearSymbol( this_frame, 0 );
+ astClearTitle( this_frame );
+
+/* If the old system was BEPOCH also clear units and timescale. This is
+ because we need to ensure that TimeScale=TT and Unit=yr will be used
+ in future (these are the only acceptable values for System=BEPOCH). */
+ if( oldsys == AST__BEPOCH ) {
+ astClearUnit( this_frame, 0 );
+ astClearTimeScale( (AstTimeFrame *) this_frame );
+ }
+ }
+}
+
+static void ClearTimeScale( AstTimeFrame *this, int *status ) {
+/*
+*+
+* Name:
+* astClearTimeScale
+
+* Purpose:
+* Clear the TimeScale attribute for a TimeFrame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void astClearTimeScale( AstTimeFrame *this )
+
+* Class Membership:
+* TimeFrame virtual function
+
+* Description:
+* This function clears the TimeScale attribute for a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* If the System is currently set to BEPOCH, then the TimeScale will
+ either be set to TT or will be unset (since SetTimeScale will not
+ allow any other value than TT if the System is BEPOCH). Therefore, if
+ System is BEPOCH, we will not need to modify the TimeOrigin value,
+ since it will already be appropriate. Otherwise, we modify the
+ TimeOrigin value stored in the TimeFrame structure to refer to the
+ default timescale (TAI or TT). */
+ if( astGetSystem( this ) != AST__BEPOCH ) OriginScale( this, AST__TAI,
+ "astClearTimeScale", status );
+
+/* Store a bad value for the timescale in the TimeFrame structure. */
+ this->timescale = AST__BADTS;
+}
+
+static double CurrentTime( AstTimeFrame *this, int *status ){
+/*
+*++
+* Name:
+c astCurrentTime
+f AST_CURRENTTIME
+
+* Purpose:
+* Return the current system time.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "timeframe.h"
+c double astCurrentTime( AstTimeFrame *this )
+f RESULT = AST_CURRENTTIME( THIS, STATUS )
+
+* Class Membership:
+* TimeFrame method.
+
+* Description:
+c This function
+f This routine
+* returns the current system time, represented in the form specified
+* by the supplied TimeFrame. That is, the returned floating point
+* value should be interpreted using the attribute values of the
+* TimeFrame. This includes System, TimeOrigin, LTOffset, TimeScale,
+* and Unit.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the TimeFrame.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astCurrentTime()
+f AST_CURRENTTIME = DOUBLE
+c A TimeFrame axis value representing the current system time.
+
+* Notes:
+* - Values of AST__BAD will be returned if this function is
+c invoked with the AST error status set, or if it should fail for
+f invoked with STATUS set to an error value, or if it should fail for
+* any reason.
+* - It is assumes that the system time (returned by the C time()
+* function) follows the POSIX standard, representing a continuous
+* monotonic increasing count of SI seconds since the epoch 00:00:00
+* UTC 1 January 1970 AD (equivalent to TAI with a constant offset).
+* Resolution is one second.
+* - An error will be reported if the TimeFrame has a TimeScale value
+* which cannot be converted to TAI (e.g. "angular" systems such as
+* UT1, GMST, LMST and LAST).
+* - Any inaccuracy in the system clock will be reflected in the value
+* returned by this function.
+*--
+*/
+
+/* Local Constants: */
+
+/* Local Variables: */
+ AstMapping *map;
+ double result;
+ double systime;
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a Mapping from the system time (TAI seconds relative to "tai_epoch")
+ to the system represented by the supplied TimeFrame. */
+ map = MakeMap( this, AST__MJD, astGetSystem( this ),
+ AST__TAI, astGetTimeScale( this ),
+ tai_epoch, astGetTimeOrigin( this ),
+ "s", astGetUnit( this, 0 ), "astCurrentTime", status );
+ if( !map ) {
+ astError( AST__INCTS, "astCurrentTime(%s): Cannot convert the "
+ "current system time to the required timescale (%s).", status,
+ astGetClass( this ),
+ TimeScaleString( astGetTimeScale( this ), status ) );
+
+/* Get the system time. The "time" function returns a "time_t" which may be
+ encoded in any way. We use "difftime" to convert this into a floating
+ point number of seconds by taking the difference between the current
+ time and zero time. This assumes nothing about the structure of a
+ "time_t" except that zero can be cast into a time_t representing
+ the epoch. */
+ } else {
+ systime = difftime( time( NULL ), (time_t) 0 );
+
+/* Use the Mapping to convert the time into the requied system. */
+ astTran1( map, 1, &systime, 1, &result );
+
+/* Free resources */
+ map = astAnnul( map );
+ }
+
+/* Set result to AST__BAD if an error occurred. */
+ if( !astOK ) result = AST__BAD;
+
+/* Return the result. */
+ return result;
+}
+
+static const char *DefUnit( AstSystemType system, const char *method,
+ const char *class, int *status ){
+/*
+* Name:
+* DefUnit
+
+* Purpose:
+* Return the default units for a time coordinate system type.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *DefUnit( AstSystemType system, const char *method,
+* const char *class, int *status )
+
+* Class Membership:
+* TimeFrame member function.
+
+* Description:
+* This function returns a textual representation of the default
+* units associated with the specified time coordinate system.
+
+* Parameters:
+* system
+* The time coordinate system.
+* method
+* Pointer to a string holding the name of the calling method.
+* This is only for use in constructing error messages.
+* class
+* Pointer to a string holding the name of the supplied object class.
+* This is only for use in constructing error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A string describing the default units. This string follows the
+* units syntax described in FITS WCS paper I "Representations of world
+* coordinates in FITS" (Greisen & Calabretta).
+
+* Notes:
+* - A NULL pointer is returned if this function is invoked with
+* the global error status set or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ const char *result; /* Value to return */
+
+/* Initialize */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get an identifier for the default units. */
+ if( system == AST__MJD ) {
+ result = "d";
+ } else if( system == AST__JD ) {
+ result = "d";
+ } else if( system == AST__BEPOCH ) {
+ result = "yr";
+ } else if( system == AST__JEPOCH ) {
+ result = "yr";
+
+/* Report an error if the coordinate system was not recognised. */
+ } else {
+ astError( AST__SCSIN, "%s(%s): Corrupt %s contains illegal System "
+ "identification code (%d).", status, method, class, class,
+ (int) system );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int Fields( AstFrame *this_frame, int axis, const char *fmt,
+ const char *str, int maxfld, char **fields,
+ int *nc, double *val, int *status ) {
+/*
+* Name:
+* Fields
+
+* Purpose:
+* Identify numerical fields within a formatted Axis value.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "frame.h"
+* int Fields( AstFrame *this, int axis, const char *fmt,
+* const char *str, int maxfld, char **fields,
+* int *nc, double *val )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astFields protected
+* method inherited from the Frame class).
+
+* 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.
+*/
+
+/* Local Variables: */
+ AstTimeFrame *this;
+ char *p;
+ int bad;
+ int df;
+ int ifld;
+ int ndp;
+ int result;
+ int state;
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astFields" );
+
+/* Call the method inherited from the parent Frame class, unless the
+ format string indicates date-time formatting. */
+ df = DateFormat( fmt, &ndp, NULL, status );
+ if( !df ) {
+ result = (*parent_fields)( this_frame, axis, fmt, str, maxfld, fields,
+ nc, val, status );
+
+/* Now handle date/time formats.... */
+ } else {
+
+/* Initialise. */
+ for( ifld = 0; ifld < maxfld; ifld++ ) {
+ fields[ ifld ] = NULL;
+ nc[ ifld ] = 0;
+ }
+ if( val ) *val = AST__BAD;
+
+/* The formatted string should always include a date in ISO format - three
+ integer fields separated by dashes. Loop round each character until
+ all characters have been read, or the max number of fields have been
+ obtained, or it is shown that the string is badly formatted. */
+ bad = 0;
+ state = 0;
+ ifld = 0;
+ p = (char *) str - 1;
+ while( *(++p) && ifld < maxfld && !bad ){
+
+/* Looking for the start of the year field. */
+ if( state == 0 ) {
+ if( isdigit( *p ) ) {
+ fields[ ifld ] = p;
+ nc[ ifld ] = 1;
+ state = 1;
+ } else if( !isspace( *p ) ) {
+ bad = 1;
+ }
+
+/* Looking for the end of the year field. */
+ } else if( state == 1 ) {
+ if( isdigit( *p ) ) {
+ nc[ ifld ]++;
+ } else if( *p != '-' ){
+ bad = 1;
+ } else {
+ state = 2;
+ ifld++;
+ }
+
+/* Looking for the start of the month field. */
+ } else if( state == 2 ) {
+ if( isdigit( *p ) ) {
+ fields[ ifld ] = p;
+ nc[ ifld ] = 1;
+ state = 3;
+ } else {
+ bad = 1;
+ }
+
+/* Looking for the end of the month field. */
+ } else if( state == 3 ) {
+ if( isdigit( *p ) ) {
+ nc[ ifld ]++;
+ } else if( *p != '-' ){
+ bad = 1;
+ } else {
+ state = 4;
+ ifld++;
+ }
+
+/* Looking for the start of the day field. */
+ } else if( state == 4 ) {
+ if( isdigit( *p ) ) {
+ fields[ ifld ] = p;
+ nc[ ifld ] = 1;
+ state = 5;
+ } else {
+ bad = 1;
+ }
+
+/* Looking for the end of the day field. */
+ } else if( state == 5 ) {
+ if( isdigit( *p ) ) {
+ nc[ ifld ]++;
+ } else if( *p != ' ' && *p != 'T' ){
+ bad = 1;
+ } else {
+ state = 6;
+ ifld++;
+ }
+
+/* Looking for the start of the hour field. */
+ } else if( state == 6 ) {
+ if( isdigit( *p ) ) {
+ fields[ ifld ] = p;
+ nc[ ifld ] = 1;
+ state = 7;
+ } else {
+ bad = 1;
+ }
+
+/* Looking for the end of the hour field. */
+ } else if( state == 7 ) {
+ if( isdigit( *p ) ) {
+ nc[ ifld ]++;
+ } else if( *p != ':' ){
+ bad = 1;
+ } else {
+ state = 8;
+ ifld++;
+ }
+
+/* Looking for the start of the minute field. */
+ } else if( state == 8 ) {
+ if( isdigit( *p ) ) {
+ fields[ ifld ] = p;
+ nc[ ifld ] = 1;
+ state = 9;
+ } else {
+ bad = 1;
+ }
+
+/* Looking for the end of the minute field. */
+ } else if( state == 9 ) {
+ if( isdigit( *p ) ) {
+ nc[ ifld ]++;
+ } else if( *p != ':' ){
+ bad = 1;
+ } else {
+ state = 10;
+ ifld++;
+ }
+
+/* Looking for the start of the integer part of the seconds field. */
+ } else if( state == 10 ) {
+ if( isdigit( *p ) ) {
+ fields[ ifld ] = p;
+ nc[ ifld ] = 1;
+ state = 11;
+ } else {
+ bad = 1;
+ }
+
+/* Looking for the end of the integer part of the seconds field. */
+ } else if( state == 11 ) {
+ if( isdigit( *p ) ) {
+ nc[ ifld ]++;
+ } else if( *p != '.' ){
+ bad = 1;
+ } else {
+ state = 12;
+ ifld++;
+ }
+
+/* Looking for the start of the decimal part of the seconds field. */
+ } else if( state == 12 ) {
+ if( isdigit( *p ) ) {
+ fields[ ifld ] = p;
+ nc[ ifld ] = 1;
+ state = 13;
+ } else {
+ bad = 1;
+ }
+
+/* Looking for the end of the decimal part of the seconds field. */
+ } else if( state == 13 ) {
+ if( isdigit( *p ) ) {
+ nc[ ifld ]++;
+ } else if( !isspace( *p ) ){
+ bad = 1;
+ }
+
+ } else {
+ bad = 1;
+ }
+ }
+
+/* If he string is badly formatted, return null values. */
+ if( bad ) {
+ result = 0;
+ for( ifld = 0; ifld < maxfld; ifld++ ) {
+ fields[ ifld ] = NULL;
+ nc[ ifld ] = 0;
+ }
+
+/* Otherwise, unformat the string if required. */
+ } else if( val ) {
+ (void) astUnformat( this, axis, str, val );
+ }
+ }
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+static const char *Format( AstFrame *this_frame, int axis, double value, int *status ) {
+/*
+* Name:
+* Format
+
+* Purpose:
+* Format a coordinate value for a TimeFrame axis.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *Format( AstFrame *this, int axis, double value, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astFormat method inherited
+* from the Frame class).
+
+* Description:
+* This function returns a pointer to a string containing the formatted
+* (character) version of a coordinate value for a TimeFrame axis. The
+* formatting applied is that specified by a previous invocation of the
+* astSetFormat method. A suitable default format is applied if necessary.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* axis
+* The number of the axis (zero-based) for which formatting is to be
+* performed.
+* value
+* The coordinate value to be formatted, in radians.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to a null-terminated string containing the formatted value.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS
+ AstMapping *map;
+ AstSystemType sys;
+ AstTimeFrame *this;
+ AstTimeScaleType ts;
+ char *d;
+ char sep;
+ char tbuf[ 100 ];
+ char sign[ 2 ];
+ const char *fmt;
+ const char *result;
+ const char *u;
+ double fd;
+ double mjd;
+ double off;
+ int df;
+ int id;
+ int ihmsf[ 4 ];
+ int im;
+ int iy;
+ int j;
+ int ndp;
+
+/* Initialise */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_frame);
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astFormat" );
+
+/* Check if a bad coordinate value was supplied and return a pointer to an
+ appropriate string if necessary. */
+ if ( value == AST__BAD ) {
+ result = "<bad>";
+ } else {
+
+/* If the format string does not indicate a date/time format, invoke the
+ parent Format method. */
+ fmt = astGetFormat( this, 0 );
+ df = DateFormat( fmt, &ndp, &sep, status );
+ if( !df ) {
+ result = (*parent_format)( this_frame, axis, value, status );
+
+/* Otherwise, format the value as a date/time */
+ } else {
+
+/* Convert the value to an absolute MJD in units of days. */
+ ts = astGetTimeScale( this );
+ sys = astGetSystem( this );
+ off = astGetTimeOrigin( this );
+ u = astGetUnit( this, 0 );
+ map = MakeMap( this, sys, AST__MJD, ts, ts, off, 0.0, u, "d",
+ "astFormat", status );
+ if( map ) {
+ astTran1( map, 1, &value, 1, &mjd );
+ map = astAnnul( map );
+
+/* If no time fields will be produced, round to the nearest day. */
+ if( ndp < 0 ) mjd = (int) ( mjd + 0.5 );
+
+/* Convert the MJD into a set of numeric date fields, plus day fraction,
+ and format them. */
+ palDjcl( mjd, &iy, &im, &id, &fd, &j );
+ d = format_buff;
+ d += sprintf( d, "%4d-%2.2d-%2.2d", iy, im, id );
+
+/* If required, convert the day fraction into a set of numerical time
+ fields. */
+ if( ndp >= 0 ) {
+ palDd2tf( ndp, fd, sign, ihmsf );
+
+/* Format the time fields. */
+ if( ndp > 0 ) {
+ (void) sprintf( tbuf, "%c%2.2d:%2.2d:%2.2d.%*.*d", sep,
+ ihmsf[0], ihmsf[1], ihmsf[2], ndp, ndp,
+ ihmsf[3] );
+ } else {
+ (void) sprintf( tbuf, "%c%2.2d:%2.2d:%2.2d", sep, ihmsf[0],
+ ihmsf[1], ihmsf[2] );
+ }
+
+/* Add in the formatted time. */
+ d += sprintf( d, "%s", tbuf );
+
+ }
+ result = format_buff;
+ }
+ }
+ }
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+static double FromMJD( AstTimeFrame *this, double oldval, int *status ){
+/*
+*
+* Name:
+* FromMJD
+
+* Purpose:
+* Convert a supplied MJD value to the System of the supplied TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* double FromMJD( AstTimeFrame *this, double oldval, int *status )
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function converts the supplied time value from an MJD to
+* the System of the supplied TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* oldval
+* The value to be converted. It is assume to be an absolute MJD
+* value (i.e. zero offset) in units of days.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The converted value (with zero offset), in the default units
+* associated with the System of "this".
+
+*/
+
+/* Local Variables: */
+ AstTimeMap *timemap;
+ AstSystemType newsys;
+ double args[ 2 ];
+ double result;
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get the System attribute from the supplied TimeFrame. */
+ newsys = astGetSystem( this );
+
+/* If this is MJD just return the value unchanged. */
+ if( newsys == AST__MJD ) {
+ result = oldval;
+
+/* Otherwise create a TimeMap wich converts from the MJD to the required
+ system, and use it to transform the supplied value. */
+ } else {
+ timemap = astTimeMap( 0, "", status );
+
+/* The supplied and returned values are assumed to have zero offset.*/
+ args[ 0 ] = 0.0;
+ args[ 1 ] = 0.0;
+
+/* If required, add a TimeMap conversion which converts from MJD to the
+ new system. */
+ if( newsys == AST__JD ) {
+ astTimeAdd( timemap, "MJDTOJD", 2, args );
+
+ } else if( newsys == AST__JEPOCH ) {
+ astTimeAdd( timemap, "MJDTOJEP", 2, args );
+
+ } else if( newsys == AST__BEPOCH ) {
+ astTimeAdd( timemap, "MJDTOBEP", 2, args );
+ }
+
+/* Use the TimeMap to convert the supplied value. */
+ astTran1( timemap, 1, &oldval, 1, &result );
+
+/* Free resources */
+ timemap = astAnnul( timemap );
+
+ }
+
+/* Return the result */
+ return result;
+}
+
+
+static double Gap( AstFrame *this_frame, int axis, double gap, int *ntick, int *status ) {
+/*
+* Name:
+* Gap
+
+* Purpose:
+* Find a "nice" gap for tabulating Frame axis values.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* double Gap( AstFrame *this, int axis, double gap, int *ntick, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGap protected
+* method inherited from the Frame class).
+
+* 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.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The nice gap size.
+
+* Notes:
+* - A value of zero is returned if the target gap size is zero.
+* - A negative gap size is returned if the supplied gap size is negative.
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstMapping *map;
+ AstTimeFrame *this;
+ AstTimeScaleType ts;
+ const char *fmt;
+ double mjdgap;
+ double result;
+ double xin[2];
+ double xout[2];
+ int df;
+ int ndp;
+
+/* Initialise. */
+ result = 0.0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Validate the axis index. */
+ astValidateAxis( this_frame, axis, 1, "astGap" );
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* Use the parent astGap function unless the Format attribute indicates
+ that axis values are to be formatted as multi-field date/time strings. */
+ fmt = astGetFormat( this, 0 );
+ df = DateFormat( fmt, &ndp, NULL, status );
+ if( !df ) {
+ result = (*parent_gap)( this_frame, axis, gap, ntick, status );
+
+/* Otherwise. */
+ } else {
+
+/* Get a Mapping which converts TimeFrame values to MJD values. */
+ ts = astGetTimeScale( this );
+ map = MakeMap( this, astGetSystem( this ), AST__MJD, ts, ts,
+ astGetTimeOrigin( this ), 0.0, astGetUnit( this, 0 ),
+ "d", "astGap", status );
+ if( map ) {
+
+/* Use it to transform two TimeFrame times to MJD. The first is the
+ current time, and the second is the current time plus the target gap. */
+ xin[ 0 ] = astCurrentTime( this );
+ xin[ 1 ] = xin[ 0 ] + gap;
+ astTran1( map, 2, xin, 1, xout );
+
+/* Find the target MJD gap. */
+ mjdgap = xout[ 1 ] - xout[ 0 ];
+
+/* If it is 1 year or more, use the parent astGap method to find a nice
+ number of years, and convert back to days. */
+ if( mjdgap >= 365.25 ) {
+ mjdgap = 365.25*(*parent_gap)( this_frame, axis, mjdgap/365.25, ntick, status );
+
+/* If it is more than 270 days days use 1 year. */
+ } else if( mjdgap > 270.0 ) {
+ mjdgap = 365.25;
+ *ntick = 4;
+
+/* If it is more than 150 days days use 180 days (roughly half a year).
+ Use 6 divisions (30 days each, or roughly 1 month). */
+ } else if( mjdgap > 150.0 ) {
+ mjdgap = 180.0;
+ *ntick = 6;
+
+/* If it is more than 90 days days use 120 days (roughly 4 months). */
+ } else if( mjdgap > 90.0 ) {
+ mjdgap = 120.0;
+ *ntick = 4;
+
+/* If it is more than 45 days days use 60 days (roughly 2 months). */
+ } else if( mjdgap > 45.0 ) {
+ mjdgap = 60.0;
+ *ntick = 2;
+
+/* If it is more than 22 days days use 30 days (roughly one month). Use 3
+ ten day divisions. */
+ } else if( mjdgap > 22.0 ) {
+ mjdgap = 30.0;
+ *ntick = 3;
+
+/* If it is more than 12 days days use 15 days (roughly half a month). */
+ } else if( mjdgap > 12.0 ) {
+ mjdgap = 15.0;
+ *ntick = 3;
+
+/* If it is more than 7.5 days days use 10 days, with 5 two-day divisions. */
+ } else if( mjdgap > 7.5 ) {
+ mjdgap = 10.0;
+ *ntick = 5;
+
+/* If it is more than 4.5 days days use 5 days. */
+ } else if( mjdgap > 4.5 ) {
+ mjdgap = 5.0;
+ *ntick = 5;
+
+/* If it is more than 3 days days use 4 days. */
+ } else if( mjdgap > 3.0 ) {
+ mjdgap = 4.0;
+ *ntick = 4;
+
+/* If it is more than 1.5 days days use 2 days. */
+ } else if( mjdgap > 1.5 ) {
+ mjdgap = 2.0;
+ *ntick = 2;
+
+/* If it is more than 0.5 of a day use 1 day. */
+ } else if( mjdgap > 0.5 ) {
+ mjdgap = 1.0;
+ *ntick = 4;
+
+/* Otherwise, if the format indicates that no time field is allowed,
+ use 1 day. */
+ } else if( ndp < 0 ) {
+ mjdgap = 1.0;
+ *ntick = 2;
+
+/* Otherwise (i.e. if the target gap is 0.5 day or less and the format
+ indicates that a time field is allowed), choose a value which looks
+ nice. */
+ } else if( mjdgap >= 6.0/24.0 ) { /* 12 hours */
+ mjdgap = 12.0/24.0;
+ *ntick = 4;
+
+ } else if( mjdgap >= 3.0/24.0 ) { /* 6 hours */
+ mjdgap = 6.0/24.0;
+ *ntick = 3;
+
+ } else if( mjdgap >= 1.0/24.0 ) { /* 2 hours */
+ mjdgap = 2.0/24.0;
+ *ntick = 4;
+
+ } else if( mjdgap >= 30.0/1440.0 ) { /* 1 hour */
+ mjdgap = 60.0/1440.0;
+ *ntick = 4;
+
+ } else if( mjdgap >= 15.0/1440.0 ) { /* 30 minutes */
+ mjdgap = 30.0/1440.0;
+ *ntick = 3;
+
+ } else if( mjdgap >= 5.0/1440.0 ) { /* 10 minutes */
+ mjdgap = 10.0/1440.0;
+ *ntick = 5;
+
+ } else if( mjdgap >= 2.5/1440.0 ) { /* 5 minutes */
+ mjdgap = 5.0/1440.0;
+ *ntick = 5;
+
+ } else if( mjdgap >= 1.0/1440.0 ) { /* 2 minutes */
+ mjdgap = 2.0/1440.0;
+ *ntick = 4;
+
+ } else if( mjdgap >= 0.5/1440.0 ) { /* 1 minute */
+ mjdgap = 1.0/1440.0;
+ *ntick = 4;
+
+ } else if( mjdgap >= 15.0/86400.0 ) { /* 30 seconds */
+ mjdgap = 30.0/86400.0;
+ *ntick = 3;
+
+ } else if( mjdgap >= 5.0/86400.0 ) { /* 10 seconds */
+ mjdgap = 10.0/86400.0;
+ *ntick = 5;
+
+ } else if( mjdgap >= 2.5/86400.0 ) { /* 5 seconds */
+ mjdgap = 5.0/86400.0;
+ *ntick = 5;
+
+ } else if( mjdgap >= 1.0/86400.0 ) { /* 2 seconds */
+ mjdgap = 2.0/86400.0;
+ *ntick = 4;
+
+ } else if( mjdgap >= 0.5/86400.0 ) { /* 1 second */
+ mjdgap = 1.0/86400.0;
+ *ntick = 4;
+
+ } else { /* Less than 1 second */
+ mjdgap = 86400.0*(*parent_gap)( this_frame, axis, mjdgap/86400.0, ntick, status );
+
+ }
+
+/* Convert the MJD gap back into the system of the supplied TimeFrame. */
+ xout[ 1 ] = xout[ 0 ] + mjdgap;
+ astTran1( map, 2, xout, 0, xin );
+ result = xin[ 1 ] - xin[ 0 ];
+
+/* Free resources */
+ map = astAnnul( map );
+
+/* If no Mapping could be found, use the parent astGap method. */
+ } else {
+ result = (*parent_gap)( this_frame, axis, gap, ntick, status );
+ }
+ }
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = 0.0;
+
+/* Return the result. */
+ return result;
+}
+
+static int GetActiveUnit( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* GetActiveUnit
+
+* Purpose:
+* Obtain the value of the ActiveUnit flag for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int GetActiveUnit( AstFrame *this_frame, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetActiveUnit protected
+* method inherited from the Frame class).
+
+* Description:
+* This function returns the value of the ActiveUnit flag for a
+* TimeFrame, which is always 1.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The value to use for the ActiveUnit flag (1).
+
+*/
+ return 1;
+}
+
+static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* GetAttrib
+
+* Purpose:
+* Get the value of a specified attribute for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *GetAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the protected astGetAttrib
+* method inherited from the Frame class).
+
+* Description:
+* This function returns a pointer to the value of a specified
+* attribute for a TimeFrame, formatted as a character string.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* 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 TimeFrame, 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 TimeFrame. 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: */
+ AstTimeFrame *this; /* Pointer to the TimeFrame structure */
+ AstTimeScaleType ts; /* Time scale */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ char *new_attrib; /* Pointer value to new attribute name */
+ const char *result; /* Pointer value to return */
+ double dval; /* Attribute value */
+ int len; /* Length of attrib string */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_object);
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_object;
+
+/* Obtain the length of the attrib string. */
+ len = strlen( attrib );
+
+/* Compare "attrib" with each recognised attribute name in turn,
+ obtaining the value of the required attribute. If necessary, write
+ the value into "getattrib_buff" as a null-terminated string in an appropriate
+ format. Set "result" to point at the result string. */
+
+/* First look for axis attributes defined by the Frame class. Since a
+ TimeFrame has only 1 axis, we allow these attributes to be specified
+ without a trailing "(axis)" string. */
+ if ( !strcmp( attrib, "direction" ) ||
+ !strcmp( attrib, "bottom" ) ||
+ !strcmp( attrib, "top" ) ||
+ !strcmp( attrib, "format" ) ||
+ !strcmp( attrib, "label" ) ||
+ !strcmp( attrib, "symbol" ) ||
+ !strcmp( attrib, "unit" ) ) {
+
+/* Create a new attribute name from the original by appending the string
+ "(1)" and then use the parent GetAttrib method. */
+ new_attrib = astMalloc( len + 4 );
+ if( new_attrib ) {
+ memcpy( new_attrib, attrib, len );
+ memcpy( new_attrib + len, "(1)", 4 );
+ result = (*parent_getattrib)( this_object, new_attrib, status );
+ new_attrib = astFree( new_attrib );
+ }
+
+/* AlignTimeScale. */
+/* --------------- */
+/* Obtain the AlignTimeScale code and convert to a string. */
+ } else if ( !strcmp( attrib, "aligntimescale" ) ) {
+ ts = astGetAlignTimeScale( this );
+ if ( astOK ) {
+ result = TimeScaleString( ts, status );
+
+/* Report an error if the value was not recognised. */
+ if ( !result ) {
+ astError( AST__SCSIN,
+ "astGetAttrib(%s): Corrupt %s contains invalid AlignTimeScale "
+ "identification code (%d).", status, astGetClass( this ),
+ astGetClass( this ), (int) ts );
+ }
+ }
+
+/* ClockLat. */
+/* ------- */
+ } else if ( !strcmp( attrib, "clocklat" ) ) {
+ result = astGetAttrib( this, "obslat" );
+
+/* ClockLon. */
+/* ------- */
+ } else if ( !strcmp( attrib, "clocklon" ) ) {
+ result = astGetAttrib( this, "obslon" );
+
+/* TimeOrigin. */
+/* ----------- */
+ } else if ( !strcmp( attrib, "timeorigin" ) ) {
+ dval = GetTimeOriginCur( this, status );
+ if( astOK ) {
+ (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval );
+ result = getattrib_buff;
+ }
+
+/* LTOffset. */
+/* --------- */
+ } else if ( !strcmp( attrib, "ltoffset" ) ) {
+ dval = astGetLTOffset( this );
+ if( astOK ) {
+ (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval );
+ result = getattrib_buff;
+ }
+
+/* TimeScale. */
+/* ---------- */
+/* Obtain the TimeScale code and convert to a string. */
+ } else if ( !strcmp( attrib, "timescale" ) ) {
+ ts = astGetTimeScale( this );
+ if ( astOK ) {
+ result = TimeScaleString( ts, status );
+
+/* Report an error if the value was not recognised. */
+ if ( !result ) {
+ astError( AST__SCSIN,
+ "astGetAttrib(%s): Corrupt %s contains invalid TimeScale "
+ "identification code (%d).", status, astGetClass( this ),
+ astGetClass( this ), (int) ts );
+ }
+ }
+
+/* If the attribute name was not recognised, pass it on to the parent
+ method for further interpretation. */
+ } else {
+ result = (*parent_getattrib)( this_object, attrib, status );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static double GetTimeOriginCur( AstTimeFrame *this, int *status ) {
+/*
+* Name:
+* GetTimeOriginCur
+
+* Purpose:
+* Obtain the TimeOrigin attribute for a TimeFrame in current units.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* double GetTimeOriginCur( AstTimeFrame *this, int *status )
+
+* Class Membership:
+* TimeFrame virtual function
+
+* Description:
+* This function returns the TimeOrigin attribute for a TimeFrame, in
+* the current units of the TimeFrame. The protected astGetTimeOrigin
+* method can be used to obtain the time origin in the default units of
+* the TimeFrame's System.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The TimeOrigin value, in the units, system and timescale specified
+* by the current values of the Unit, System and TimeScale attributes
+* within "this".
+
+* Notes:
+* - AST__BAD is returned if this function is invoked with
+* the global error status set or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstMapping *map;
+ const char *cur;
+ const char *def;
+ double result;
+ double defval;
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get the value in the default units */
+ result = astGetTimeOrigin( this );
+
+/* If non-zero we convert to the current units.*/
+ if( result != 0.0 && result != AST__BAD ) {
+
+/* Get the default units for the TimeFrame's System. */
+ def = DefUnit( astGetSystem( this ), "astGetTimeOrigin", "TimeFrame", status );
+
+/* Get the current units from the TimeFrame. */
+ cur = astGetUnit( this, 0 );
+
+/* If the units differ, get a Mapping from default to current units. */
+ if( cur && def ){
+ if( strcmp( cur, def ) ) {
+ map = astUnitMapper( def, cur, NULL, NULL );
+
+/* Report an error if the units are incompatible. */
+ if( !map ) {
+ astError( AST__BADUN, "%s(%s): The current units (%s) are not suitable "
+ "for a TimeFrame.", status, "astGetTimeOrigin", astGetClass( this ),
+ cur );
+
+/* Otherwise, transform the stored origin value.*/
+ } else {
+ defval = result;
+ astTran1( map, 1, &defval, 1, &result );
+ map = astAnnul( map );
+ }
+ }
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *GetDomain( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* GetDomain
+
+* Purpose:
+* Obtain a pointer to the Domain attribute string for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *GetDomain( AstFrame *this, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetDomain protected
+* method inherited from the Frame class).
+
+* Description:
+* This function returns a pointer to the Domain attribute string
+* for a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to a constant null-terminated string containing the
+* Domain value.
+
+* Notes:
+* - The returned pointer or the string it refers to may become
+* invalid following further invocation of this function or
+* modification of the TimeFrame.
+* - 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: */
+ AstTimeFrame *this; /* Pointer to TimeFrame structure */
+ const char *result; /* Pointer value to return */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* If a Domain attribute string has been set, invoke the parent method
+ to obtain a pointer to it. */
+ if ( astTestDomain( this ) ) {
+ result = (*parent_getdomain)( this_frame, status );
+
+/* Otherwise, provide a pointer to a suitable default string. */
+ } else {
+ result = "TIME";
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static double GetEpoch( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* GetEpoch
+
+* Purpose:
+* Get a value for the Epoch attribute of a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* double GetEpoch( AstFrame *this, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetEpoch method
+* inherited from the Frame class).
+
+* Description:
+* This function returns a value for the Epoch attribute of a
+* TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The Epoch attribute value.
+
+* Notes:
+* - A value of AST__BAD will be returned if this function is invoked
+* with the global error status set or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstMapping *map;
+ AstSystemType sys;
+ AstTimeFrame *this;
+ AstTimeScaleType ts;
+ const char *u;
+ double oldval;
+ double result;
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* If an Epoch attribute value has been set, invoke the parent method
+ to obtain it. */
+ if ( astTestEpoch( this ) ) {
+ result = (*parent_getepoch)( this_frame, status );
+
+/* Otherwise, if the TimeOrigin value is set in the TimeFrame,
+ return it, converted to an absolute TDB MJD. */
+ } else if( astTestTimeOrigin( this ) ){
+
+/* Get the required properties of the TimeFrame. */
+ oldval = astGetTimeOrigin( this );
+ ts = astGetTimeScale( this );
+ sys = astGetSystem( this );
+ u = DefUnit( sys, "astGetEpoch", "TimeFrame", status );
+
+/* Epoch is defined as a TDB value. If the timescale is stored in an angular
+ timescale such as UT1, then we would not normally be able to convert it
+ to TDB since knowledge of DUT1 is required (the difference between UTC
+ and UT1). Since the default Epoch value is not critical we assume a DUT1
+ value of zero in this case. We first map the stored value to UT1 then
+ from UTC to TDB (using the approximation UT1 == UTC). */
+ if( ts == AST__UT1 || ts == AST__GMST ||
+ ts == AST__LAST || ts == AST__LMST ) {
+ map = MakeMap( this, sys, AST__MJD, ts, AST__UT1, 0.0, 0.0, u,
+ "d", "astGetEpoch", status );
+ if( map ) {
+ astTran1( map, 1, &oldval, 1, &result );
+ map = astAnnul( map );
+
+/* Update the values to use when converting to TBD. */
+ oldval = result;
+ ts = AST__UTC;
+ sys = AST__MJD;
+ u = "d";
+
+ } else if( astOK ) {
+ astError( AST__INTER, "astGetEpoch(%s): No Mapping from %s to "
+ "UT1 (AST internal programming error).", status,
+ astGetClass( this ), TimeScaleString( ts, status ) );
+ }
+ }
+
+/* Now convert to TDB */
+ map = MakeMap( this, sys, AST__MJD, ts, AST__TDB, 0.0, 0.0, u,
+ "d", "astGetEpoch", status );
+ if( map ) {
+ oldval = astGetTimeOrigin( this );
+ astTran1( map, 1, &oldval, 1, &result );
+ map = astAnnul( map );
+
+ } else if( astOK ) {
+ astError( AST__INTER, "astGetEpoch(%s): No Mapping from %s to "
+ "TDB (AST internal programming error).", status,
+ astGetClass( this ), TimeScaleString( ts, status ) );
+ }
+
+/* Otherwise, return the default Epoch value from the parent Frame. */
+ } else {
+ result = (*parent_getepoch)( this_frame, status );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *GetLabel( AstFrame *this, int axis, int *status ) {
+/*
+* Name:
+* GetLabel
+
+* Purpose:
+* Access the Label string for a TimeFrame axis.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *GetLabel( AstFrame *this, int axis, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetLabel method inherited
+* from the Frame class).
+
+* Description:
+* This function returns a pointer to the Label string for a specified axis
+* of a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* axis
+* Axis index (zero-based) identifying the axis for which information is
+* required.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to a constant null-terminated character string containing the
+* requested information.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstMapping *map; /* Mapping between units */
+ AstSystemType system; /* Code identifying type of time coordinates */
+ char *new_lab; /* Modified label string */
+ const char *fmt; /* Pointer to original Format string */
+ const char *result; /* Pointer to label string */
+ double ltoff; /* Local Time offset from UTC (hours) */
+ double orig; /* Time origin (seconds) */
+ int fmtSet; /* Was Format attribute set? */
+ int ndp; /* Number of decimal places for seconds field */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* Initialise. */
+ result = NULL;
+
+/* Validate the axis index. */
+ astValidateAxis( this, axis, 1, "astGetLabel" );
+
+/* Check if a value has been set for the required axis label string. If so,
+ invoke the parent astGetLabel method to obtain a pointer to it. */
+ if ( astTestLabel( this, axis ) ) {
+ result = (*parent_getlabel)( this, axis, status );
+
+/* Otherwise, provide a suitable default label. */
+ } else {
+
+/* If the Format attribute indicates that time values will be formatted
+ as dates, then choose a suitable label. */
+ fmt = astGetFormat( this, 0 );
+ if( DateFormat( fmt, &ndp, NULL, status ) ) {
+ result = ( ndp >= 0 ) ? "Date/Time" : "Date";
+
+/* Otherwise, identify the time coordinate system described by the
+ TimeFrame. */
+ } else {
+ system = astGetSystem( this );
+
+/* If OK, supply a pointer to a suitable default label string. */
+ if ( astOK ) {
+ result = strcpy( getlabel_buff, SystemLabel( system, status ) );
+ getlabel_buff[ 0 ] = toupper( getlabel_buff[ 0 ] );
+
+/* If a non-zero TimeOrigin has been specified, include the offset now as a
+ date/time string. */
+ orig = astGetTimeOrigin( this );
+ if( orig != 0.0 ) {
+
+/* Save the Format attribute, and then temporarily set it to give a date/time
+ string. */
+ fmt = astStore( NULL, fmt, strlen( fmt ) + 1 );
+ fmtSet = astTestFormat( this, 0 );
+ astSetFormat( this, 0, "iso.0" );
+
+/* Format the origin value as an absolute time and append it to the
+ returned label string. Note, the origin always corresponds to a
+ TimeFrame axis value of zero. */
+ sprintf( getlabel_buff + strlen( getlabel_buff ), " offset from %s",
+ astFormat( this, 0, 0.0 ) );
+
+/* Re-instate the original Format value. */
+ if( fmtSet ) {
+ astSetFormat( this, 0, fmt );
+ } else {
+ astClearFormat( this, 0 );
+ }
+
+/* Free the memory holding the copy of the format string. */
+ fmt = astFree( (char *) fmt );
+
+/* If the time of day is "00:00:00", remove it. */
+ if( !strcmp( getlabel_buff + strlen( getlabel_buff ) - 8, "00:00:00" ) ) {
+ getlabel_buff[ strlen( getlabel_buff ) - 8 ] = 0;
+ }
+ }
+
+/* Modify this default to take account of the current value of the Unit
+ attribute, if set. */
+ if( astTestUnit( this, axis ) ) {
+
+/* Find a Mapping from the default Units for the current System, to the
+ units indicated by the Unit attribute. This Mapping is used to modify
+ the existing default label appropriately. For instance, if the default
+ units is "yr" and the actual units is "log(yr)", then the default label
+ of "Julian epoch" is changed to "log( Julian epoch )". */
+ map = astUnitMapper( DefUnit( system, "astGetLabel",
+ astGetClass( this ), status ),
+ astGetUnit( this, axis ), result,
+ &new_lab );
+ if( new_lab ) {
+ result = strcpy( getlabel_buff, new_lab );
+ new_lab = astFree( new_lab );
+ }
+
+/* Annul the unused Mapping. */
+ if( map ) map = astAnnul( map );
+ }
+ }
+ }
+
+/* If the time is a Local Time, indicate the offset from UTC. */
+ if( astGetTimeScale( this ) == AST__LT ) {
+ ltoff = astGetLTOffset( this );
+ if( ltoff >= 0.0 ) {
+ sprintf( getlabel_buff, "%s (UTC+%g)", result, ltoff );
+ } else {
+ sprintf( getlabel_buff, "%s (UTC-%g)", result, -ltoff );
+ }
+ result = getlabel_buff;
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *GetSymbol( AstFrame *this, int axis, int *status ) {
+/*
+* Name:
+* GetSymbol
+
+* Purpose:
+* Obtain a pointer to the Symbol string for a TimeFrame axis.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *GetSymbol( AstFrame *this, int axis, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetSymbol method inherited
+* from the Frame class).
+
+* Description:
+* This function returns a pointer to the Symbol string for a specified axis
+* of a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* axis
+* Axis index (zero-based) identifying the axis for which information is
+* required.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to a constant null-terminated character string containing the
+* requested information.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstMapping *map; /* Mapping between units */
+ AstSystemType system; /* Code identifying type of sky coordinates */
+ char *new_sym; /* Modified symbol string */
+ const char *result; /* Pointer to symbol string */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* Initialise. */
+ result = NULL;
+
+/* Validate the axis index. */
+ astValidateAxis( this, axis, 1, "astGetSymbol" );
+
+/* Check if a value has been set for the required axis symbol string. If so,
+ invoke the parent astGetSymbol method to obtain a pointer to it. */
+ if ( astTestSymbol( this, axis ) ) {
+ result = (*parent_getsymbol)( this, axis, status );
+
+/* Otherwise, identify the sky coordinate system described by the TimeFrame. */
+ } else {
+ system = astGetSystem( this );
+
+/* If OK, supply a pointer to a suitable default Symbol string. */
+ if ( astOK ) {
+
+ if( system == AST__MJD ) {
+ result = "MJD";
+ } else if( system == AST__JD ) {
+ result = "JD";
+ } else if( system == AST__BEPOCH ) {
+ result = "BEP";
+ } else if( system == AST__JEPOCH ) {
+ result = "JEP";
+
+/* Report an error if the coordinate system was not recognised. */
+ } else {
+ astError( AST__SCSIN, "astGetSymbol(%s): Corrupt %s contains "
+ "invalid System identification code (%d).", status,
+ astGetClass( this ), astGetClass( this ), (int) system );
+ }
+
+/* Modify this default to take account of the current value of the Unit
+ attribute, if set. */
+ if( astTestUnit( this, axis ) ) {
+
+/* Find a Mapping from the default Units for the current System, to the
+ units indicated by the Unit attribute. This Mapping is used to modify
+ the existing default symbol appropriately. For instance, if the default
+ units is "yr" and the actual units is "log(yr)", then the default symbol
+ of "JEP" is changed to "log( JEP )". */
+ map = astUnitMapper( DefUnit( system, "astGetSymbol",
+ astGetClass( this ), status ),
+ astGetUnit( this, axis ), result,
+ &new_sym );
+ if( new_sym ) {
+ result = strcpy( getsymbol_buff, new_sym );
+ new_sym = astFree( new_sym );
+ }
+
+/* Annul the unused Mapping. */
+ if( map ) map = astAnnul( map );
+
+ }
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* GetAlignSystem
+
+* Purpose:
+* Obtain the AlignSystem attribute for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "Specframe.h"
+* AstSystemType GetAlignSystem( AstFrame *this_frame, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetAlignSystem protected
+* method inherited from the Frame class).
+
+* Description:
+* This function returns the AlignSystem attribute for a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The AlignSystem value.
+
+*/
+
+/* Local Variables: */
+ AstTimeFrame *this; /* Pointer to TimeFrame structure */
+ AstSystemType result; /* Value to return */
+
+/* Initialise. */
+ result = AST__BADSYSTEM;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* If a AlignSystem attribute has been set, invoke the parent method to obtain
+ it. */
+ if ( astTestAlignSystem( this ) ) {
+ result = (*parent_getalignsystem)( this_frame, status );
+
+/* Otherwise, provide a suitable default. */
+ } else {
+ result = AST__MJD;
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static AstTimeScaleType GetAlignTimeScale( AstTimeFrame *this, int *status ) {
+/*
+*+
+* Name:
+* astGetAlignTimeScale
+
+* Purpose:
+* Obtain the AlignTimeScale attribute for a TimeFrame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstTimeScaleType GetAlignTimeScale( AstTimeFrame *this )
+
+* Class Membership:
+* TimeFrame virtual function
+
+* Description:
+* This function returns the System attribute for a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+
+* Returned Value:
+* The System value.
+
+* Notes:
+* - AST__BADTS is returned if this function is invoked with
+* the global error status set or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstTimeScaleType result;
+ AstTimeScaleType ts;
+
+/* Initialise. */
+ result = AST__BADTS;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* If a value has been set, return it. */
+ if( this->aligntimescale != AST__BADTS ) {
+ result = this->aligntimescale;
+
+/* Otherwise, return a default depending on the current TimeScale value */
+ } else {
+ ts = astGetTimeScale( this );
+ if ( ts == AST__UT1 || ts == AST__LAST || ts == AST__LMST || ts == AST__GMST ) {
+ result = AST__UT1;
+ } else {
+ result = AST__TAI;
+ }
+
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static AstSystemType GetSystem( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* GetSystem
+
+* Purpose:
+* Obtain the System attribute for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstSystemType GetSystem( AstFrame *this_frame, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetSystem protected
+* method inherited from the Frame class).
+
+* Description:
+* This function returns the System attribute for a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The System value.
+
+* Notes:
+* - AST__BADSYSTEM is returned if this function is invoked with
+* the global error status set or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstTimeFrame *this; /* Pointer to TimeFrame structure */
+ AstSystemType result; /* Value to return */
+
+/* Initialise. */
+ result = AST__BADSYSTEM;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* If a System attribute has been set, invoke the parent method to obtain
+ it. */
+ if ( astTestSystem( this ) ) {
+ result = (*parent_getsystem)( this_frame, status );
+
+/* Otherwise, provide a suitable default. */
+ } else {
+ result = AST__MJD;
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static AstTimeScaleType GetTimeScale( AstTimeFrame *this, int *status ) {
+/*
+*+
+* Name:
+* astGetTimeScale
+
+* Purpose:
+* Obtain the TimeScale attribute for a TimeFrame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstTimeScaleType GetTimeScale( AstTimeFrame *this )
+
+* Class Membership:
+* TimeFrame virtual function
+
+* Description:
+* This function returns the System attribute for a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+
+* Returned Value:
+* The System value.
+
+* Notes:
+* - AST__BADTS is returned if this function is invoked with
+* the global error status set or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstTimeScaleType result;
+
+/* Initialise. */
+ result = AST__BADTS;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* If a value has been set, return it. */
+ if( this->timescale != AST__BADTS ) {
+ result = this->timescale;
+
+/* Otherwise, return a default depending on the current System value. */
+ } else {
+ if ( astGetSystem( this ) == AST__BEPOCH ) {
+ result = AST__TT;
+ } else {
+ result = AST__TAI;
+ }
+
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *GetTitle( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* GetTitle
+
+* Purpose:
+* Obtain a pointer to the Title string for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *GetTitle( AstFrame *this_frame, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetTitle method inherited
+* from the Frame class).
+
+* Description:
+* This function returns a pointer to the Title string for a TimeFrame.
+* A pointer to a suitable default string is returned if no Title value has
+* previously been set.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to a null-terminated character string containing the requested
+* information.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstSystemType system; /* Code identifying type of coordinates */
+ AstTimeScaleType ts; /* Time scale value */
+ AstTimeFrame *this; /* Pointer to TimeFrame structure */
+ const char *fmt; /* Pointer to original Format string */
+ const char *result; /* Pointer to result string */
+ double ltoff; /* Local Time offset from UTC (hours) */
+ double orig; /* Time origin (seconds) */
+ int fmtSet; /* Was Format attribute set? */
+ int nc; /* No. of characters added */
+ int ndp; /* Number of decimal places */
+ int pos; /* Buffer position to enter text */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_frame);
+
+/* Initialise. */
+ result = NULL;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* See if a Title string has been set. If so, use the parent astGetTitle
+ method to obtain a pointer to it. */
+ if ( astTestTitle( this ) ) {
+ result = (*parent_gettitle)( this_frame, status );
+
+/* Otherwise, we will generate a default Title string. Obtain the values of the
+ TimeFrame's attributes that determine what this string will be. */
+ } else {
+ system = astGetSystem( this );
+ orig = GetTimeOriginCur( this, status );
+ ts = astGetTimeScale( this );
+ if ( astOK ) {
+ result = gettitle_buff;
+
+/* Begin with the system's default label. */
+ pos = sprintf( gettitle_buff, "%s", SystemLabel( system, status ) );
+ gettitle_buff[ 0 ] = toupper( gettitle_buff[ 0 ] );
+
+/* Append the time scale code, if a value has been set for the timescale.
+ Do not do this if the system is BEPOCH since BEPOCH can only be used
+ with the TT timescale. */
+ if( system != AST__BEPOCH && astTestTimeScale( this ) ) {
+ nc = sprintf( gettitle_buff + pos, " [%s", TimeScaleString( ts, status ) );
+ pos += nc;
+
+/* For Local Time, include the offset from UTC. */
+ if( ts == AST__LT ) {
+ ltoff = astGetLTOffset( this );
+ if( ltoff >= 0.0 ) {
+ nc = sprintf( gettitle_buff + pos, " (UTC+%g)", ltoff );
+ } else {
+ nc = sprintf( gettitle_buff + pos, " (UTC-%g)", -ltoff );
+ }
+ pos += nc;
+ }
+
+/* Close the brackets. */
+ nc = sprintf( gettitle_buff + pos, "]" );
+ pos += nc;
+ }
+
+/* If a non-zero offset has been specified, and the Format attribute does
+ not indicate a date string (which is always absolute), include the
+ offset now as a date/time string. */
+ fmt = astGetFormat( this, 0 );
+ if( orig != 0.0 && !DateFormat( fmt, &ndp, NULL, status ) ) {
+
+/* Save the Format attribute, and then temporarily set it to give a date/time
+ string. */
+ fmt = astStore( NULL, fmt, strlen( fmt ) + 1 );
+ fmtSet = astTestFormat( this, 0 );
+ astSetFormat( this, 0, "iso.0" );
+
+/* Format the origin value as an absolute time and append it to the
+ returned title string. Note, the origin always corresponds to a
+ TimeFrame axis value of zero. */
+ nc = sprintf( gettitle_buff+pos, " offset from %s",
+ astFormat( this, 0, 0.0 ) );
+ pos += nc;
+
+/* Re-instate the original Format value. */
+ if( fmtSet ) {
+ astSetFormat( this, 0, fmt );
+ } else {
+ astClearFormat( this, 0 );
+ }
+
+/* Free the Format string copy. */
+ fmt = astFree( (char *) fmt );
+
+ }
+ }
+ }
+
+/* If an error occurred, clear the returned pointer value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+static const char *GetUnit( AstFrame *this_frame, int axis, int *status ) {
+/*
+* Name:
+* GetUnit
+
+* Purpose:
+* Obtain a pointer to the Unit string for a TimeFrame's axis.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *GetUnit( AstFrame *this_frame, int axis )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astGetUnit method inherited
+* from the Frame class).
+
+* Description:
+* This function returns a pointer to the Unit string for a specified axis
+* of a TimeFrame. If the Unit attribute has not been set for the axis, a
+* pointer to a suitable default string is returned instead.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* axis
+* The number of the axis (zero-based) for which information is required.
+
+* Returned Value:
+* A pointer to a null-terminated string containing the Unit value.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstTimeFrame *this; /* Pointer to the TimeFrame structure */
+ AstSystemType system; /* The TimeFrame's System value */
+ const char *result; /* Pointer value to return */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* Validate the axis index. */
+ astValidateAxis( this, axis, 1, "astGetUnit" );
+
+/* If a value has been set for the Unit attribute, use the parent
+ GetUnit method to return a pointer to the required Unit string. */
+ if( astTestUnit( this, axis ) ){
+ result = (*parent_getunit)( this_frame, axis, status );
+
+/* Otherwise, identify the time coordinate system described by the
+ TimeFrame. */
+ } else {
+ system = astGetSystem( this );
+
+/* Return a string describing the default units. */
+ result = DefUnit( system, "astGetUnit", astGetClass( this ), status );
+ }
+
+/* If an error occurred, clear the returned value. */
+ if ( !astOK ) result = NULL;
+
+/* Return the result. */
+ return result;
+}
+
+void astInitTimeFrameVtab_( AstTimeFrameVtab *vtab, const char *name, int *status ) {
+/*
+*+
+* Name:
+* astInitTimeFrameVtab
+
+* Purpose:
+* Initialise a virtual function table for a TimeFrame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void astInitTimeFrameVtab( AstTimeFrameVtab *vtab, const char *name )
+
+* Class Membership:
+* TimeFrame vtab initialiser.
+
+* Description:
+* This function initialises the component of a virtual function
+* table which is used by the TimeFrame class.
+
+* Parameters:
+* vtab
+* Pointer to the virtual function table. The components used by
+* all ancestral classes will be initialised if they have not already
+* been initialised.
+* name
+* Pointer to a constant null-terminated character string which contains
+* the name of the class to which the virtual function table belongs (it
+* is this pointer value that will subsequently be returned by the Object
+* astClass function).
+*-
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstFrameVtab *frame; /* Pointer to Frame component of Vtab */
+ AstMapping *map; /* Temporary Maping */
+ AstObjectVtab *object; /* Pointer to Object component of Vtab */
+ double utc_epoch; /* Unix epoch as a UTC MJD */
+
+/* Check the local error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Initialize the component of the virtual function table used by the
+ parent class. */
+ astInitFrameVtab( (AstFrameVtab *) vtab, name );
+
+/* Store a unique "magic" value in the virtual function table. This
+ will be used (by astIsATimeFrame) to determine if an object belongs
+ to this class. We can conveniently use the address of the (static)
+ class_check variable to generate this unique value. */
+ vtab->id.check = &class_check;
+ vtab->id.parent = &(((AstFrameVtab *) vtab)->id);
+
+/* Initialise member function pointers. */
+/* ------------------------------------ */
+/* Store pointers to the member functions (implemented here) that
+ provide virtual methods for this class. */
+
+ vtab->ClearAlignTimeScale = ClearAlignTimeScale;
+ vtab->TestAlignTimeScale = TestAlignTimeScale;
+ vtab->GetAlignTimeScale = GetAlignTimeScale;
+ vtab->SetAlignTimeScale = SetAlignTimeScale;
+
+ vtab->ClearTimeOrigin = ClearTimeOrigin;
+ vtab->TestTimeOrigin = TestTimeOrigin;
+ vtab->GetTimeOrigin = GetTimeOrigin;
+ vtab->SetTimeOrigin = SetTimeOrigin;
+
+ vtab->ClearLTOffset = ClearLTOffset;
+ vtab->TestLTOffset = TestLTOffset;
+ vtab->GetLTOffset = GetLTOffset;
+ vtab->SetLTOffset = SetLTOffset;
+
+ vtab->ClearTimeScale = ClearTimeScale;
+ vtab->TestTimeScale = TestTimeScale;
+ vtab->GetTimeScale = GetTimeScale;
+ vtab->SetTimeScale = SetTimeScale;
+
+ vtab->CurrentTime = CurrentTime;
+
+/* Save the inherited pointers to methods that will be extended, and
+ replace them with pointers to the new member functions. */
+ object = (AstObjectVtab *) vtab;
+ frame = (AstFrameVtab *) vtab;
+
+ parent_clearattrib = object->ClearAttrib;
+ object->ClearAttrib = ClearAttrib;
+ parent_getattrib = object->GetAttrib;
+ object->GetAttrib = GetAttrib;
+ parent_setattrib = object->SetAttrib;
+ object->SetAttrib = SetAttrib;
+ parent_testattrib = object->TestAttrib;
+ object->TestAttrib = TestAttrib;
+
+ parent_getdomain = frame->GetDomain;
+ frame->GetDomain = GetDomain;
+
+ parent_getsystem = frame->GetSystem;
+ frame->GetSystem = GetSystem;
+ parent_setsystem = frame->SetSystem;
+ frame->SetSystem = SetSystem;
+ parent_clearsystem = frame->ClearSystem;
+ frame->ClearSystem = ClearSystem;
+
+ parent_getalignsystem = frame->GetAlignSystem;
+ frame->GetAlignSystem = GetAlignSystem;
+
+ parent_getlabel = frame->GetLabel;
+ frame->GetLabel = GetLabel;
+
+ parent_getsymbol = frame->GetSymbol;
+ frame->GetSymbol = GetSymbol;
+
+ parent_gettitle = frame->GetTitle;
+ frame->GetTitle = GetTitle;
+
+ parent_getepoch = frame->GetEpoch;
+ frame->GetEpoch = GetEpoch;
+
+ parent_getunit = frame->GetUnit;
+ frame->GetUnit = GetUnit;
+
+ parent_setunit = frame->SetUnit;
+ frame->SetUnit = SetUnit;
+
+ parent_match = frame->Match;
+ frame->Match = Match;
+
+ parent_overlay = frame->Overlay;
+ frame->Overlay = Overlay;
+
+ parent_subframe = frame->SubFrame;
+ frame->SubFrame = SubFrame;
+
+ parent_format = frame->Format;
+ frame->Format = Format;
+
+ parent_unformat = frame->Unformat;
+ frame->Unformat = Unformat;
+
+ parent_abbrev = frame->Abbrev;
+ frame->Abbrev = Abbrev;
+
+ parent_fields = frame->Fields;
+ frame->Fields = Fields;
+
+ parent_gap = frame->Gap;
+ frame->Gap = Gap;
+
+ parent_centre = frame->Centre;
+ frame->Centre = Centre;
+
+/* Store replacement pointers for methods which will be over-ridden by new
+ member functions implemented here. */
+ frame->GetActiveUnit = GetActiveUnit;
+ frame->TestActiveUnit = TestActiveUnit;
+ frame->ValidateSystem = ValidateSystem;
+ frame->SystemString = SystemString;
+ frame->SystemCode = SystemCode;
+
+/* Declare the copy constructor, destructor and class dump
+ function. */
+ astSetDump( vtab, Dump, "TimeFrame",
+ "Description of time coordinate system" );
+
+/* Convert the Unix Epoch (00:00:00 UTC 1 January 1970 AD) from UTC to TAI. */
+ LOCK_MUTEX2
+ map = MakeMap( NULL, AST__MJD, AST__MJD, AST__UTC, AST__TAI,
+ 0.0, 0.0, "d", "d", "astInitTimeFrameVtab", status );
+ utc_epoch = UNIX_EPOCH;
+ astTran1( map, 1, &utc_epoch, 1, &tai_epoch );
+ map = astAnnul( map );
+ UNLOCK_MUTEX2
+
+/* If we have just initialised the vtab for the current class, indicate
+ that the vtab is now initialised, and store a pointer to the class
+ identifier in the base "object" level of the vtab. */
+ if( vtab == &class_vtab ) {
+ class_init = 1;
+ astSetVtabClassIdentifier( vtab, &(vtab->id) );
+ }
+}
+
+static AstMapping *MakeMap( AstTimeFrame *this, AstSystemType sys1,
+ AstSystemType sys2, AstTimeScaleType ts1,
+ AstTimeScaleType ts2, double off1, double off2,
+ const char *unit1, const char *unit2,
+ const char *method, int *status ){
+/*
+* Name:
+* MakeMap
+
+* Purpose:
+* Make a Mapping between stated timescales and systems.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstMapping *MakeMap( AstTimeFrame *this, AstSystemType sys1,
+* AstSystemType sys2, AstTimeScaleType ts1,
+* AstTimeScaleType ts2, double off1, double off2,
+* const char *unit1, const char unit2,
+* const char *method, int *status )
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function creates a Mapping from a stated pair of System and
+* TimeScale to another stated pair.
+
+* Parameters:
+* this
+* A TimeFrame which specifies extra attributes (the clock position,
+* time zone, etc) for both input and output.
+* sys1
+* The input System.
+* sys2
+* The output System.
+* ts1
+* The input System.
+* ts2
+* The output System.
+* off1
+* The axis offset used with the input, in the defaults units
+* associated with "sys1".
+* off2
+* The axis offset used with the output, in the defaults units
+* associated with "sys2".
+* unit1
+* The input units.
+* unit2
+* The output units.
+* method
+* A string containing the method name to include in error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to the new Mapping. NULL if the timescales were
+* incompatible.
+
+*/
+
+
+/* Local Variables: */
+ AstMapping *result;
+ AstMapping *tmap;
+ AstMapping *tmap2;
+ AstMapping *umap;
+ AstMapping *umap1;
+ AstMapping *umap2;
+ AstTimeMap *timemap;
+ const char *du;
+ double args[ 5 ];
+ double args_lt[ 1 ];
+ double args_ut[ 1 ];
+ double args_tai[ 2 ];
+ double shift;
+
+/* Check the global error status. */
+ result = NULL;
+ if ( !astOK ) return result;
+
+/* If the timescales are equal... */
+ if( ts1 == ts2 ) {
+
+/* and the time systems are equal... */
+ if( sys1 == sys2 ) {
+
+/* and the time offsets are equal... */
+ if( astEQUALS( off1, off2, 1.0E3 ) ) {
+
+/* and the units are equal, return a UnitMap. */
+ if( !strcmp( unit1, unit2 ) ) {
+ result = (AstMapping *) astUnitMap( 1, "", status );
+
+/* If only the units differ, return the appropriate units Mapping. */
+ } else {
+ result = astUnitMapper( unit1, unit2, NULL, NULL );
+ }
+
+/* If the time offsets differ... */
+ } else {
+
+/* Transform the difference in offsets from the default units associated
+ with the (common) system, to the units associated with the output. */
+ shift = off1 - off2;
+ du = DefUnit( sys1, method, "TimeFrame", status );
+ if( du && strcmp( du, unit2 ) && shift != 0.0 ) {
+ umap = astUnitMapper( DefUnit( sys1, method, "TimeFrame", status ),
+ unit2, NULL, NULL );
+ astTran1( umap, 1, &shift, 1, &shift );
+ umap = astAnnul( umap );
+ }
+
+/* Create a ShiftMap to apply the shift. */
+ result = (AstMapping *) astShiftMap( 1, &shift, "", status );
+
+/* If the input and output units also differ, include the appropriate units
+ Mapping. */
+ if( strcmp( unit1, unit2 ) ) {
+ umap = astUnitMapper( unit1, unit2, NULL, NULL );
+ tmap = (AstMapping *) astCmpMap( umap, result, 1, "", status );
+ umap = astAnnul( umap );
+ (void) astAnnul( result );
+ result = tmap;
+ }
+ }
+ }
+ }
+
+/* If the systems and/or timescales differ, we convert first from the
+ input frame to a common frame, then from the common frame to the output
+ frame. */
+ if( !result ) {
+
+/* First, a Mapping from the input units to the default units for the
+ input System (these are the units expected by the TimeMap conversions). */
+ umap1 = astUnitMapper( unit1, DefUnit( sys1, method, "TimeFrame", status ),
+ NULL, NULL );
+
+/* Now create a null TimeMap. */
+ timemap = astTimeMap( 0, "", status );
+
+/* Store the input time offsets to use. They correspond to the same moment in
+ time (the second is the MJD equivalent of the first). */
+ args[ 0 ] = off1;
+ args[ 1 ] = ToMJD( sys1, off1, status );
+
+/* Add a conversion from the input System to MJD. */
+ if( sys1 == AST__JD ) {
+ astTimeAdd( timemap, "JDTOMJD", 2, args );
+
+ } else if( sys1 == AST__JEPOCH ) {
+ astTimeAdd( timemap, "JEPTOMJD", 2, args );
+
+ } else if( sys1 == AST__BEPOCH ) {
+ astTimeAdd( timemap, "BEPTOMJD", 2, args );
+ }
+
+/* All timescale conversions except UTTOUTC and UTCTOUT require the input (MJD)
+ offset as the first argument. In general, the observers longitude, latitude
+ and altitude are also needed. The Frame class stores longitude values in a
+ +ve eastwards sense, but the TimeMap class needs +ve westwards, so negate
+ the longitude. */
+ args[ 0 ] = args[ 1 ];
+ args[ 1 ] = this ? -astGetObsLon( this ) : 0.0;
+ args[ 2 ] = this ? astGetObsLat( this ) : 0.0;
+ args[ 3 ] = this ? astGetObsAlt( this ) : 0.0;
+
+/* Currently the only conversion that take 5 arguments require the DTAI
+ value as the 5th argument. */
+ args[ 4 ] = this ? astGetDtai( this ) : AST__BAD;
+
+/* The UTTOUTC and UTCTOUT conversions required just the DUT1 value. */
+ args_ut[ 0 ] = this ? astGetDut1( this ) : 0.0;
+
+/* The LTTOUTC and UTCTOLT conversions required just the time zone
+ correction. */
+ args_lt[ 0 ] = this ? astGetLTOffset( this ) : 0.0;
+
+/* The UTCTOTAI and TAITOUTC conversions require the input offset and DTAI. */
+ args_tai[ 0 ] = args[ 0 ];
+ args_tai[ 1 ] = this ? astGetDtai( this ) : AST__BAD;
+
+/* If the input and output timescales differ, now add a conversion from the
+ input timescale to TAI. */
+ if( ts1 != ts2 ) {
+ if( ts1 == AST__TAI ) {
+
+ } else if( ts1 == AST__UTC ) {
+ astTimeAdd( timemap, "UTCTOTAI", 2, args_tai );
+
+ } else if( ts1 == AST__TT ) {
+ astTimeAdd( timemap, "TTTOTAI", 1, args );
+
+ } else if( ts1 == AST__TDB ) {
+ astTimeAdd( timemap, "TDBTOTT", 5, args );
+ astTimeAdd( timemap, "TTTOTAI", 1, args );
+
+ } else if( ts1 == AST__TCG ) {
+ astTimeAdd( timemap, "TCGTOTT", 1, args );
+ astTimeAdd( timemap, "TTTOTAI", 1, args );
+
+ } else if( ts1 == AST__LT ) {
+ astTimeAdd( timemap, "LTTOUTC", 1, args_lt );
+ astTimeAdd( timemap, "UTCTOTAI", 2, args_tai );
+
+ } else if( ts1 == AST__TCB ) {
+ astTimeAdd( timemap, "TCBTOTDB", 1, args );
+ astTimeAdd( timemap, "TDBTOTT", 5, args );
+ astTimeAdd( timemap, "TTTOTAI", 1, args );
+
+ } else if( ts1 == AST__UT1 ) {
+ astTimeAdd( timemap, "UTTOUTC", 1, args_ut );
+ astTimeAdd( timemap, "UTCTOTAI", 2, args_tai );
+
+ } else if( ts1 == AST__GMST ) {
+ astTimeAdd( timemap, "GMSTTOUT", 1, args );
+ astTimeAdd( timemap, "UTTOUTC", 1, args_ut );
+ astTimeAdd( timemap, "UTCTOTAI", 2, args_tai );
+
+ } else if( ts1 == AST__LAST ) {
+ astTimeAdd( timemap, "LASTTOLMST", 3, args );
+ astTimeAdd( timemap, "LMSTTOGMST", 3, args );
+ astTimeAdd( timemap, "GMSTTOUT", 1, args );
+ astTimeAdd( timemap, "UTTOUTC", 1, args_ut );
+ astTimeAdd( timemap, "UTCTOTAI", 2, args_tai );
+
+ } else if( ts1 == AST__LMST ) {
+ astTimeAdd( timemap, "LMSTTOGMST", 3, args );
+ astTimeAdd( timemap, "GMSTTOUT", 1, args );
+ astTimeAdd( timemap, "UTTOUTC", 1, args_ut );
+ astTimeAdd( timemap, "UTCTOTAI", 2, args_tai );
+ }
+
+/* Now add a conversion from TAI to the output timescale. */
+ if( ts2 == AST__TAI ) {
+
+ } else if( ts2 == AST__UTC ) {
+ astTimeAdd( timemap, "TAITOUTC", 2, args_tai );
+
+ } else if( ts2 == AST__TT ) {
+ astTimeAdd( timemap, "TAITOTT", 1, args );
+
+ } else if( ts2 == AST__TDB ) {
+ astTimeAdd( timemap, "TAITOTT", 1, args );
+ astTimeAdd( timemap, "TTTOTDB", 5, args );
+
+ } else if( ts2 == AST__TCG ) {
+ astTimeAdd( timemap, "TAITOTT", 1, args );
+ astTimeAdd( timemap, "TTTOTCG", 1, args );
+
+ } else if( ts2 == AST__TCB ) {
+ astTimeAdd( timemap, "TAITOTT", 1, args );
+ astTimeAdd( timemap, "TTTOTDB", 5, args );
+ astTimeAdd( timemap, "TDBTOTCB", 1, args );
+
+ } else if( ts2 == AST__UT1 ) {
+ astTimeAdd( timemap, "TAITOUTC", 2, args_tai );
+ astTimeAdd( timemap, "UTCTOUT", 1, args_ut );
+
+ } else if( ts2 == AST__GMST ) {
+ astTimeAdd( timemap, "TAITOUTC", 2, args_tai );
+ astTimeAdd( timemap, "UTCTOUT", 1, args_ut );
+ astTimeAdd( timemap, "UTTOGMST", 1, args );
+
+ } else if( ts2 == AST__LAST ) {
+ astTimeAdd( timemap, "TAITOUTC", 2, args_tai );
+ astTimeAdd( timemap, "UTCTOUT", 1, args_ut );
+ astTimeAdd( timemap, "UTTOGMST", 1, args );
+ astTimeAdd( timemap, "GMSTTOLMST", 3, args );
+ astTimeAdd( timemap, "LMSTTOLAST", 3, args );
+
+ } else if( ts2 == AST__LMST ) {
+ astTimeAdd( timemap, "TAITOUTC", 2, args_tai );
+ astTimeAdd( timemap, "UTCTOUT", 1, args_ut );
+ astTimeAdd( timemap, "UTTOGMST", 1, args );
+ astTimeAdd( timemap, "GMSTTOLMST", 3, args );
+
+ } else if( ts2 == AST__LT ) {
+ astTimeAdd( timemap, "TAITOUTC", 2, args_tai );
+ astTimeAdd( timemap, "UTCTOLT", 1, args_lt );
+
+ }
+ }
+
+/* Add a conversion from MJD to the output System, if needed. */
+ args[ 1 ] = off2;
+ if( sys2 == AST__MJD ) {
+ if( args[ 0 ] != off2 ) astTimeAdd( timemap, "MJDTOMJD", 2, args );
+
+ } else if( sys2 == AST__JD ) {
+ astTimeAdd( timemap, "MJDTOJD", 2, args );
+
+ } else if( sys2 == AST__JEPOCH ) {
+ astTimeAdd( timemap, "MJDTOJEP", 2, args );
+
+ } else if( sys2 == AST__BEPOCH ) {
+ astTimeAdd( timemap, "MJDTOBEP", 2, args );
+ }
+
+/* Now, create a Mapping from the default units for the output System (these
+ are the units produced by the TimeMap conversions) to the requested
+ output units. */
+ umap2 = astUnitMapper( DefUnit( sys2, method, "TimeFrame", status ), unit2,
+ NULL, NULL );
+
+/* If OK, combine the Mappings in series. Note, umap1 and umap2 should
+ always be non-NULL because the suitablity of units strings is checked
+ within OriginSystem - called from within SetSystem. */
+ if( umap1 && umap2 ) {
+ tmap = (AstMapping *) astCmpMap( umap1, timemap, 1, "", status );
+ tmap2 = (AstMapping *) astCmpMap( tmap, umap2, 1, "", status );
+ tmap = astAnnul( tmap );
+ result = astSimplify( tmap2 );
+ tmap2 = astAnnul( tmap2 );
+ }
+
+/* Free remaining resources */
+ if( umap1 ) umap1 = astAnnul( umap1 );
+ if( umap2 ) umap2 = astAnnul( umap2 );
+ timemap = astAnnul( timemap );
+ }
+
+/* Return NULL if an error has occurred. */
+ if( !astOK ) result = astAnnul( result );
+
+/* Return the result. */
+ return result;
+
+}
+
+static int MakeTimeMapping( AstTimeFrame *target, AstTimeFrame *result,
+ AstTimeFrame *align_frm, int report,
+ AstMapping **map, int *status ) {
+/*
+* Name:
+* MakeTimeMapping
+
+* Purpose:
+* Generate a Mapping between two TimeFrames.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int MakeTimeMapping( AstTimeFrame *target, AstTimeFrame *result,
+* AstTimeFrame *align_frm, int report,
+* AstMapping **map, int *status ) {
+
+* Class Membership:
+* TimeFrame member function.
+
+* Description:
+* This function takes two TimeFrames and generates a Mapping that
+* converts between them, taking account of differences in their
+* coordinate systems, offsets, timescales, units, etc.
+
+* Parameters:
+* target
+* Pointer to the first TimeFrame.
+* result
+* Pointer to the second TimeFrame.
+* align_frm
+* A TimeFrame defining the system and time scale in which to
+* align the target and result TimeFrames. The AlignSystem and
+* AlignTimeScale attributes are used for this purpose.
+* report
+* Should errors be reported if no match is possible? These reports
+* will describe why no match was possible.
+* map
+* Pointer to a location which is to receive a pointer to the
+* returned Mapping. The forward transformation of this Mapping
+* will convert from "target" coordinates to "result"
+* coordinates, and the inverse transformation will convert in
+* the opposite direction (all coordinate values in radians).
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Non-zero if the Mapping could be generated, or zero if the two
+* TimeFrames are sufficiently un-related that no meaningful Mapping
+* can be produced (albeit an "unmeaningful" Mapping will be returned
+* in this case, which will need to be annulled).
+
+* Notes:
+* A value of zero is returned if this function is invoked with the
+* global error status set or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstMapping *map1; /* Intermediate Mapping */
+ AstMapping *map2; /* Intermediate Mapping */
+ AstMapping *tmap; /* Intermediate Mapping */
+ AstSystemType sys1; /* Code to identify input system */
+ AstSystemType sys2; /* Code to identify output system */
+ AstTimeScaleType align_ts; /* Alignment time scale */
+ AstTimeScaleType ts1; /* Input time scale */
+ AstTimeScaleType ts2; /* Output time scale */
+ const char *align_unit; /* Units used for alignment */
+ const char *u1; /* Input target units */
+ const char *u2; /* Output target units */
+ double align_off; /* Axis offset */
+ double ltoff1; /* Input axis Local Time offset */
+ double ltoff2; /* Output axis Local Time offset */
+ double off1; /* Input axis offset */
+ double off2; /* Output axis offset */
+ int arclk; /* Align->result depends on clock position? */
+ int ardtai; /* Align->result depends on Dtai? */
+ int ardut; /* Align->result depends on Dut1? */
+ int arlto; /* Align->result depends on LT offset? */
+ int clkdiff; /* Do target and result clock positions differ? */
+ int dtaidiff; /* Do target and result Dtai values differ? */
+ int dut1diff; /* Do target and result Dut1 values differ? */
+ int ltodiff; /* Do target and result LTOffset values differ? */
+ int match; /* Mapping can be generated? */
+ int taclk; /* Target->align depends on clock position? */
+ int tadut; /* Target->align depends on Dut1? */
+ int tadtai; /* Target->align depends on Dtai? */
+ int talto; /* Target->align depends on LT offset? */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Initialise the returned values. */
+ match = 0;
+ *map = NULL;
+
+/* Get the required properties of the input (target) TimeFrame */
+ sys1 = astGetSystem( target );
+ ts1 = astGetTimeScale( target );
+ off1 = astGetTimeOrigin( target );
+ u1 = astGetUnit( target, 0 );
+ ltoff1= astGetLTOffset( target );
+
+/* Get the required properties of the output (result) TimeFrame */
+ sys2 = astGetSystem( result );
+ ts2 = astGetTimeScale( result );
+ off2 = astGetTimeOrigin( result );
+ u2 = astGetUnit( result, 0 );
+ ltoff2= astGetLTOffset( result );
+
+/* Get the timescale in which alignment is to be performed. The alignment
+ System does not matter since they all supported time systems are linearly
+ related, and so the choice of alignment System has no effect on the total
+ Mapping. We arbitrarily choose MJD as the alignment System (if needed). */
+ align_ts = astGetAlignTimeScale( align_frm );
+
+/* The main difference between this function and the MakeMap function is
+ that this function takes account of the requested alignment frame. But
+ the alignment Frame only makes a difference to the overall Mapping if
+ 1) the observer's positions are different in the target and result Frame,
+ and 2) one or both of the Mappings to or from the alignment frame depends
+ on the observer's position. If either of these 2 conditions is not met,
+ then the alignment frame can be ignored, and the simpler MakeMap function
+ can be called. See if the observer's positions differ. */
+ clkdiff = ( astGetObsLon( target ) != astGetObsLon( result ) ||
+ astGetObsLat( target ) != astGetObsLat( result ) ||
+ astGetObsAlt( target ) != astGetObsAlt( result ) );
+
+/* See if the Mapping from target to alignment frame depends on the
+ observer's position. */
+ taclk = CLOCK_SCALE( ts1 ) || CLOCK_SCALE( align_ts );
+
+/* See if the Mapping from alignment to result frame depends on the
+ observer's position. */
+ arclk = CLOCK_SCALE( align_ts ) || CLOCK_SCALE( ts2 );
+
+/* In addition, the alignment frame is significant if either of the Mappings
+ depends on DUT1 and the values of the DUT1 attribute are different for the
+ two TimeFrames. Or if DTAI differs and is similarly relevant. */
+ dut1diff = ( astGetDut1( target ) != astGetDut1( result ) );
+ tadut = DUT1_SCALE( ts1 ) != DUT1_SCALE( align_ts );
+ ardut = DUT1_SCALE( align_ts ) != DUT1_SCALE( ts2 );
+
+ dtaidiff = ! EQUAL( astGetDtai( target ), astGetDtai( result ), 1.0E-6 );
+ tadtai = DTAI_SCALE( ts1 ) != DTAI_SCALE( align_ts );
+ ardtai = DTAI_SCALE( align_ts ) != DTAI_SCALE( ts2 );
+
+/* In addition, the alignment frame is significant if either of the Mappings
+ depends on LTOffset and the values of the LTOffset attribute are different
+ for the two TimeFrames. */
+ ltodiff = ( ltoff1 != ltoff2 );
+ talto = LTOFFSET_SCALE( ts1 ) != LTOFFSET_SCALE( align_ts );
+ arlto = LTOFFSET_SCALE( align_ts ) != LTOFFSET_SCALE( ts2 );
+
+/* If the alignment frame can be ignored, use MakeMap */
+ if( ( !clkdiff || !( taclk || arclk ) ) &&
+ ( !ltodiff || !( talto || arlto ) ) &&
+ ( !dut1diff || !( tadut || ardut ) ) &&
+ ( !dtaidiff || !( tadtai || ardtai ) ) ) {
+ *map = MakeMap( target, sys1, sys2, ts1, ts2, off1, off2, u1, u2,
+ "astSubFrame", status );
+ if( *map ) match = 1;
+
+/* Otherwise, we create the Mapping in two parts; first a Mapping from
+ the target Frame to the alignment Frame (using the target clock, dtai, dut1
+ and ltoffset), then a Mapping from the alignment Frame to the results
+ Frame (using the result clock, dtai, dut1 and ltoffset). */
+ } else {
+
+/* Create a Mapping from target units/system/timescale/offset to MJD in
+ the alignment timescale with default units and offset equal to the MJD
+ equivalent of the target offset. */
+ align_off = ToMJD( sys1, off1, status );
+ align_unit = DefUnit( AST__MJD, "MakeTimeMap", "TimeFrame", status );
+ map1 = MakeMap( target, sys1, AST__MJD, ts1, align_ts, off1, align_off,
+ u1, align_unit, "MakeTimeMap", status );
+
+/* Report an error if the timescales were incompatible. */
+ if( !map1 ){
+ match = 0;
+ if( report && astOK ) {
+ astError( AST__INCTS, "astMatch(%s): Alignment in requested "
+ "timescale (%s) is not possible since one or both of the "
+ "TimeFrames being aligned refer to the %s timescale.", status,
+ astGetClass( target ), TimeScaleString( align_ts, status ),
+ TimeScaleString( ts1, status ) );
+ }
+ }
+
+/* We now create a Mapping that converts from the alignment System (MJD),
+ TimeScale and offset to the result coordinate system. */
+ map2 = MakeMap( result, AST__MJD, sys2, align_ts, ts2, align_off, off2,
+ align_unit, u2, "MakeTimeMap", status );
+
+/* Report an error if the timescales were incompatible. */
+ if( !map2 ){
+ match = 0;
+ if( report && astOK ) {
+ astError( AST__INCTS, "astMatch(%s): Alignment in requested "
+ "timescale (%s) is not possible since one or both of the "
+ "TimeFrames being aligned refer to the %s timescale.", status,
+ astGetClass( result ), TimeScaleString( align_ts, status ),
+ TimeScaleString( ts2, status ) );
+ }
+ }
+
+/* Combine these two Mappings. */
+ if( map1 && map2 ) {
+ match = 1;
+ tmap = (AstMapping *) astCmpMap( map1, map2, 1, "", status );
+ *map = astSimplify( tmap );
+ tmap = astAnnul( tmap );
+ }
+
+/* Free resources. */
+ if( map1 ) map1 = astAnnul( map1 );
+ if( map2 ) map2 = astAnnul( map2 );
+ }
+
+/* If an error occurred, annul the returned Mapping and clear the returned
+ values. */
+ if ( !astOK ) {
+ *map = astAnnul( *map );
+ match = 0;
+ }
+
+/* Return the result. */
+ return match;
+}
+
+static int Match( AstFrame *template_frame, AstFrame *target, int matchsub,
+ int **template_axes, int **target_axes, AstMapping **map,
+ AstFrame **result, int *status ) {
+/*
+* Name:
+* Match
+
+* Purpose:
+* Determine if conversion is possible between two coordinate systems.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int Match( AstFrame *template, AstFrame *target, int matchsub,
+* int **template_axes, int **target_axes,
+* AstMapping **map, AstFrame **result, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the protected astMatch method
+* inherited from the Frame class).
+
+* Description:
+* This function matches a "template" TimeFrame 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 TimeFrame. This describes the coordinate
+* system (or set of possible coordinate systems) into which we wish to
+* convert our coordinates.
+* target
+* Pointer to the target Frame. This describes the coordinate system in
+* which we already have coordinates.
+* matchsub
+* If zero then a match only occurs if the template is of the same
+* class as the target, or of a more specialised class. If non-zero
+* then a match can occur even if this is not the case.
+* template_axes
+* Address of a location where a pointer to int will be returned if the
+* requested coordinate conversion is possible. This pointer will point
+* at a dynamically allocated array of integers with one element for each
+* axis of the "result" Frame (see below). It must be freed by the caller
+* (using astFree) when no longer required.
+*
+* For each axis in the result Frame, the corresponding element of this
+* array will return the index of the template TimeFrame axis from
+* which it is derived. If it is not derived from any template
+* TimeFrame axis, a value of -1 will be returned instead.
+* target_axes
+* Address of a location where a pointer to int will be returned if the
+* requested coordinate conversion is possible. This pointer will point
+* at a dynamically allocated array of integers with one element for each
+* axis of the "result" Frame (see below). It must be freed by the caller
+* (using astFree) when no longer required.
+*
+* For each axis in the result Frame, the corresponding element of this
+* array will return the index of the target Frame axis from which it
+* is derived. If it is not derived from any target Frame axis, a value
+* of -1 will be returned instead.
+* map
+* Address of a location where a pointer to a new Mapping will be
+* returned if the requested coordinate conversion is possible. If
+* returned, the forward transformation of this Mapping may be used to
+* convert coordinates between the "target" Frame and the "result"
+* Frame (see below) and the inverse transformation will convert in the
+* opposite direction.
+* result
+* Address of a location where a pointer to a new Frame will be returned
+* if the requested coordinate conversion is possible. If returned, this
+* Frame describes the coordinate system that results from applying the
+* returned Mapping (above) to the "target" coordinate system. In
+* general, this Frame will combine attributes from (and will therefore
+* be more specific than) both the target and the template Frames. In
+* particular, when the template allows the possibility of transformaing
+* to any one of a set of alternative coordinate systems, the "result"
+* Frame will indicate which of the alternatives was used.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A non-zero value is returned if the requested coordinate conversion is
+* possible. Otherwise zero is returned (this will not in itself result in
+* an error condition).
+
+* Notes:
+* - A value of zero will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+
+* Implementation Notes:
+* This implementation addresses the matching of a TimeFrame class
+* object to any other class of Frame. A TimeFrame will match any class
+* of TimeFrame (i.e. possibly from a derived class) but will not match
+* a less specialised class of Frame.
+*/
+
+ AstFrame *frame0; /* Pointer to Frame underlying axis 0 */
+ AstTimeFrame *template; /* Pointer to template TimeFrame structure */
+ int iaxis0; /* Axis index underlying axis 0 */
+ int iaxis; /* Axis index */
+ int match; /* Coordinate conversion possible? */
+ int target_axis0; /* Index of TimeFrame axis in the target */
+ int target_naxes; /* Number of target axes */
+
+/* Initialise the returned values. */
+ *template_axes = NULL;
+ *target_axes = NULL;
+ *map = NULL;
+ *result = NULL;
+ match = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return match;
+
+/* Obtain a pointer to the template TimeFrame structure. */
+ template = (AstTimeFrame *) template_frame;
+
+/* Obtain the number of axes in the target Frame. */
+ target_naxes = astGetNaxes( target );
+
+/* The first criterion for a match is that the template matches as a
+ Frame class object. This ensures that the number of axes (1) and
+ domain, etc. of the target Frame are suitable. Invoke the parent
+ "astMatch" method to verify this. */
+ match = (*parent_match)( template_frame, target, matchsub,
+ template_axes, target_axes, map, result, status );
+
+/* If a match was found, annul the returned objects, which are not
+ needed, but keep the memory allocated for the axis association
+ arrays, which we will re-use. */
+ if ( astOK && match ) {
+ *map = astAnnul( *map );
+ *result = astAnnul( *result );
+ }
+
+/* If OK so far, obtain pointers to the primary Frames which underlie
+ all target axes. Stop when a TimeFrame axis is found. */
+ if ( match && astOK ) {
+ match = 0;
+ for( iaxis = 0; iaxis < target_naxes; iaxis++ ) {
+ astPrimaryFrame( target, iaxis, &frame0, &iaxis0 );
+ if( astIsATimeFrame( frame0 ) ) {
+ frame0 = astAnnul( frame0 );
+ target_axis0 = iaxis;
+ match = 1;
+ break;
+ } else {
+ frame0 = astAnnul( frame0 );
+ }
+ }
+ }
+
+/* Check at least one TimeFrame axis was found it the target. Store the
+ axis associataions. */
+ if( match && astOK ) {
+ (*template_axes)[ 0 ] = 0;
+ (*target_axes)[ 0 ] = target_axis0;
+
+/* Use the target's "astSubFrame" method to create a new Frame (the
+ result Frame) with copies of the target axes in the required
+ order. This process also overlays the template attributes on to the
+ target Frame and returns a Mapping between the target and result
+ Frames which effects the required coordinate conversion. */
+ match = astSubFrame( target, template, 1, *target_axes, *template_axes,
+ map, result );
+ }
+
+/* If an error occurred, or conversion to the result Frame's coordinate
+ system was not possible, then free all memory, annul the returned
+ objects, and reset the returned value. */
+ if ( !astOK || !match ) {
+ *template_axes = astFree( *template_axes );
+ *target_axes = astFree( *target_axes );
+ if( *map ) *map = astAnnul( *map );
+ if( *result ) *result = astAnnul( *result );
+ match = 0;
+ }
+
+/* Return the result. */
+ return match;
+}
+
+static void OriginScale( AstTimeFrame *this, AstTimeScaleType newts,
+ const char *method, int *status ){
+/*
+* Name:
+* OriginScale
+
+* Purpose:
+* Convert the TimeOrigin in a TimeFrame to a new timescale.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void OriginScale( AstTimeFrame *this, AstTimeScaleType newts,
+* const char *method, int *status )
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function converts the value of the TimeOrigin attribute stored
+* within a supplied TimeFrame from the timescale currently associated
+* with the TimeFrame, to the new timescale indicated by "newts".
+
+* Parameters:
+* this
+* Point to the TimeFrame. On entry, the TimeOrigin value is
+* assumed to refer to the timescale given by the astGetTimeScale
+* method. On exit, the TimeOrigin value refers to the timescale
+* supplied in "newts". The TimeScale attribute of the TimeFrame
+* should then be modified in order to keep things consistent.
+* newts
+* The timescale to which the TimeOrigin value stored within "this"
+* should refer on exit.
+* method
+* Pointer to a string holding the name of the method to be
+* included in any error messages.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+
+/* Local Variables: */
+ AstMapping *map;
+ AstSystemType sys;
+ AstTimeScaleType oldts;
+ const char *u;
+ double newval;
+ double oldval;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Do nothing if the TimeOrigin attribute has not been assigned a value. */
+ if( astTestTimeOrigin( this ) ) {
+
+/* Do nothing if the Scale will not change. */
+ oldts = astGetTimeScale( this );
+ if( newts != oldts ) {
+
+/* Create a Mapping to perform the TimeScale change. */
+ sys = astGetSystem( this );
+ u = DefUnit( sys, method, "TimeFrame", status ),
+ map = MakeMap( this, sys, sys, oldts, newts, 0.0, 0.0, u, u,
+ method, status );
+
+/* Use the Mapping to convert the stored TimeOrigin value. */
+ if( map ) {
+ oldval = astGetTimeOrigin( this );
+ astTran1( map, 1, &oldval, 1, &newval );
+
+/* Store the new value */
+ astSetTimeOrigin( this, newval );
+
+/* Free resources */
+ map = astAnnul( map );
+
+ } else if( astOK ) {
+ astError( AST__INCTS, "%s(%s): Cannot convert the TimeOrigin "
+ "value to a different timescale because of "
+ "incompatible time scales.", status, method,
+ astGetClass( this ) );
+ }
+ }
+ }
+}
+
+static void OriginSystem( AstTimeFrame *this, AstSystemType oldsys,
+ const char *method, int *status ){
+/*
+* Name:
+* OriginSystem
+
+* Purpose:
+* Convert the TimeOrigin in a TimeFrame to a new System.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void OriginSystem( AstTimeFrame *this, AstSystemType oldsys,
+* const char *method, int *status )
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function converts the value of the TimeOrigin attribute stored
+* within a supplied TimeFrame from its original System, etc, to the
+* System, etc, currently associated with the TimeFrame.
+
+* Parameters:
+* this
+* Point to the TimeFrame. On entry, the TimeOrigin value is
+* assumed to refer to the System given by "oldsys", etc. On exit, the
+* TimeOrigin value refers to the System returned by the astGetSystem
+* method, etc.
+* oldsys
+* The System to which the TimeOrigin value stored within "this"
+* refers on entry.
+* method
+* A string containing the method name for error messages.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstMapping *map;
+ AstSystemType newsys;
+ AstTimeScaleType ts;
+ const char *oldu;
+ const char *newu;
+ double newval;
+ double oldval;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Do nothing if the TimeOrigin attribute has not been assigned a value. */
+ if( astTestTimeOrigin( this ) ) {
+
+/* Do nothing if the System has not changed. */
+ newsys = astGetSystem( this );
+ if( oldsys != newsys ) {
+
+/* Create a Mapping to perform the System change. */
+ ts = astGetTimeScale( this );
+ oldu = DefUnit( oldsys, method, "TimeFrame", status ),
+ newu = DefUnit( newsys, method, "TimeFrame", status ),
+ map = MakeMap( this, oldsys, newsys, ts, ts, 0.0, 0.0, oldu, newu,
+ method, status );
+
+/* Use the Mapping to convert the stored TimeOrigin value. */
+ if( map ) {
+ oldval = astGetTimeOrigin( this );
+ astTran1( map, 1, &oldval, 1, &newval );
+
+/* Store the new value */
+ astSetTimeOrigin( this, newval );
+
+/* Free resources */
+ map = astAnnul( map );
+
+ } else if( astOK ) {
+ astError( AST__INCTS, "%s(%s): Cannot convert the TimeOrigin "
+ "value to a different System because of incompatible "
+ "time scales.", status, method, astGetClass( this ) );
+ }
+ }
+ }
+}
+
+static void Overlay( AstFrame *template, const int *template_axes,
+ AstFrame *result, int *status ) {
+/*
+* Name:
+* Overlay
+
+* Purpose:
+* Overlay the attributes of a template TimeFrame on to another Frame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void Overlay( AstFrame *template, const int *template_axes,
+* AstFrame *result, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the protected astOverlay method
+* inherited from the Frame class).
+
+* Description:
+* This function overlays attributes of a TimeFrame (the "template") on to
+* another Frame, so as to over-ride selected attributes of that second
+* Frame. Normally only those attributes which have been specifically set
+* in the template will be transferred. This implements a form of
+* defaulting, in which a Frame acquires attributes from the template, but
+* retains its original attributes (as the default) if new values have not
+* previously been explicitly set in the template.
+*
+* Note that if the result Frame is a TimeFrame and a change of time
+* coordinate system occurs as a result of overlaying its System
+* attribute, then some of its original attribute values may no
+* longer be appropriate (e.g. the Title, or attributes describing
+* its axes). In this case, these will be cleared before overlaying
+* any new values.
+
+* Parameters:
+* template
+* Pointer to the template TimeFrame, 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.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* void
+
+* Notes:
+* - In general, if the result Frame is not from the same class as the
+* template TimeFrame, or from a class derived from it, then attributes may
+* exist in the template TimeFrame which do not exist in the result Frame.
+* In this case, these attributes will not be transferred.
+*/
+
+
+/* Local Variables: */
+ AstSystemType new_alignsystem;/* Code identifying new alignment coords */
+ AstSystemType new_system; /* Code identifying new cordinates */
+ AstSystemType old_system; /* Code identifying old coordinates */
+ int resetSystem; /* Was the template System value cleared? */
+ int timeframe; /* Result Frame is a TimeFrame? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get the old and new systems. */
+ old_system = astGetSystem( result );
+ new_system = astGetSystem( template );
+
+/* If the result Frame is a TimeFrame, we must test to see if overlaying its
+ System attribute will change the type of coordinate system it describes.
+ Determine the value of this attribute for the result and template
+ TimeFrames. */
+ resetSystem = 0;
+ timeframe = astIsATimeFrame( result );
+ if( timeframe ) {
+
+/* If the coordinate system will change, any value already set for the result
+ TimeFrame's Title, etc, will no longer be appropriate, so clear it. */
+ if ( new_system != old_system ) {
+ astClearTitle( result );
+ astClearLabel( result, 0 );
+ astClearSymbol( result, 0 );
+ }
+
+/* If the result Frame is not a TimeFrame, we must temporarily clear the
+ System and AlignSystem values since the values used by this class are only
+ appropriate to this class. */
+ } else {
+ if( astTestSystem( template ) ) {
+ astClearSystem( template );
+
+ new_alignsystem = astGetAlignSystem( template );
+ astClearAlignSystem( template );
+
+ resetSystem = 1;
+ }
+ }
+
+/* Invoke the parent class astOverlay method to transfer attributes inherited
+ from the parent class. */
+ (*parent_overlay)( template, template_axes, result, status );
+
+/* Reset the System and AlignSystem values if necessary */
+ if( resetSystem ) {
+ astSetSystem( template, new_system );
+ astSetAlignSystem( template, new_alignsystem );
+ }
+
+/* Check if the result Frame is a TimeFrame or from a class derived from
+ TimeFrame. If not, we cannot transfer TimeFrame attributes to it as it is
+ insufficiently specialised. In this case simply omit these attributes. */
+ if ( timeframe && astOK ) {
+
+/* Define macros that test whether an attribute is set in the template and,
+ if so, transfers its value to the result. */
+#define OVERLAY(attribute) \
+ if ( astTest##attribute( template ) ) { \
+ astSet##attribute( result, astGet##attribute( template ) ); \
+ }
+
+/* Use the macro to transfer each TimeFrame attribute in turn. Note,
+ SourceVRF must be overlayed before SourceVel. Otherwise the stored value
+ for SourceVel would be changed from the default SourceVRF to the specified
+ SourceVRF when SourceVRF was overlayed. */
+ OVERLAY(AlignTimeScale)
+ OVERLAY(LTOffset)
+ OVERLAY(TimeOrigin)
+ OVERLAY(TimeScale)
+ }
+
+/* Undefine macros local to this function. */
+#undef OVERLAY
+}
+
+static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
+/*
+* Name:
+* SetAttrib
+
+* Purpose:
+* Set an attribute value for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void SetAttrib( AstObject *this, const char *setting, int *status )
+
+* Class Membership:
+* TimeFrame member function (extends the astSetAttrib method inherited from
+* the Mapping class).
+
+* Description:
+* This function assigns an attribute value for a TimeFrame, 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 TimeFrame.
+* setting
+* Pointer to a null terminated string specifying the new attribute
+* value.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* void
+
+* Notes:
+* This protected method is intended to be invoked by the Object astSet
+* method and makes additional attributes accessible to it.
+*/
+
+/* Local Vaiables: */
+ AstTimeFrame *this; /* Pointer to the TimeFrame structure */
+ AstTimeScaleType ts; /* time scale type code */
+ char *a; /* Pointer to next character */
+ char *new_setting; /* Pointer value to new attribute setting */
+ double dval; /* Double atribute value */
+ double mjd; /* MJD read from setting */
+ double origin; /* TimeOrigin value */
+ int len; /* Length of setting string */
+ int namelen; /* Length of attribute name in setting */
+ int nc; /* Number of characters read by astSscanf */
+ int off; /* Offset of attribute value */
+ int rep; /* Original error reporting state */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_object;
+
+/* Obtain the length of the setting string. */
+ len = strlen( setting );
+
+/* Test for each recognised attribute in turn, using "astSscanf" to parse the
+ setting string and extract the attribute value (or an offset to it in the
+ case of string values). In each case, use the value set in "nc" to check
+ that the entire string was matched. Once a value has been obtained, use the
+ appropriate method to set it. */
+
+/* First look for axis attributes defined by the Frame class. Since a
+ TimeFrame has only 1 axis, we allow these attributes to be specified
+ without a trailing "(axis)" string. */
+ if ( !strncmp( setting, "direction=", 10 ) ||
+ !strncmp( setting, "bottom=", 7 ) ||
+ !strncmp( setting, "top=", 4 ) ||
+ !strncmp( setting, "format=", 7 ) ||
+ !strncmp( setting, "label=", 6 ) ||
+ !strncmp( setting, "symbol=", 7 ) ||
+ !strncmp( setting, "unit=", 5 ) ) {
+
+/* Create a new setting string from the original by appending the string
+ "(1)" to the end of the attribute name and then use the parent SetAttrib
+ method. */
+ new_setting = astMalloc( len + 4 );
+ if( new_setting ) {
+ memcpy( new_setting, setting, len + 1 );
+ a = strchr( new_setting, '=' );
+ namelen = a - new_setting;
+ memcpy( a, "(1)", 4 );
+ a += 3;
+ strcpy( a, setting + namelen );
+ (*parent_setattrib)( this_object, new_setting, status );
+ new_setting = astFree( new_setting );
+ }
+
+/* AlignTimeScale. */
+/* --------------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "aligntimescale=%n%*s %n", &off, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Convert the string to a TimeScale code before use. */
+ ts = TimeScaleCode( setting + off, status );
+ if ( ts != AST__BADTS ) {
+ astSetAlignTimeScale( this, ts );
+
+/* Report an error if the string value wasn't recognised. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid time scale "
+ "description \"%s\".", status, astGetClass( this ), setting+off );
+ }
+
+/* ClockLat. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "clocklat=%n%*s %n", &off, &nc ) )
+ && ( nc >= 7 ) ) {
+ new_setting = astMalloc( sizeof( char )*(size_t) len + 1 );
+ new_setting[ 0 ] = 'o';
+ new_setting[ 1 ] = 'b';
+ new_setting[ 2 ] = 's';
+ strcpy( new_setting + 3, setting + 5 );
+ astSetAttrib( this, new_setting );
+ new_setting = astFree( new_setting );
+
+/* ClockLon. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "clocklon=%n%*s %n", &off, &nc ) )
+ && ( nc >= 7 ) ) {
+ new_setting = astMalloc( sizeof( char )*(size_t) len + 1 );
+ new_setting[ 0 ] = 'o';
+ new_setting[ 1 ] = 'b';
+ new_setting[ 2 ] = 's';
+ strcpy( new_setting + 3, setting + 5 );
+ astSetAttrib( this, new_setting );
+ new_setting = astFree( new_setting );
+
+/* LTOffset */
+/* -------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "ltoffset= %lg %n", &dval, &nc ) )
+ && ( nc >= len ) ) {
+ astSetLTOffset( this, dval );
+
+/* TimeOrigin */
+/* ---------- */
+
+/* Floating-point without any units indication - assume the current Unit
+ value. */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "timeorigin= %lg %n", &dval, &nc ) )
+ && ( nc >= len ) ) {
+
+ astSetTimeOrigin( this, ToUnits( this, astGetUnit( this, 0 ), dval,
+ "astSetTimeOrigin", status ) );
+
+/* Floating-point with units. */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "timeorigin= %lg %n%*s %n", &dval, &off, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Defer error reporting in case a date string was given which starts
+ with a floating point number, then convert the supplied value to the
+ default units for the TimeFrame's System. */
+ rep = astReporting( 0 );
+ origin = ToUnits( this, setting + off, dval, "astSetTimeOrigin", status );
+ if( !astOK ) astClearStatus;
+ astReporting( rep );
+
+/* If the origin was converted, store it. */
+ if( origin != AST__BAD ) {
+ astSetTimeOrigin( this, origin );
+
+/* Otherwise, interpret the string as a date. Convert first to MJD then to
+ default system. */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "timeorigin=%n%*[^\n]%n", &off, &nc ) )
+ && ( nc >= len ) ) {
+ mjd = astReadDateTime( setting + off );
+ if ( astOK ) {
+ astSetTimeOrigin( this, FromMJD( this, mjd, status ) );
+
+/* Report contextual information if the conversion failed. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid TimeOrigin value "
+ "\"%s\" given.", status, astGetClass( this ), setting + off );
+ }
+ }
+
+/* String (assumed to be a date). Convert first to MJD then to default
+ system. */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "timeorigin=%n%*[^\n]%n", &off, &nc ) )
+ && ( nc >= len ) ) {
+ mjd = astReadDateTime( setting + off );
+ if ( astOK ) {
+ astSetTimeOrigin( this, FromMJD( this, mjd, status ) );
+
+/* Report contextual information if the conversion failed. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid TimeOrigin value "
+ "\"%s\" given.", status, astGetClass( this ), setting + off );
+ }
+
+/* TimeScale. */
+/* ---------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "timescale=%n%*s %n", &off, &nc ) )
+ && ( nc >= len ) ) {
+
+/* Convert the string to a TimeScale code before use. */
+ ts = TimeScaleCode( setting + off, status );
+ if ( ts != AST__BADTS ) {
+ astSetTimeScale( this, ts );
+
+/* Report an error if the string value wasn't recognised. */
+ } else {
+ astError( AST__ATTIN, "astSetAttrib(%s): Invalid time scale "
+ "description \"%s\".", status, astGetClass( this ), setting + off );
+ }
+
+/* Pass any unrecognised setting to the parent method for further
+ interpretation. */
+ } else {
+ (*parent_setattrib)( this_object, setting, status );
+ }
+}
+
+static void SetSystem( AstFrame *this_frame, AstSystemType newsys, int *status ) {
+/*
+* Name:
+* SetSystem
+
+* Purpose:
+* Set the System attribute for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void SetSystem( AstFrame *this_frame, AstSystemType newsys, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astSetSystem protected
+* method inherited from the Frame class).
+
+* Description:
+* This function sets the System attribute for a TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* newsys
+* The new System value to be stored.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstTimeFrame *this; /* Pointer to TimeFrame structure */
+ AstSystemType oldsys; /* Original System value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* If we are changing the System to BEPOCH, set the Unit attribute to
+ "yr" and TimeScale to "TT". */
+ if( newsys == AST__BEPOCH ) {
+ astSetUnit( this_frame, 0, "yr" );
+ astSetTimeScale( (AstTimeFrame *) this_frame, AST__TT );
+ }
+
+/* Save the original System value */
+ oldsys = astGetSystem( this_frame );
+
+/* Use the parent SetSystem method to store the new System value. */
+ (*parent_setsystem)( this_frame, newsys, status );
+
+/* If the system has changed... */
+ if( oldsys != newsys ) {
+
+/* Modify the stored TimeOrigin. */
+ OriginSystem( this, oldsys, "astSetSystem", status );
+
+/* Clear all attributes which have system-specific defaults. */
+ astClearLabel( this_frame, 0 );
+ astClearSymbol( this_frame, 0 );
+ astClearTitle( this_frame );
+ }
+}
+
+static void SetTimeScale( AstTimeFrame *this, AstTimeScaleType value, int *status ) {
+/*
+*+
+* Name:
+* astSetTimeScale
+
+* Purpose:
+* Set the TimeScale attribute for a TimeFrame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void astSetTimeScale( AstTimeFrame *this, AstTimeScaleType value )
+
+* Class Membership:
+* TimeFrame virtual function
+
+* Description:
+* This function set a new value for the TimeScale attribute for a
+* TimeFrame.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* value
+* The new value.
+
+*-
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Verify the supplied timescale value */
+ if( value < FIRST_TS || value > LAST_TS ) {
+ astError( AST__ATTIN, "%s(%s): Bad value (%d) given for TimeScale "
+ "attribute.", status, "astSetTimeScale", astGetClass( this ),
+ (int) value );
+
+/* Report an error if System is set to BEPOCH and an in appropriate
+ TimeScale was supplied. */
+ } else if( astGetSystem( this ) == AST__BEPOCH &&
+ value != AST__TT ) {
+ astError( AST__ATTIN, "%s(%s): Supplied TimeScale (%s) cannot be "
+ "used because the %s represents Besselian Epoch which "
+ "is defined in terms of TT.", status, "astSetTimeScale",
+ astGetClass( this ), TimeScaleString( value, status ),
+ astGetClass( this ) );
+
+/* Otherwise set the new TimeScale */
+ } else {
+
+/* Modify the TimeOrigin value stored in the TimeFrame structure to refer
+ to the new timescale. */
+ OriginScale( this, value, "astSetTimeScale", status );
+
+/* Store the new value for the timescale in the TimeFrame structure. */
+ this->timescale = value;
+
+ }
+}
+
+static void SetUnit( AstFrame *this_frame, int axis, const char *value, int *status ) {
+/*
+* Name:
+* SetUnit
+
+* Purpose:
+* Set a pointer to the Unit string for a TimeFrame's axis.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void SetUnit( AstFrame *this_frame, int axis, const char *value )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astSetUnit method inherited
+* from the Frame class).
+
+* Description:
+* This function stores a pointer to the Unit string for a specified axis
+* of a TimeFrame. It also stores the string in the "usedunits" array
+* in the TimeFrame structure, in the element associated with the
+* current System.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* axis
+* The number of the axis (zero-based) for which information is required.
+* unit
+* The new string to store.
+*/
+
+/* Local Variables: */
+ AstTimeFrame *this;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* Validate the axis index. */
+ astValidateAxis( this, axis, 1, "astSetUnit" );
+
+/* Report an error if System is set to BEPOCH and an in appropriate
+ Unit was supplied. */
+ if( astGetSystem( this ) == AST__BEPOCH && strcmp( "yr", value ) ) {
+ astError( AST__ATTIN, "astSetUnit(%s): Supplied Unit (%s) cannot "
+ "be used because the %s represents Besselian Epoch which "
+ "is defined in units of years (yr).", status, astGetClass( this ),
+ value, astGetClass( this ) );
+
+/* Otherwise use the parent SetUnit method to store the value in the Axis
+ structure */
+ } else {
+ (*parent_setunit)( this_frame, axis, value, status );
+ }
+}
+
+static AstTimeScaleType TimeScaleCode( const char *ts, int *status ) {
+/*
+* Name:
+* TimeScaleCode
+
+* Purpose:
+* Convert a string into a time scale type code.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstTimeScaleType TimeScaleCode( const char *ts )
+
+* Class Membership:
+* TimeFrame member function.
+
+* Description:
+* This function converts a string used for the external description of
+* a time scale into a TimeFrame time scale type code (TimeScale attribute
+* value). It is the inverse of the TimeScaleString function.
+
+* Parameters:
+* ts
+* Pointer to a constant null-terminated string containing the
+* external description of the time scale.
+
+* Returned Value:
+* The TimeScale type code.
+
+* Notes:
+* - A value of AST__BADTS is returned if the time scale
+* description was not recognised. This does not produce an error.
+* - A value of AST__BADTS is also returned if this function
+* is invoked with the global error status set or if it should fail
+* for any reason.
+*/
+
+/* Local Variables: */
+ AstTimeScaleType result; /* Result value to return */
+
+/* Initialise. */
+ result = AST__BADTS;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Match the timescale string against each possibility and assign the
+ result. */
+ if ( astChrMatch( "TAI", ts ) ) {
+ result = AST__TAI;
+
+ } else if ( astChrMatch( "UTC", ts ) ) {
+ result = AST__UTC;
+
+ } else if ( astChrMatch( "UT1", ts ) ) {
+ result = AST__UT1;
+
+ } else if ( astChrMatch( "GMST", ts ) ) {
+ result = AST__GMST;
+
+ } else if ( astChrMatch( "LAST", ts ) ) {
+ result = AST__LAST;
+
+ } else if ( astChrMatch( "LMST", ts ) ) {
+ result = AST__LMST;
+
+ } else if ( astChrMatch( "TT", ts ) ) {
+ result = AST__TT;
+
+ } else if ( astChrMatch( "TDB", ts ) ) {
+ result = AST__TDB;
+
+ } else if ( astChrMatch( "TCG", ts ) ) {
+ result = AST__TCG;
+
+ } else if ( astChrMatch( "TCB", ts ) ) {
+ result = AST__TCB;
+
+ } else if ( astChrMatch( "LT", ts ) ) {
+ result = AST__LT;
+
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *TimeScaleString( AstTimeScaleType ts, int *status ) {
+/*
+* Name:
+* TimeScaleString
+
+* Purpose:
+* Convert a time scale type code into a string.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *TimeScaleString( AstTimeScaleType ts, int *status )
+
+* Class Membership:
+* TimeFrame member function.
+
+* Description:
+* This function converts a TimeFrame time scale type code (TimeScale
+* attribute value) into a string suitable for use as an external
+* representation of the time scale type.
+
+* Parameters:
+* ts
+* The time scale type code.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to a constant null-terminated string containing the
+* textual equivalent of the type code supplied.
+
+* Notes:
+* - A NULL pointer value is returned if the time scale
+* 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 timescale value against each possibility and convert to a
+ string pointer. */
+ switch ( ts ) {
+
+ case AST__TAI:
+ result = "TAI";
+ break;
+
+ case AST__UTC:
+ result = "UTC";
+ break;
+
+ case AST__UT1:
+ result = "UT1";
+ break;
+
+ case AST__GMST:
+ result = "GMST";
+ break;
+
+ case AST__LAST:
+ result = "LAST";
+ break;
+
+ case AST__LMST:
+ result = "LMST";
+ break;
+
+ case AST__TT:
+ result = "TT";
+ break;
+
+ case AST__TDB:
+ result = "TDB";
+ break;
+
+ case AST__TCB:
+ result = "TCB";
+ break;
+
+ case AST__TCG:
+ result = "TCG";
+ break;
+
+ case AST__LT:
+ result = "LT";
+ break;
+
+ }
+
+/* Return the result pointer. */
+ return result;
+}
+
+static int SubFrame( AstFrame *target_frame, AstFrame *template,
+ int result_naxes, const int *target_axes,
+ const int *template_axes, AstMapping **map,
+ AstFrame **result, int *status ) {
+/*
+* Name:
+* SubFrame
+
+* Purpose:
+* Select axes from a TimeFrame and convert to the new coordinate
+* system.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int SubFrame( AstFrame *target, AstFrame *template,
+* int result_naxes, const int *target_axes,
+* const int *template_axes, AstMapping **map,
+* AstFrame **result, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the protected astSubFrame
+* method inherited from the Frame class).
+
+* Description:
+* This function selects a requested sub-set (or super-set) of the axes
+* from a "target" TimeFrame 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 TimeFrame, 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 TimeFrame. 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
+* TimeFrame to that described by the result Frame. The inverse
+* transformation will convert in the opposite direction.
+* result
+* Address of a location to receive a pointer to the result Frame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A non-zero value is returned if coordinate conversion is possible
+* between the target and the result Frame. Otherwise zero is returned and
+* *map and *result are returned as NULL (but this will not in itself
+* result in an error condition). In general, coordinate conversion should
+* always be possible if no template Frame is supplied but may not always
+* be possible otherwise.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+
+* Implementation Notes:
+* - This implementation addresses the selection of axes from a
+* TimeFrame object. This results in another object of the same class
+* only if the single TimeFrame axis is selected exactly once.
+* Otherwise, the result is a Frame class object which inherits the
+* TimeFrame's axis information (if appropriate) but none of the other
+* properties of a TimeFrame.
+* - In the event that a TimeFrame results, the returned Mapping will
+* take proper account of the relationship between the target and result
+* coordinate systems.
+* - In the event that a Frame class object results, the returned Mapping
+* will only represent a selection/permutation of axes.
+
+* Implementation Deficiencies:
+* - Any axis selection is currently permitted. Probably this should be
+* restricted so that each axis can only be selected once. The
+* astValidateAxisSelection method will do this but currently there are bugs
+* in the CmpFrame class that cause axis selections which will not pass this
+* test. Install the validation when these are fixed.
+*/
+
+/* Local Variables: */
+ AstTimeFrame *target; /* Pointer to the TimeFrame structure */
+ AstTimeFrame *temp; /* Pointer to copy of target TimeFrame */
+ AstTimeFrame *align_frm; /* Frame in which to align the TimeFrames */
+ int match; /* Coordinate conversion is possible? */
+
+/* Initialise the returned values. */
+ *map = NULL;
+ *result = NULL;
+ match = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return match;
+
+/* Obtain a pointer to the target TimeFrame structure. */
+ target = (AstTimeFrame *) target_frame;
+
+/* Result is a TimeFrame. */
+/* -------------------------- */
+/* Check if the result Frame is to have one axis obtained by selecting
+ the single target TimeFrame axis. If so, the result will also be
+ a TimeFrame. */
+ if ( ( result_naxes == 1 ) && ( target_axes[ 0 ] == 0 ) ) {
+
+/* Form the result from a copy of the target. */
+ *result = astCopy( target );
+
+/* If required, overlay the template attributes on to the result TimeFrame.
+ Also choose the Frame which defined the alignment system and time scale
+ (via its AlignSystem and AlignTimeScale attributes) in which to align the
+ two TimeFrames. This is the template (if there is a template). */
+ if ( template ) {
+ astOverlay( template, template_axes, *result );
+ if( astIsATimeFrame( template ) ) {
+ align_frm = astClone( template );
+ } else {
+ align_frm = astClone( target );
+ }
+
+/* If no template was supplied, align in the System and TimeScale of the
+ target. */
+ } else {
+ VerifyAttrs( target, "convert between different time systems",
+ "TimeScale", "astMatch", status );
+ align_frm = astClone( target );
+ }
+
+/* Generate a Mapping that takes account of changes in the sky coordinate
+ system (equinox, epoch, etc.) between the target TimeFrame and the result
+ TimeFrame. If this Mapping can be generated, set "match" to indicate that
+ coordinate conversion is possible. */
+ match = ( MakeTimeMapping( target, (AstTimeFrame *) *result,
+ align_frm, 0, map, status ) != 0 );
+
+/* Free resources. */
+ align_frm = astAnnul( align_frm );
+
+/* Result is not a TimeFrame. */
+/* ------------------------------ */
+/* In this case, we select axes as if the target were from the Frame
+ class. However, since the resulting data will then be separated
+ from their enclosing TimeFrame, default attribute values may differ
+ if the methods for obtaining them were over-ridden by the TimeFrame
+ class. To overcome this, we ensure that these values are explicitly
+ set for the result Frame (rather than relying on their defaults). */
+ } else {
+
+/* Make a temporary copy of the target TimeFrame. We will explicitly
+ set the attribute values in this copy so as not to modify the original. */
+ temp = astCopy( target );
+
+/* Define a macro to test if an attribute is set. If not, set it
+ explicitly to its default value. */
+#define SET(attribute) \
+ if ( !astTest##attribute( temp ) ) { \
+ astSet##attribute( temp, astGet##attribute( temp ) ); \
+ }
+
+/* Set attribute values which apply to the Frame as a whole and which
+ we want to retain, but whose defaults are over-ridden by the
+ TimeFrame class. */
+ SET(Domain)
+ SET(Title)
+
+/* Define a macro to test if an attribute is set for axis zero (the only
+ axis of a TimeFrame). If not, set it explicitly to its default value. */
+#define SET_AXIS(attribute) \
+ if ( !astTest##attribute( temp, 0 ) ) { \
+ astSet##attribute( temp, 0, \
+ astGet##attribute( temp, 0 ) ); \
+ }
+
+/* Use this macro to set explicit values for all the axis attributes
+ for which the TimeFrame class over-rides the default value. */
+ SET_AXIS(Label)
+ SET_AXIS(Symbol)
+ SET_AXIS(Unit)
+
+/* Clear attributes which have an extended range of values allowed by
+ this class. */
+ astClearSystem( temp );
+ astClearAlignSystem( temp );
+
+/* Invoke the astSubFrame method inherited from the Frame class to
+ produce the result Frame by selecting the required set of axes and
+ overlaying the template Frame's attributes. */
+ match = (*parent_subframe)( (AstFrame *) temp, template,
+ result_naxes, target_axes, template_axes,
+ map, result, status );
+
+/* Delete the temporary copy of the target TimeFrame. */
+ temp = astDelete( temp );
+ }
+
+/* If an error occurred or no match was found, annul the returned
+ objects and reset the returned result. */
+ if ( !astOK || !match ) {
+ if( *map ) *map = astAnnul( *map );
+ if( *result ) *result = astAnnul( *result );
+ match = 0;
+ }
+
+/* Return the result. */
+ return match;
+
+/* Undefine macros local to this function. */
+#undef SET
+#undef SET_AXIS
+}
+
+static AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) {
+/*
+* Name:
+* SystemCode
+
+* Purpose:
+* Convert a string into a coordinate system type code.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstSystemType SystemCode( AstFrame *this, const char *system, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astSystemCode method
+* inherited from the Frame class).
+
+* Description:
+* This function converts a string used for the external description of
+* a coordinate system into a TimeFrame coordinate system type code
+* (System attribute value). It is the inverse of the astSystemString
+* function.
+
+* Parameters:
+* this
+* The Frame.
+* system
+* Pointer to a constant null-terminated string containing the
+* external description of the sky coordinate system.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The System type code.
+
+* Notes:
+* - A value of AST__BADSYSTEM is returned if the sky coordinate
+* system description was not recognised. This does not produce an
+* error.
+* - A value of AST__BADSYSTEM is also returned if this function
+* is invoked with the global error status set or if it should fail
+* for any reason.
+*/
+
+/* Local Variables: */
+ AstSystemType result; /* Result value to return */
+
+/* Initialise. */
+ result = AST__BADSYSTEM;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Match the "system" string against each possibility and assign the
+ result. */
+ if ( astChrMatch( "MJD", system ) || astChrMatch( "Modified Julian Date", system ) ) {
+ result = AST__MJD;
+
+ } else if ( astChrMatch( "JD", system ) || astChrMatch( "Julian Date", system ) ) {
+ result = AST__JD;
+
+ } else if ( astChrMatch( "BEPOCH", system ) || astChrMatch( "Besselian Epoch", system ) ) {
+ result = AST__BEPOCH;
+
+ } else if ( astChrMatch( "JEPOCH", system ) || astChrMatch( "Julian Epoch", system ) ) {
+ result = AST__JEPOCH;
+
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *SystemLabel( AstSystemType system, int *status ) {
+/*
+* Name:
+* SystemLabel
+
+* Purpose:
+* Return a label for a coordinate system type code.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *SystemLabel( AstSystemType system, int *status )
+
+* Class Membership:
+* TimeFrame member function.
+
+* Description:
+* This function converts a TimeFrame coordinate system type code
+* (System attribute value) into a descriptive string for human readers.
+
+* Parameters:
+* system
+* The coordinate system type code.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to a constant null-terminated string containing the
+* textual equivalent of the type code supplied.
+
+* Notes:
+* - A NULL pointer value is returned if the sky coordinate system
+* code was not recognised. This does not produce an error.
+* - A NULL pointer value is also returned if this function is
+* invoked with the global error status set or if it should fail
+* for any reason.
+*/
+
+/* Local Variables: */
+ const char *result; /* Pointer value to return */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Match the "system" value against each possibility and convert to a
+ string pointer. */
+ switch ( system ) {
+
+ case AST__MJD:
+ result = "Modified Julian Date";
+ break;
+
+ case AST__JD:
+ result = "Julian Date";
+ break;
+
+ case AST__JEPOCH:
+ result = "Julian Epoch";
+ break;
+
+ case AST__BEPOCH:
+ result = "Besselian Epoch";
+ break;
+
+ }
+
+/* Return the result pointer. */
+ return result;
+}
+
+static const char *SystemString( AstFrame *this, AstSystemType system, int *status ) {
+/*
+* Name:
+* SystemString
+
+* Purpose:
+* Convert a coordinate system type code into a string.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* const char *SystemString( AstFrame *this, AstSystemType system, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astSystemString method
+* inherited from the Frame class).
+
+* Description:
+* This function converts a TimeFrame coordinate system type code
+* (System attribute value) into a string suitable for use as an
+* external representation of the coordinate system type.
+
+* Parameters:
+* this
+* The Frame.
+* system
+* The coordinate system type code.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to a constant null-terminated string containing the
+* textual equivalent of the type code supplied.
+
+* Notes:
+* - A NULL pointer value is returned if the sky coordinate system
+* code was not recognised. This does not produce an error.
+* - A NULL pointer value is also returned if this function is
+* invoked with the global error status set or if it should fail
+* for any reason.
+*/
+
+/* Local Variables: */
+ const char *result; /* Pointer value to return */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Match the "system" value against each possibility and convert to a
+ string pointer. (Where possible, return the same string as would be
+ used in the FITS WCS representation of the coordinate system). */
+ switch ( system ) {
+
+ case AST__MJD:
+ result = "MJD";
+ break;
+
+ case AST__JD:
+ result = "JD";
+ break;
+
+ case AST__JEPOCH:
+ result = "JEPOCH";
+ break;
+
+ case AST__BEPOCH:
+ result = "BEPOCH";
+ break;
+ }
+
+/* Return the result pointer. */
+ return result;
+}
+
+static int TestActiveUnit( AstFrame *this_frame, int *status ) {
+/*
+* Name:
+* TestActiveUnit
+
+* Purpose:
+* Test the ActiveUnit flag for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int TestActiveUnit( AstFrame *this_frame, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astTestActiveUnit protected
+* method inherited from the Frame class).
+
+* Description:
+* This function test the value of the ActiveUnit flag for a TimeFrame,
+* which is always "unset".
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The result of the test (0).
+
+*/
+ return 0;
+}
+
+static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* TestAttrib
+
+* Purpose:
+* Test if a specified attribute value is set for a TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int TestAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astTestAttrib protected
+* method inherited from the Frame class).
+
+* Description:
+* This function returns a boolean result (0 or 1) to indicate whether
+* a value has been set for one of a TimeFrame's attributes.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* 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: */
+ AstTimeFrame *this; /* Pointer to the TimeFrame structure */
+ char *new_attrib; /* Pointer value to new attribute name */
+ int len; /* Length of attrib string */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_object;
+
+/* Obtain the length of the attrib string. */
+ len = strlen( attrib );
+
+/* Check the attribute name and test the appropriate attribute. */
+
+/* First look for axis attributes defined by the Frame class. Since a
+ TimeFrame has only 1 axis, we allow these attributes to be specified
+ without a trailing "(axis)" string. */
+ if ( !strcmp( attrib, "direction" ) ||
+ !strcmp( attrib, "bottom" ) ||
+ !strcmp( attrib, "top" ) ||
+ !strcmp( attrib, "format" ) ||
+ !strcmp( attrib, "label" ) ||
+ !strcmp( attrib, "symbol" ) ||
+ !strcmp( attrib, "unit" ) ) {
+
+/* Create a new attribute name from the original by appending the string
+ "(1)" and then use the parent TestAttrib method. */
+ new_attrib = astMalloc( len + 4 );
+ if( new_attrib ) {
+ memcpy( new_attrib, attrib, len );
+ memcpy( new_attrib + len, "(1)", 4 );
+ result = (*parent_testattrib)( this_object, new_attrib, status );
+ new_attrib = astFree( new_attrib );
+ }
+
+/* AlignTimeScale. */
+/* --------------- */
+ } else if ( !strcmp( attrib, "aligntimescale" ) ) {
+ result = astTestAlignTimeScale( this );
+
+/* ClockLat. */
+/* ------- */
+ } else if ( !strcmp( attrib, "clocklat" ) ) {
+ result = astTestAttrib( this, "obslat" );
+
+/* ClockLon. */
+/* ------- */
+ } else if ( !strcmp( attrib, "clocklon" ) ) {
+ result = astTestAttrib( this, "obslon" );
+
+/* LTOffset. */
+/* --------- */
+ } else if ( !strcmp( attrib, "ltoffset" ) ) {
+ result = astTestLTOffset( this );
+
+/* TimeOrigin. */
+/* --------- */
+ } else if ( !strcmp( attrib, "timeorigin" ) ) {
+ result = astTestTimeOrigin( this );
+
+/* TimeScale. */
+/* ---------- */
+ } else if ( !strcmp( attrib, "timescale" ) ) {
+ result = astTestTimeScale( this );
+
+/* If the attribute is not recognised, pass it on to the parent method
+ for further interpretation. */
+ } else {
+ result = (*parent_testattrib)( this_object, attrib, status );
+ }
+
+/* Return the result, */
+ return result;
+}
+
+static double ToMJD( AstSystemType oldsys, double oldval, int *status ){
+/*
+* Name:
+* ToMJD
+
+* Purpose:
+* Convert a time value from TimeFrame's System to MJD.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* double ToMJD( AstSystemType oldsys, double oldval, int *status ){
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function converts the supplied value from the supplied System
+* to an MJD.
+
+* Parameters:
+* oldsys
+* The System in which the oldval is supplied.
+* oldval
+* The value to convert, assumed to be in the default units
+* associated with "oldsys".
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The MJD value corresponding to "oldval"
+
+* Notes:
+* - Both old and new value are assumed to be absolute (i.e. have zero
+* offset).
+
+*/
+
+/* Local Variables; */
+ AstMapping *map;
+ double result;
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* If the old system is MJD just return the value unchanged. */
+ if( oldsys == AST__MJD ) {
+ result = oldval;
+
+/* Otherwise create a TimeMap wich converts from the TimeFrame system to
+ MJD, and use it to transform the supplied value. */
+ } else {
+ map = ToMJDMap( oldsys, 0.0, status );
+
+/* Use the TimeMap to convert the supplied value. */
+ astTran1( map, 1, &oldval, 1, &result );
+
+/* Free resources */
+ map = astAnnul( map );
+
+ }
+
+/* Return the result */
+ return result;
+}
+
+static AstMapping *ToMJDMap( AstSystemType oldsys, double off, int *status ){
+/*
+* Name:
+* ToMJDMap
+
+* Purpose:
+* Create a Mapping from a specified System to MJD.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstMapping *ToMJDMap( AstSystemType oldsys, double off, int *status ){
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function creates a Mapping which converts from the supplied
+* system and offset to absolute MJD.
+
+* Parameters:
+* oldsys
+* The System in which the oldval is supplied.
+* off
+* The axis offset used with the old System, assumed to be in the
+* default system associated with oldsys.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The Mapping.
+
+*/
+
+/* Local Variables; */
+ AstTimeMap *timemap;
+ double args[ 2 ];
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Create a null TimeMap */
+ timemap = astTimeMap( 0, "", status );
+
+/* Set the offsets for the supplied and returned values. */
+ args[ 0 ] = off;
+ args[ 1 ] = 0.0;
+
+/* If required, add a TimeMap conversion which converts from the TimeFrame
+ system to MJD. */
+ if( oldsys == AST__MJD ) {
+/* if( off != 0.0 ) astTimeAdd( timemap, "MJDTOMJD", 2, args ); */
+ astTimeAdd( timemap, "MJDTOMJD", 2, args );
+
+ } else if( oldsys == AST__JD ) {
+ astTimeAdd( timemap, "JDTOMJD", 2, args );
+
+ } else if( oldsys == AST__JEPOCH ) {
+ astTimeAdd( timemap, "JEPTOMJD", 2, args );
+
+ } else if( oldsys == AST__BEPOCH ) {
+ astTimeAdd( timemap, "BEPTOMJD", 2, args );
+ }
+
+/* Return the result */
+ return (AstMapping *) timemap;
+}
+
+static double ToUnits( AstTimeFrame *this, const char *oldunit, double oldval,
+ const char *method, int *status ){
+/*
+*
+* Name:
+* ToUnits
+
+* Purpose:
+* Convert a supplied time value to the default units of the supplied TimeFrame.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* double ToUnits( AstTimeFrame *this, const char *oldunit, double oldval,
+* const char *method, int *status )
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function converts the supplied time value from the supplied
+* units to the default units associated with the supplied TimeFrame's
+* System.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* oldunit
+* The units in which "oldval" is supplied.
+* oldval
+* The value to be converted.
+* method
+* Pointer to a string holding the name of the method to be
+* included in any error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The converted value.
+
+*/
+
+/* Local Variables: */
+ AstMapping *map;
+ const char *defunit;
+ double result;
+
+/* Initialise. */
+ result = AST__BAD;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get default units associated with the System attribute of the supplied
+ TimeFrame, and find a Mapping from the old units to the default. */
+ defunit = DefUnit( astGetSystem( this ), method, "TimeFrame", status );
+ map = astUnitMapper( oldunit, defunit, NULL, NULL );
+ if( map ) {
+
+/* Use the Mapping to convert the supplied value. */
+ astTran1( map, 1, &oldval, 1, &result );
+
+/* Free resources. */
+ map = astAnnul( map );
+
+/* Report an error if no conversion is possible. */
+ } else if( astOK ){
+ astError( AST__BADUN, "%s(%s): Cannot convert the supplied attribute "
+ "value from units of %s to %s.", status, method, astGetClass( this ),
+ oldunit, defunit );
+ }
+
+/* Return the result */
+ return result;
+}
+
+static int Unformat( AstFrame *this_frame, int axis, const char *string,
+ double *value, int *status ) {
+/*
+* Name:
+* Unformat
+
+* Purpose:
+* Read a formatted coordinate value for a TimeFrame axis.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int Unformat( AstFrame *this, int axis, const char *string,
+* double *value, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the public astUnformat
+* method inherited from the Frame class).
+
+* Description:
+* This function reads a formatted coordinate value for a TimeFrame
+* 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 TimeFrame.
+* axis
+* The number of the TimeFrame axis for which the coordinate
+* value is to be read (axis numbering starts at zero for the
+* first axis).
+* string
+* Pointer to a constant null-terminated string containing the
+* formatted coordinate value.
+* value
+* Pointer to a double in which the coordinate value read will
+* be returned.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The number of characters read from the string to obtain the
+* coordinate value.
+
+* Notes:
+* - Any white space at the beginning of the string will be
+* skipped, as also will any trailing white space following the
+* coordinate value read. The function's return value will reflect
+* this.
+* - A function value of zero (and no coordinate value) will be
+* returned, without error, if the string supplied does not contain
+* a suitably formatted value.
+* - The string "<bad>" is recognised as a special case and will
+* generate the value AST__BAD, without error. The test for this
+* string is case-insensitive and permits embedded white space.
+* - A function result of zero will be returned and no coordinate
+* value will be returned via the "value" pointer if this function
+* is invoked with the global error status set, or if it should
+* fail for any reason.
+*/
+
+/* Local Variables: */
+ AstMapping *map;
+ AstTimeFrame *this;
+ AstTimeScaleType ts1;
+ AstTimeScaleType ts2;
+ const char *c;
+ char *old_fmt;
+ char *str;
+ const char *txt;
+ double mjd;
+ double val1;
+ int l;
+ int lt;
+ int nc1;
+ int nc;
+ int ndp;
+ int rep;
+
+/* Initialise. */
+ nc = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return nc;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_frame;
+
+/* Validate the axis index. */
+ (void) astValidateAxis( this, axis, 1, "astUnformat" );
+
+/* First attempt to read the value using the parent unformat method, and
+ note how many characters were used. We temporarily clear the Format
+ attribute if it has been set to a date format, since the parent Frame
+ class does not understand date format.*/
+ txt = astGetFormat( this, axis );
+ if( DateFormat( txt, &ndp, NULL, status ) ) {
+ old_fmt = astStore( NULL, txt, strlen( txt ) + 1 );
+ astClearFormat( this, axis );
+ } else {
+ old_fmt = NULL;
+ }
+
+ nc1 = (*parent_unformat)( this_frame, axis, string, &val1, status );
+
+/* Re-instate the original Format */
+ if( old_fmt ) {
+ astSetFormat( this,axis, old_fmt );
+ old_fmt = astFree( old_fmt );
+ }
+
+/* The astReadDateTime function (defined within frame.c) does not allow
+ for any extra text to be appended to the end of the formatted date/time
+ (AST__BAD is returned if any such extra text is present). But astUnformat
+ is contracted to allow such text. So we need to make multiple attempts
+ at reading the date/time in order to find the longest leading string
+ which gives a non-bad value. First take a copy of the supplied string
+ si we can terminate it at any point we wish. */
+ l = astChrLen( string );
+ str = astStore( NULL, string, l + 1 );
+
+/* Now attempt to read an ISO date from the start of the string. We
+ switch off error reporting to avoid reports of unsuitable syntax. */
+ rep = astReporting( 0 );
+
+/* Attempt to read a date/time from the whol string. If this fails
+ terminate the string in order to make it one character shorter and try
+ again. */
+ for( lt = l; lt > 0; lt-- ) {
+ str[ lt ] = 0;
+ mjd = astReadDateTime( str );
+ if( !astOK ) astClearStatus;
+ if( mjd != AST__BAD ) break;
+ }
+
+/* Re-instate error reporting. */
+ astReporting( rep );
+
+/* Free resources. */
+ str = astFree( str );
+
+/* If the whole non-blank start of the string was consumed, add on any
+ trailing white space. */
+ if( lt >= l ) lt = strlen( string );
+
+/* If no date/time could be read, or if reading the value as a
+ floating point value was at least as good, return the floating point
+ value (assumed to be in the system and units of the TimeFrame. */
+ if( mjd == AST__BAD || nc1 >= l ) {
+ *value = val1;
+ nc = nc1;
+
+/* Otherwise, if a date/time was read convert it to the TimeFrame system,
+ etc. */
+ } else if( mjd != AST__BAD ) {
+
+/* Save the number of character read from the supplied string. */
+ nc = lt;
+
+/* We require a value in the timescale of the supplied TimeFrame. Get
+ this TimeScale. */
+ ts2 = astGetTimeScale( this );
+
+/* If the supplied string gave the date/time as a Besselian epoch, the
+ input timescale is TT, otherwise it is assumed to be the TimeScale of
+ the TimeFrame. Locate the first non-space character. */
+ c = string;
+ while( *c && isspace( *c ) ) c++;
+
+/* If the first non-space is a "B", assuming a TT timescale. Otherwise
+ assume the timescale of the supplied TimeFrame. */
+ ts1 = ( *c == 'B' || *c == 'b' ) ? AST__TT : ts2;
+
+/* Create the Mapping and use it to transform the mjd value. */
+ map = MakeMap( this, AST__MJD, astGetSystem( this ), ts1, ts2,
+ 0.0, astGetTimeOrigin( this ), "d",
+ astGetUnit( this, 0 ), "astFormat", status );
+ if( map ) {
+ astTran1( map, 1, &mjd, 1, value );
+ map = astAnnul( map );
+ } else {
+ astError( AST__INCTS, "astUnformat(%s): Cannot convert the "
+ "supplied date/time string (%s) to the required "
+ "timescale (%s).", status, astGetClass( this ), string,
+ TimeScaleString( ts2, status ) );
+ }
+ }
+
+/* Return the number of characters read. */
+ return nc;
+}
+
+static int ValidateSystem( AstFrame *this, AstSystemType system, const char *method, int *status ) {
+/*
+*
+* Name:
+* ValidateSystem
+
+* Purpose:
+* Validate a value for a Frame's System attribute.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "timeframe.h"
+* int ValidateSystem( AstFrame *this, AstSystemType system,
+* const char *method, int *status )
+
+* Class Membership:
+* TimeFrame member function (over-rides the astValidateSystem method
+* inherited from the Frame class).
+
+* Description:
+* This function checks the validity of the supplied system value.
+* If the value is valid, it is returned unchanged. Otherwise, an
+* error is reported and a value of AST__BADSYSTEM is returned.
+
+* Parameters:
+* this
+* Pointer to the Frame.
+* system
+* The system value to be checked.
+* method
+* Pointer to a constant null-terminated character string
+* containing the name of the method that invoked this function
+* to validate an axis index. This method name is used solely
+* for constructing error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The validated system value.
+
+* Notes:
+* - A value of AST__BADSYSTEM will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstSystemType result; /* Validated system value */
+
+/* Initialise. */
+ result = AST__BADSYSTEM;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* If the value is out of bounds, report an error. */
+ if ( system < FIRST_SYSTEM || system > LAST_SYSTEM ) {
+ astError( AST__AXIIN, "%s(%s): Bad value (%d) given for the System "
+ "or AlignSystem attribute of a %s.", status, method,
+ astGetClass( this ), (int) system, astGetClass( this ) );
+
+/* Otherwise, return the supplied value. */
+ } else {
+ result = system;
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static void VerifyAttrs( AstTimeFrame *this, const char *purp,
+ const char *attrs, const char *method, int *status ) {
+/*
+* Name:
+* VerifyAttrs
+
+* Purpose:
+* Verify that usable attribute values are available.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "timeframe.h"
+* void VerifyAttrs( AstTimeFrame *this, const char *purp,
+* const char *attrs, const char *method, int *status )
+
+* Class Membership:
+* TimeFrame member function
+
+* Description:
+* This function tests each attribute listed in "attrs". It returns
+* without action if 1) an explicit value has been set for each attribute
+* or 2) the UseDefs attribute of the supplied TimeFrame is non-zero.
+*
+* If UseDefs is zero (indicating that default values should not be
+* used for attributes), and any of the named attributes does not have
+* an explicitly set value, then an error is reported.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame.
+* purp
+* Pointer to a text string containing a message which will be
+* included in any error report. This shouldindicate the purpose
+* for which the attribute value is required.
+* attrs
+* A string holding a space separated list of attribute names.
+* method
+* A string holding the name of the calling method for use in error
+* messages.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ const char *a;
+ const char *desc;
+ const char *p;
+ int len;
+ int set;
+ int state;
+
+/* Check inherited status */
+ if( !astOK ) return;
+
+/* Stop compiler warnings about uninitialised variables */
+ a = NULL;
+ desc = NULL;
+ len = 0;
+ set = 0;
+
+/* If the TimeFrame has a non-zero value for its UseDefs attribute, then
+ all attributes are assumed to have usable values, since the defaults
+ will be used if no explicit value has been set. So we only need to do
+ any checks if UseDefs is zero. */
+ if( !astGetUseDefs( this ) ) {
+
+/* Loop round the "attrs" string identifying the start and length of each
+ non-blank word in the string. */
+ state = 0;
+ p = attrs;
+ while( 1 ) {
+ if( state == 0 ) {
+ if( !isspace( *p ) ) {
+ a = p;
+ len = 1;
+ state = 1;
+ }
+ } else {
+ if( isspace( *p ) || !*p ) {
+
+/* The end of a word has just been reached. Compare it to each known
+ attribute value. Get a flag indicating if the attribute has a set
+ value, and a string describing the attribute.*/
+ if( len > 0 ) {
+
+ if( !strncmp( "ObsLat", a, len ) ) {
+ set = astTestObsLat( this );
+ desc = "observer latitude";
+
+ } else if( !strncmp( "ObsLon", a, len ) ) {
+ set = astTestObsLon( this );
+ desc = "observer longitude";
+
+ } else if( !strncmp( "ObsAlt", a, len ) ) {
+ set = astTestObsAlt( this );
+ desc = "observer altitude";
+
+ } else if( !strncmp( "Dtai", a, len ) ) {
+ set = astTestDtai( this );
+ desc = "TAI-UTC correction";
+
+ } else if( !strncmp( "Dut1", a, len ) ) {
+ set = astTestDut1( this );
+ desc = "UT1-UTC correction";
+
+ } else if( !strncmp( "TimeOrigin", a, len ) ) {
+ set = astTestTimeOrigin( this );
+ desc = "time offset";
+
+ } else if( !strncmp( "LTOffset", a, len ) ) {
+ set = astTestLTOffset( this );
+ desc = "local time offset";
+
+ } else if( !strncmp( "TimeScale", a, len ) ) {
+ set = astTestTimeScale( this );
+ desc = "time scale";
+
+ } else {
+ astError( AST__INTER, "VerifyAttrs(TimeFrame): "
+ "Unknown attribute name \"%.*s\" supplied (AST "
+ "internal programming error).", status, len, a );
+ }
+
+/* If the attribute does not have a set value, report an error. */
+ if( !set && astOK ) {
+ astError( AST__NOVAL, "%s(%s): Cannot %s.", status, method,
+ astGetClass( this ), purp );
+ astError( AST__NOVAL, "No value has been set for "
+ "the AST \"%.*s\" attribute (%s).", status, len, a,
+ desc );
+ }
+
+/* Continue the word search algorithm. */
+ }
+ len = 0;
+ state = 0;
+ } else {
+ len++;
+ }
+ }
+ if( !*(p++) ) break;
+ }
+ }
+}
+
+/* Functions which access class attributes. */
+/* ---------------------------------------- */
+
+/*
+*att++
+* Name:
+* TimeOrigin
+
+* Purpose:
+* The zero point for TimeFrame axis values
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Floating point.
+
+* Description:
+* This specifies the origin from which all time values are measured.
+* The default value (zero) results in the TimeFrame describing
+* absolute time values in the system given by the System attribute
+* (e.g. MJD, Julian epoch, etc). If a TimeFrame is to be used to
+* describe elapsed time since some origin, the TimeOrigin attribute
+* should be set to hold the required origin value. The TimeOrigin value
+* stored inside the TimeFrame structure is modified whenever TimeFrame
+* attribute values are changed so that it refers to the original moment
+* in time.
+*
+* Input Formats:
+* The formats accepted when setting a TimeOrigin 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).
+*
+* - Units: An unqualified decimal value is interpreted as a value in
+* the system specified by the TimeFrame's System attribute, in the
+* units given by the TimeFrame's Unit attribute. Alternatively, an
+* appropriate unit string can be appended to the end of the floating
+* point value ("123.4 d" for example), in which case the supplied value
+* is scaled into the units specified by the Unit attribute.
+*
+* - 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 TimeOrigin values, the returned formatted floating
+* point value represents a value in the TimeFrame's System, in the unit
+* specified by the TimeFrame's Unit attribute.
+
+* Applicability:
+* TimeFrame
+* All TimeFrames have this attribute.
+
+*att--
+*/
+/* The time origin, stored internally in the default units associated
+ with the current System value. Clear the TimeOrigin value by setting it
+ to AST__BAD, which gives 0.0 as the default value. Any value is acceptable. */
+astMAKE_CLEAR(TimeFrame,TimeOrigin,timeorigin,AST__BAD)
+astMAKE_GET(TimeFrame,TimeOrigin,double,0.0,((this->timeorigin!=AST__BAD)?this->timeorigin:0.0))
+astMAKE_SET(TimeFrame,TimeOrigin,double,timeorigin,value)
+astMAKE_TEST(TimeFrame,TimeOrigin,( this->timeorigin != AST__BAD ))
+
+/*
+*att++
+* Name:
+* LTOffset
+
+* Purpose:
+* The offset from UTC to Local Time, in hours.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Floating point.
+
+* Description:
+* This specifies the offset from UTC to Local Time, in hours (fractional
+* hours can be supplied). It is positive for time zones east of Greenwich.
+* AST uses the figure as given, without making any attempt to correct for
+* daylight saving. The default value is zero.
+
+* Applicability:
+* TimeFrame
+* All TimeFrames have this attribute.
+
+*att--
+*/
+astMAKE_CLEAR(TimeFrame,LTOffset,ltoffset,AST__BAD)
+astMAKE_GET(TimeFrame,LTOffset,double,0.0,((this->ltoffset!=AST__BAD)?this->ltoffset:0.0))
+astMAKE_SET(TimeFrame,LTOffset,double,ltoffset,value)
+astMAKE_TEST(TimeFrame,LTOffset,( this->ltoffset != AST__BAD ))
+
+/*
+*att++
+* Name:
+* AlignTimeScale
+
+* Purpose:
+* Time scale to use when aligning TimeFrames.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute controls how a TimeFrame 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)
+* TimeFrame. It identifies the time scale in which alignment is
+* to occur. See the TimeScale attribute for a desription of the values
+* which may be assigned to this attribute. The default AlignTimeScale
+* value depends on the current value of TimeScale: if TimeScale is
+* UT1, GMST, LMST or LAST, the default for AlignTimeScale is UT1, for all
+* other TimeScales the default is TAI.
+*
+c When astFindFrame or astConvert is used on two TimeFrames (potentially
+f When AST_FindFrame or AST_CONVERT is used on two TimeFrames (potentially
+* describing different time coordinate systems), it returns a Mapping
+* which can be used to transform a position in one TimeFrame into the
+* corresponding position in the other. The Mapping is made up of the
+* following steps in the indicated order:
+*
+* - Map values from the system used by the target (MJD, JD, etc) to the
+* system specified by the AlignSystem attribute.
+*
+* - Map these values from the target's time scale to the time scale
+* specified by the AlignTimeScale attribute.
+*
+* - Map these values from the time scale specified by the AlignTimeScale
+* attribute, to the template's time scale.
+*
+* - Map these values from the system specified by the AlignSystem
+* attribute, to the system used by the template.
+
+* Applicability:
+* TimeFrame
+* All TimeFrames have this attribute.
+
+*att--
+*/
+astMAKE_TEST(TimeFrame,AlignTimeScale,( this->aligntimescale != AST__BADTS ))
+astMAKE_CLEAR(TimeFrame,AlignTimeScale,aligntimescale,AST__BADTS)
+astMAKE_SET(TimeFrame,AlignTimeScale,AstTimeScaleType,aligntimescale,(
+ ( ( value >= FIRST_TS ) && ( value <= LAST_TS ) ) ?
+ value :
+ ( astError( AST__ATTIN, "%s(%s): Bad value (%d) "
+ "given for AlignTimeScale attribute.", status,
+ "astSetAlignTimeScale", astGetClass( this ), (int) value ),
+
+/* Leave the value unchanged on error. */
+ this->aligntimescale ) ) )
+
+/*
+*att++
+* Name:
+* TimeScale
+
+* Purpose:
+* Time scale.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute identifies the time scale to which the time axis values
+* of a TimeFrame refer, and may take any of the values listed in the
+* "Time Scales" section (below).
+*
+* The default TimeScale value depends on the current System value; if
+* the current TimeFrame system is "Besselian epoch" the default is
+* "TT", otherwise it is "TAI". Note, if the System attribute is set
+* so that the TimeFrame represents Besselian Epoch, then an error
+* will be reported if an attempt is made to set the TimeScale to
+* anything other than TT.
+*
+* Note, the supported time scales fall into two groups. The first group
+* containing UT1, GMST, LAST and LMST define time in terms of the
+* orientation of the earth. The second group (containing all the remaining
+* time scales) define time in terms of an atomic process. Since the rate of
+* rotation of the earth varies in an unpredictable way, conversion between
+* two timescales in different groups relies on a value being supplied for
+* the Dut1 attribute (defined by the parent Frame class). This attribute
+* specifies the difference between the UT1 and UTC time scales, in seconds,
+* and defaults to zero. See the documentation for the Dut1 attribute for
+* further details.
+
+* Applicability:
+* TimeFrame
+* All TimeFrames have this attribute.
+
+* Time Scales:
+* The TimeFrame class supports the following TimeScale values (all are
+* case-insensitive):
+*
+* - "TAI" - International Atomic Time
+* - "UTC" - Coordinated Universal Time
+* - "UT1" - Universal Time
+* - "GMST" - Greenwich Mean Sidereal Time
+* - "LAST" - Local Apparent Sidereal Time
+* - "LMST" - Local Mean Sidereal Time
+* - "TT" - Terrestrial Time
+* - "TDB" - Barycentric Dynamical Time
+* - "TCB" - Barycentric Coordinate Time
+* - "TCG" - Geocentric Coordinate Time
+* - "LT" - Local Time (the offset from UTC is given by attribute LTOffset)
+*
+* An very informative description of these and other time scales is
+* available at http://www.ucolick.org/~sla/leapsecs/timescales.html.
+
+* UTC Warnings:
+* UTC should ideally be expressed using separate hours, minutes and
+* seconds fields (or at least in seconds for a given date) if leap seconds
+* are to be taken into account. Since the TimeFrame class represents
+* each moment in time using a single floating point number (the axis value)
+* there will be an ambiguity during a leap second. Thus an error of up to
+* 1 second can result when using AST to convert a UTC time to another
+* time scale if the time occurs within a leap second. Leap seconds
+* occur at most twice a year, and are introduced to take account of
+* variation in the rotation of the earth. The most recent leap second
+* occurred on 1st January 1999. Although in the vast majority of cases
+* leap second ambiguities won't matter, there are potential problems in
+* on-line data acquisition systems and in critical applications involving
+* taking the difference between two times.
+
+*att--
+*/
+astMAKE_TEST(TimeFrame,TimeScale,( this->timescale != AST__BADTS ))
+
+/* Copy constructor. */
+/* ----------------- */
+
+/* Destructor. */
+/* ----------- */
+
+/* Dump function. */
+/* -------------- */
+static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
+/*
+* Name:
+* Dump
+
+* Purpose:
+* Dump function for TimeFrame 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 TimeFrame class to an output Channel.
+
+* Parameters:
+* this
+* Pointer to the TimeFrame whose data are being written.
+* channel
+* Pointer to the Channel to which the data are being written.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstTimeFrame *this; /* Pointer to the TimeFrame structure */
+ AstTimeScaleType ts; /* TimeScale attribute value */
+ const char *sval; /* Pointer to string value */
+ double dval; /* Double value */
+ int set; /* Attribute value set? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the TimeFrame structure. */
+ this = (AstTimeFrame *) this_object;
+
+/* Write out values representing the instance variables for the
+ TimeFrame 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. */
+
+/* TimeScale. */
+/* ---------- */
+ set = TestTimeScale( this, status );
+ ts = set ? GetTimeScale( this, status ) : astGetTimeScale( this );
+
+/* If set, convert explicitly to a string for the external
+ representation. */
+ sval = "";
+ if ( set ) {
+ if ( astOK ) {
+ sval = TimeScaleString( ts, status );
+
+/* Report an error if the TimeScale value was not recognised. */
+ if ( !sval ) {
+ astError( AST__SCSIN,
+ "%s(%s): Corrupt %s contains invalid time scale "
+ "identification code (%d).", status, "astWrite",
+ astGetClass( channel ), astGetClass( this ), (int) ts );
+ }
+ }
+
+/* If not set, use astGetAttrib which returns a string value using
+ (possibly over-ridden) methods. */
+ } else {
+ sval = astGetAttrib( this_object, "timescale" );
+ }
+
+/* Write out the value. */
+ astWriteString( channel, "TmScl", set, 1, sval, "Time scale" );
+
+/* AlignTimeScale. */
+/* --------------- */
+ set = TestAlignTimeScale( this, status );
+ ts = set ? GetAlignTimeScale( this, status ) : astGetAlignTimeScale( this );
+
+/* If set, convert explicitly to a string for the external representation. */
+ if ( set ) {
+ if ( astOK ) {
+ sval = TimeScaleString( ts, status );
+
+/* Report an error if the TimeScale value was not recognised. */
+ if ( !sval ) {
+ astError( AST__SCSIN,
+ "%s(%s): Corrupt %s contains invalid alignment time "
+ "scale identification code (%d).", status, "astWrite",
+ astGetClass( channel ), astGetClass( this ), (int) ts );
+ }
+ }
+
+/* If not set, use astGetAttrib which returns a string value using
+ (possibly over-ridden) methods. */
+ } else {
+ sval = astGetAttrib( this_object, "aligntimescale" );
+ }
+
+/* Write out the value. */
+ astWriteString( channel, "ATmScl", set, 0, sval, "Alignment time scale" );
+
+/* TimeOrigin. */
+/* ----------- */
+ set = TestTimeOrigin( this, status );
+ dval = set ? GetTimeOrigin( this, status ) : astGetTimeOrigin( this );
+ astWriteDouble( channel, "TmOrg", set, 0, dval, "Time offset" );
+
+/* LTOffset. */
+/* --------- */
+ set = TestLTOffset( this, status );
+ dval = set ? GetLTOffset( this, status ) : astGetLTOffset( this );
+ astWriteDouble( channel, "LTOff", set, 0, dval, "Local Time offset from UTC" );
+
+}
+
+/* Standard class functions. */
+/* ========================= */
+/* Implement the astIsATimeFrame and astCheckTimeFrame functions using the
+ macros defined for this purpose in the "object.h" header file. */
+astMAKE_ISA(TimeFrame,Frame)
+astMAKE_CHECK(TimeFrame)
+
+AstTimeFrame *astTimeFrame_( const char *options, int *status, ...) {
+/*
+*+
+* Name:
+* astTimeFrame
+
+* Purpose:
+* Create a TimeFrame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstTimeFrame *astTimeFrame( const char *options, int *status, ... )
+
+* Class Membership:
+* TimeFrame constructor.
+
+* Description:
+* This function creates a new TimeFrame and optionally initialises its
+* attributes.
+
+* Parameters:
+* options
+* Pointer to a null terminated string containing an optional
+* comma-separated list of attribute assignments to be used for
+* initialising the new TimeFrame. 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 TimeFrame.
+
+* 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 TimeFrame constructor which
+* is available via the protected interface to the TimeFrame class.
+* A public interface is provided by the astTimeFrameId_ function.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstMapping *um; /* Mapping from default to actual units */
+ AstTimeFrame *new; /* Pointer to new TimeFrame */
+ AstSystemType s; /* System */
+ const char *u; /* Units string */
+ va_list args; /* Variable argument list */
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Check the global status. */
+ if ( !astOK ) return NULL;
+
+/* Initialise the TimeFrame, allocating memory and initialising the virtual
+ function table as well if necessary. */
+ new = astInitTimeFrame( NULL, sizeof( AstTimeFrame ), !class_init,
+ &class_vtab, "TimeFrame" );
+
+/* 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 TimeFrame's attributes. */
+ va_start( args, status );
+ astVSet( new, options, NULL, args );
+ va_end( args );
+
+/* Check the Units are appropriate for the System. */
+ u = astGetUnit( new, 0 );
+ s = astGetSystem( new );
+ um = astUnitMapper( DefUnit( s, "astTimeFrame", "TimeFrame", status ),
+ u, NULL, NULL );
+ if( um ) {
+ um = astAnnul( um );
+ } else {
+ astError( AST__BADUN, "astTimeFrame: Inappropriate units (%s) "
+ "specified for a %s axis.", status, u, SystemLabel( s, status ) );
+ }
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return a pointer to the new TimeFrame. */
+ return new;
+}
+
+AstTimeFrame *astInitTimeFrame_( void *mem, size_t size, int init,
+ AstTimeFrameVtab *vtab, const char *name, int *status ) {
+/*
+*+
+* Name:
+* astInitTimeFrame
+
+* Purpose:
+* Initialise a TimeFrame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstTimeFrame *astInitTimeFrame( void *mem, size_t size, int init,
+* AstFrameVtab *vtab, const char *name )
+
+* Class Membership:
+* TimeFrame initialiser.
+
+* Description:
+* This function is provided for use by class implementations to
+* initialise a new TimeFrame object. It allocates memory (if
+* necessary) to accommodate the TimeFrame plus any additional data
+* associated with the derived class. It then initialises a
+* TimeFrame 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 TimeFrame at the start of the memory passed via the
+* "vtab" parameter.
+
+* Parameters:
+* mem
+* A pointer to the memory in which the TimeFrame is to be
+* created. This must be of sufficient size to accommodate the
+* TimeFrame data (sizeof(TimeFrame)) 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 TimeFrame (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 TimeFrame structure, so a valid value must be supplied
+* even if not required for allocating memory.
+* init
+* A logical flag indicating if the TimeFrame'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 TimeFrame.
+* name
+* Pointer to a constant null-terminated character string which
+* contains the name of the class to which the new object belongs
+* (it is this pointer value that will subsequently be returned by
+* the astGetClass method).
+
+* Returned Value:
+* A pointer to the new TimeFrame.
+
+* 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: */
+ AstTimeFrame *new; /* Pointer to the new TimeFrame */
+
+/* Check the global status. */
+ if ( !astOK ) return NULL;
+
+/* If necessary, initialise the virtual function table. */
+ if ( init ) astInitTimeFrameVtab( vtab, name );
+
+/* Initialise a 1D Frame structure (the parent class) as the first component
+ within the TimeFrame structure, allocating memory if necessary. */
+ new = (AstTimeFrame *) astInitFrame( mem, size, 0,
+ (AstFrameVtab *) vtab, name, 1 );
+
+ if ( astOK ) {
+
+/* Initialise the TimeFrame data. */
+/* ----------------------------- */
+/* Initialise all attributes to their "undefined" values. */
+ new->timeorigin = AST__BAD;
+ new->ltoffset = AST__BAD;
+ new->timescale = AST__BADTS;
+ new->aligntimescale = AST__BADTS;
+
+/* 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;
+}
+
+AstTimeFrame *astLoadTimeFrame_( void *mem, size_t size,
+ AstTimeFrameVtab *vtab,
+ const char *name, AstChannel *channel, int *status ) {
+/*
+*+
+* Name:
+* astLoadTimeFrame
+
+* Purpose:
+* Load a TimeFrame.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "timeframe.h"
+* AstTimeFrame *astLoadTimeFrame( void *mem, size_t size,
+* AstTimeFrameVtab *vtab,
+* const char *name, AstChannel *channel )
+
+* Class Membership:
+* TimeFrame loader.
+
+* Description:
+* This function is provided to load a new TimeFrame 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
+* TimeFrame structure in this memory, using data read from the
+* input Channel.
+
+* Parameters:
+* mem
+* A pointer to the memory into which the TimeFrame is to be
+* loaded. This must be of sufficient size to accommodate the
+* TimeFrame data (sizeof(TimeFrame)) 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 TimeFrame (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 TimeFrame 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(AstTimeFrame) is used instead.
+* vtab
+* Pointer to the start of the virtual function table to be
+* associated with the new TimeFrame. If this is NULL, a pointer
+* to the (static) virtual function table for the TimeFrame 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 "TimeFrame" is used instead.
+
+* Returned Value:
+* A pointer to the new TimeFrame.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstTimeFrame *new; /* Pointer to the new TimeFrame */
+ char *sval; /* Pointer to string value */
+ double obslat; /* Value for ObsLat attribute */
+ double obslon; /* Value for ObsLon attribute */
+
+/* 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 TimeFrame. In this case the
+ TimeFrame belongs to this class, so supply appropriate values to be
+ passed to the parent class loader (and its parent, etc.). */
+ if ( !vtab ) {
+ size = sizeof( AstTimeFrame );
+ vtab = &class_vtab;
+ name = "TimeFrame";
+
+/* If required, initialise the virtual function table for this class. */
+ if ( !class_init ) {
+ astInitTimeFrameVtab( 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 TimeFrame. */
+ new = astLoadFrame( mem, size, (AstFrameVtab *) vtab, name,
+ channel );
+ if ( astOK ) {
+
+/* Read input data. */
+/* ================ */
+/* Request the input Channel to read all the input data appropriate to
+ this class into the internal "values list". */
+ astReadClassData( channel, "TimeFrame" );
+
+/* 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. */
+
+/* TimeScale. */
+/* ---------- */
+/* Set the default and read the external representation as a string. */
+ new->timescale = AST__BADTS;
+ sval = astReadString( channel, "tmscl", NULL );
+
+/* If a value was read, convert from a string to a TimeScale code. */
+ if ( sval ) {
+ if ( astOK ) {
+ new->timescale = TimeScaleCode( sval, status );
+
+/* Report an error if the value wasn't recognised. */
+ if ( new->timescale == AST__BADTS ) {
+ astError( AST__ATTIN,
+ "astRead(%s): Invalid time scale description "
+ "\"%s\".", status, astGetClass( channel ), sval );
+ }
+ }
+
+/* Free the string value. */
+ sval = astFree( sval );
+ }
+
+/* AlignTimeScale. */
+/* --------------- */
+/* Set the default and read the external representation as a string. */
+ new->aligntimescale = AST__BADTS;
+ sval = astReadString( channel, "atmscl", NULL );
+
+/* If a value was read, convert from a string to a TimeScale code. */
+ if ( sval ) {
+ if ( astOK ) {
+ new->aligntimescale = TimeScaleCode( sval, status );
+
+/* Report an error if the value wasn't recognised. */
+ if ( new->aligntimescale == AST__BADTS ) {
+ astError( AST__ATTIN,
+ "astRead(%s): Invalid alignment time scale "
+ "description \"%s\".", status, astGetClass( channel ), sval );
+ }
+ }
+
+/* Free the string value. */
+ sval = astFree( sval );
+ }
+
+/* ClockLat. */
+/* --------- */
+/* Retained for backward compatibility with older versions of AST in
+ which TimeFrame had a ClockLat attribute (now ObsLat is used instead). */
+ if( !astTestObsLat( new ) ) {
+ obslat = astReadDouble( channel, "cllat", AST__BAD );
+ if ( obslat != AST__BAD ) astSetObsLat( new, obslat );
+ }
+
+/* ClockLon. */
+/* ------- */
+/* Retained for backward compatibility with older versions of AST in
+ which TimeFrame had a ClockLon attribute (now ObsLon is used instead). */
+ if( !astTestObsLon( new ) ) {
+ obslon = astReadDouble( channel, "cllon", AST__BAD );
+ if ( obslon != AST__BAD ) astSetObsLon( new, obslon );
+ }
+
+/* TimeOrigin. */
+/* --------- */
+ new->timeorigin = astReadDouble( channel, "tmorg", AST__BAD );
+ if ( TestTimeOrigin( new, status ) ) SetTimeOrigin( new, new->timeorigin, status );
+
+/* LTOffset. */
+/* --------- */
+ new->ltoffset = astReadDouble( channel, "ltoff", AST__BAD );
+ if ( TestLTOffset( new, status ) ) SetLTOffset( new, new->ltoffset, status );
+
+/* If an error occurred, clean up by deleting the new TimeFrame. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return the new TimeFrame pointer. */
+ return new;
+}
+
+/* Virtual function interfaces. */
+/* ============================ */
+/* These provide the external interface to the virtual functions defined by
+ this class. Each simply checks the global error status and then locates and
+ executes the appropriate member function, using the function pointer stored
+ in the object's virtual function table (this pointer is located using the
+ astMEMBER macro defined in "object.h").
+
+ Note that the member function may not be the one defined here, as it may
+ have been over-ridden by a derived class. However, it should still have the
+ same interface. */
+
+void astSetTimeScale_( AstTimeFrame *this, AstTimeScaleType value, int *status ){
+ if ( !astOK ) return;
+ (**astMEMBER(this,TimeFrame,SetTimeScale))(this,value, status );
+}
+
+void astClearTimeScale_( AstTimeFrame *this, int *status ){
+ if ( !astOK ) return;
+ (**astMEMBER(this,TimeFrame,ClearTimeScale))(this, status );
+}
+
+AstTimeScaleType astGetAlignTimeScale_( AstTimeFrame *this, int *status ) {
+ if ( !astOK ) return AST__BADTS;
+ return (**astMEMBER(this,TimeFrame,GetAlignTimeScale))(this, status );
+}
+
+AstTimeScaleType astGetTimeScale_( AstTimeFrame *this, int *status ) {
+ if ( !astOK ) return AST__BADTS;
+ return (**astMEMBER(this,TimeFrame,GetTimeScale))(this, status );
+}
+
+double astCurrentTime_( AstTimeFrame *this, int *status ){
+ if ( !astOK ) return AST__BAD;
+ return (**astMEMBER(this,TimeFrame,CurrentTime))(this, status );
+}
+
+
+
+/* Special public interface functions. */
+/* =================================== */
+/* These provide the public interface to certain special functions
+ whose public interface cannot be handled using macros (such as
+ astINVOKE) alone. In general, they are named after the
+ corresponding protected version of the function, but with "Id"
+ appended to the name. */
+
+/* Public Interface Function Prototypes. */
+/* ------------------------------------- */
+/* The following functions have public prototypes only (i.e. no
+ protected prototypes), so we must provide local prototypes for use
+ within this module. */
+AstTimeFrame *astTimeFrameId_( const char *, ... );
+
+/* Special interface function implementations. */
+/* ------------------------------------------- */
+AstTimeFrame *astTimeFrameId_( const char *options, ... ) {
+/*
+*++
+* Name:
+c astTimeFrame
+f AST_TIMEFRAME
+
+* Purpose:
+* Create a TimeFrame.
+
+* Type:
+* Public function.
+
+* Synopsis:
+c #include "timeframe.h"
+c AstTimeFrame *astTimeFrame( const char *options, ... )
+f RESULT = AST_TIMEFRAME( OPTIONS, STATUS )
+
+* Class Membership:
+* TimeFrame constructor.
+
+* Description:
+* This function creates a new TimeFrame and optionally initialises
+* its attributes.
+*
+* A TimeFrame is a specialised form of one-dimensional Frame which
+* represents various coordinate systems used to describe positions in
+* time.
+*
+* A TimeFrame represents a moment in time as either an Modified Julian
+* Date (MJD), a Julian Date (JD), a Besselian epoch or a Julian epoch,
+* as determined by the System attribute. Optionally, a zero point can be
+* specified (using attribute TimeOrigin) which results in the TimeFrame
+* representing time offsets from the specified zero point.
+*
+* Even though JD and MJD are defined as being in units of days, the
+* TimeFrame class allows other units to be used (via the Unit attribute)
+* on the basis of simple scalings (60 seconds = 1 minute, 60 minutes = 1
+* hour, 24 hours = 1 day, 365.25 days = 1 year). Likewise, Julian epochs
+* can be described in units other than the usual years. Besselian epoch
+* are always represented in units of (tropical) years.
+*
+* The TimeScale attribute allows the time scale to be specified (that
+* is, the physical proces used to define the rate of flow of time).
+* MJD, JD and Julian epoch can be used to represent a time in any
+* supported time scale. However, Besselian epoch may only be used with the
+* "TT" (Terrestrial Time) time scale. The list of supported time scales
+* includes universal time and siderial time. Strictly, these represent
+* angles rather than time scales, but are included in the list since
+* they are in common use and are often thought of as time scales.
+*
+* When a time value is formatted it can be formated either as a simple
+* floating point value, or as a Gregorian date (see the Format
+* attribute).
+
+* Parameters:
+c options
+f OPTIONS = CHARACTER * ( * ) (Given)
+c Pointer to a null-terminated string containing an optional
+c comma-separated list of attribute assignments to be used for
+c initialising the new TimeFrame. 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 TimeFrame. 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 astTimeFrame()
+f AST_TIMEFRAME = INTEGER
+* A pointer to the new TimeFrame.
+
+* Notes:
+* - When conversion between two TimeFrames is requested (as when
+c supplying TimeFrames to astConvert),
+f supplying TimeFrames AST_CONVERT),
+* account will be taken of the nature of the time coordinate systems
+* they represent, together with any qualifying time scale, offset,
+* unit, etc. The AlignSystem and AlignTimeScale attributes will also be
+* taken into account.
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+*--
+
+* Implementation Notes:
+* - This function implements the external (public) interface to
+* the astTimeFrame constructor function. It returns an ID value
+* (instead of a true C pointer) to external users, and must be
+* provided because astTimeFrame_ 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 astTimeFrame_ directly, so it must be a
+* re-implementation of it in all respects, except for the final
+* conversion of the result to an ID value.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstMapping *um; /* Mapping from default to actual units */
+ AstTimeFrame *new; /* Pointer to new TimeFrame */
+ AstSystemType s; /* System */
+ const char *u; /* Units string */
+ va_list args; /* Variable argument list */
+
+ int *status; /* Pointer to inherited status value */
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Get a pointer to the inherited status value. */
+ status = astGetStatusPtr;
+
+/* Check the global status. */
+ if ( !astOK ) return NULL;
+
+/* Initialise the TimeFrame, allocating memory and initialising the virtual
+ function table as well if necessary. */
+ new = astInitTimeFrame( NULL, sizeof( AstTimeFrame ), !class_init,
+ &class_vtab, "TimeFrame" );
+
+/* 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 TimeFrame's attributes. */
+ va_start( args, options );
+ astVSet( new, options, NULL, args );
+ va_end( args );
+
+/* Check the Units are appropriate for the System. */
+ u = astGetUnit( new, 0 );
+ s = astGetSystem( new );
+ um = astUnitMapper( DefUnit( s, "astTimeFrame", "TimeFrame", status ),
+ u, NULL, NULL );
+ if( um ) {
+ um = astAnnul( um );
+ } else {
+ astError( AST__BADUN, "astTimeFrame: Inappropriate units (%s) "
+ "specified for a %s axis.", status, u, SystemLabel( s, status ) );
+ }
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return an ID value for the new TimeFrame. */
+ return astMakeId( new );
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+