diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2019-05-10 18:45:23 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2019-05-10 18:45:23 (GMT) |
commit | 0b1addf5643c828955a6add53f2a4f7a7a813e41 (patch) | |
tree | 94fe32a76399be787746c3c403cca2076a253e29 /ast/timeframe.c | |
parent | 75fab9d80911f74aaab738fa9ab8a4f9b0f57a6b (diff) | |
download | blt-0b1addf5643c828955a6add53f2a4f7a7a813e41.zip blt-0b1addf5643c828955a6add53f2a4f7a7a813e41.tar.gz blt-0b1addf5643c828955a6add53f2a4f7a7a813e41.tar.bz2 |
upgrade ast 8.7.1
Diffstat (limited to 'ast/timeframe.c')
-rw-r--r-- | ast/timeframe.c | 7530 |
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 ); +} + + + + + + + + + + + + + + + + + + + + |