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/specframe.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/specframe.c')
-rw-r--r-- | ast/specframe.c | 7437 |
1 files changed, 7437 insertions, 0 deletions
diff --git a/ast/specframe.c b/ast/specframe.c new file mode 100644 index 0000000..482f1d8 --- /dev/null +++ b/ast/specframe.c @@ -0,0 +1,7437 @@ +/* +*class++ +* Name: +* SpecFrame + +* Purpose: +* Spectral coordinate system description. + +* Constructor Function: +c astSpecFrame +f AST_SPECFRAME + +* Description: +* A SpecFrame is a specialised form of one-dimensional Frame which +* represents various coordinate systems used to describe positions within +* an electro-magnetic spectrum. The particular coordinate system to be +* used is specified by setting the SpecFrame's System attribute (the +* default is wavelength) qualified, as necessary, by other attributes +* such as the rest frequency, the standard of rest, the epoch of +* observation, units, etc (see the description of the System attribute +* for details). +* +* By setting a value for thr SpecOrigin attribute, a SpecFrame can be made +* to represent offsets from a given spectral position, rather than absolute +* spectral values. + +* Inheritance: +* The SpecFrame class inherits from the Frame class. + +* Attributes: +* In addition to those attributes common to all Frames, every +* SpecFrame also has the following attributes: +* +* - AlignSpecOffset: Align SpecFrames using the offset coordinate system? +* - AlignStdOfRest: Standard of rest in which to align SpecFrames +* - RefDec: Declination of the source (FK5 J2000) +* - RefRA: Right ascension of the source (FK5 J2000) +* - RestFreq: Rest frequency +* - SourceSys: Source velocity spectral system +* - SourceVel: Source velocity +* - SourceVRF: Source velocity rest frame +* - SpecOrigin: The zero point for SpecFrame axis values +* - StdOfRest: Standard of rest +* +* Several of the Frame attributes inherited by the SpecFrame class +* refer to a specific axis of the Frame (for instance Unit(axis), +* Label(axis), etc). Since a SpecFrame 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 SpecFrames: +f In addition to those routines applicable to all Frames, the +f following routines may also be applied to all SpecFrames: +* +c - astSetRefPos: Set reference position in any celestial system +f - AST_SETREFPOS: Set reference position in any celestial system +c - astGetRefPos: Get reference position in any celestial system +f - AST_GETREFPOS: Get reference position in any celestial system + +* 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: +* DSB: David S. Berry (Starlink) + +* History: +* 4-NOV-2002 (DSB): +* Original version. +* 2-FEB-2005 (DSB): +* - Avoid using astStore to allocate more storage than is supplied +* in the "data" pointer. This can cause access violations since +* astStore will then read beyond the end of the "data" area. +* 22-MAR-2005 (DSB): +* - Re-structure MakeSpecMapping in order to avoid unnecessary +* access to SpecFrame attributes which may not be set, and to +* check that all required attributes have been set if UseDefs is +* zero. +* 23-MAR-2005 (DSB): +* - Added missing rest frames to SorEqual. +* 12-AUG-2005 (DSB): +* - Remove GeoLon and GeoLat attributes. Use the new ObsLon and +* ObsLat attributes in the parent Frame class instead. Note, for +* backward compatibility the public attribute accessors and the +* astLoadSpecFrame functions still recogonise GeoLon and GeoLat, +* but use the ObsLat/ObsLon attributes internally. +* 14-FEB-2006 (DSB): +* Override astGetObjSize. +* 1-MAR-2006 (DSB): +* Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM. +* 6-OCT-2006 (DSB): +* Guard against annulling null pointers in subFrame. +* 18-OCT-2006 (DSB): +* Added SpecOrigin and AlignSpecOffset attributes. +* 23-OCT-2006 (DSB): +* Fix memory leak caused by addition of SpecOrigin and AlignSpecOffset +* attributes. +* 15-NOV-2006 (DSB): +* Only write out SpecOrigin if it is not bad. +* 8-JAN-2006 (DSB): +* - SubFrame: Copy the SourceSystem and SourceStdOfRest attributes +* to the System and StdOfRest attributes of the "align_frm" +* SpecFrame before calling MakeSpecMapping. Previously, the +* values assigned to SourceSystem and SourceStdOfRest were +* ignored, and alignment was always performed in the templates System +* and StdOfRest. +* - MakeSpecMapping: Correct logic used to decide if steps 2 and 7 +* can be cancelled. +* - OriginSystem: Clear the AlignSpecOffset attributes before +* finding the Mapping between the old and new Systems. +* 16-JAN-2006 (DSB): +* Fix bug in Dump that caused SrcVRF not to be written out. +* 31-JAN-2007 (DSB): +* Modified so that a SpecFrame can be used as a template to find a +* SpecFrame contained within a CmpFrame. This involves changes in +* Match and the removal of the local versions of SetMaxAxes and +* SetMinAxes. +* 8-AUG-2007 (DSB): +* Changed Overlay to avoid the possibility of making permanent +* changes to the supplied template Frame. +* 3-SEP-2007 (DSB): +* In SubFrame, since AlignSystem is extended by the SpecFrame class +* it needs to be cleared before invoking the parent SubFrame +* method in cases where the result Frame is not a SkyFrame. +* 2-OCT-2007 (DSB): +* In Overlay, clear AlignSystem as well as System before calling +* the parent overlay method. +* 4-SEP-2009 (DSB): +* In MakeSpecMapping, in order to produce alignment that is not +* affected by the epoch or reference position, make the alignment +* frame adapt to the epoch and reference position of the target +* and result Frames. +* 14-SEP-2009 (DSB): +* In MakeSpecMapping, extend the 4-SEP-2009 fix to cover other +* attributes that define the available rest frames (e.g. +* SourceVRF, SourceVel, ObsLat, ObsLon, ObsAlt). +* 16-SEP-2009 (DSB): +* In MakeSpecMapping, retain the original alignment frame attribute +* values if we are restoring the integrity of a FrameSet. +* 29-APR-2011 (DSB): +* Prevent astFindFrame from matching a subclass template against a +* superclass target. +*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 SpecFrame + +/* Define the first and last acceptable System values. */ +#define FIRST_SYSTEM AST__FREQ +#define LAST_SYSTEM AST__VREL + +/* Define the first and last acceptable StdOfRest values. */ +#define FIRST_SOR AST__TPSOR +#define LAST_SOR AST__SCSOR + +/* The supported spectral coordinate systems fall into two groups; + "relative", and "absolute". The relative systems define each axis + value with respect to the rest frequency, whereas the absolute systems + have axis values which do not depend on the rest frequency. Define a + macro which returns one if the specified system is absolute, and zero + otherwise. */ +#define ABS_SYSTEM(sys) \ + ( ( sys == AST__ENERGY || \ + sys == AST__WAVENUM || \ + sys == AST__WAVELEN || \ + sys == AST__AIRWAVE || \ + sys == AST__FREQ ) ? 1 : 0 ) + +/* Define other numerical constants for use in this module. */ +#define GETATTRIB_BUFF_LEN 50 +#define GETLABEL_BUFF_LEN 200 +#define GETSYMBOL_BUFF_LEN 20 +#define GETTITLE_BUFF_LEN 200 + +/* 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 "specmap.h" /* Spectral coordinate Mappings */ +#include "frame.h" /* Parent Frame class */ +#include "skyframe.h" /* Celestial coordinate frames */ +#include "specframe.h" /* Interface definition for this class */ +#include "mapping.h" /* Coordinate Mappings */ +#include "cmpmap.h" /* Compound Mappings */ +#include "unitmap.h" /* Unit Mappings */ +#include "pal.h" /* SlaLib interface */ +#include "shiftmap.h" /* Change of origin */ + +/* 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 <limits.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 int (* parent_getobjsize)( AstObject *, int * ); +static AstSystemType (* parent_getalignsystem)( AstFrame *, int * ); +static AstSystemType (* parent_getsystem)( AstFrame *, int * ); +static const char *(* parent_getattrib)( AstObject *, const char *, int * ); +static const char *(* parent_getdomain)( AstFrame *, int * ); +static const char *(* parent_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 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 void (* parent_setunit)( AstFrame *, int, const char *, int * ); +static void (* parent_clearattrib)( AstObject *, const char *, 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_clearsystem)( AstFrame *, int * ); +static void (* parent_clearunit)( AstFrame *, int, int * ); + +/* Define a variable to hold a SkyFrame which will be used for formatting + and unformatting sky positions, etc. */ +static AstSkyFrame *skyframe; + +/* Define macros for accessing each item of thread specific global data. */ +#ifdef THREAD_SAFE + +/* Define how to initialise thread-specific globals. */ +#define GLOBAL_inits \ + globals->Class_Init = 0; \ + globals->GetAttrib_Buff[ 0 ] = 0; \ + globals->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(SpecFrame) + +/* Define macros for accessing each item of thread specific global data. */ +#define class_init astGLOBAL(SpecFrame,Class_Init) +#define class_vtab astGLOBAL(SpecFrame,Class_Vtab) +#define getattrib_buff astGLOBAL(SpecFrame,GetAttrib_Buff) +#define getlabel_buff astGLOBAL(SpecFrame,GetLabel_Buff) +#define getsymbol_buff astGLOBAL(SpecFrame,GetSymbol_Buff) +#define gettitle_buff astGLOBAL(SpecFrame,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 + +/* Buffer returned by GetAttrib. */ +static char getattrib_buff[ 51 ]; + +/* Default GetLabel string buffer */ +static char getlabel_buff[ 201 ]; + +/* Default GetSymbol buffer */ +static char getsymbol_buff[ 21 ]; + +/* Default Title string buffer */ +static char gettitle_buff[ 201 ]; + + +/* Define the class virtual function table and its initialisation flag + as static variables. */ +static AstSpecFrameVtab 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 AstStdOfRestType StdOfRestCode( const char *, int * ); +static int GetObjSize( AstObject *, int * ); +static AstSystemType GetAlignSystem( AstFrame *, int * ); +static AstSystemType SystemCode( AstFrame *, const char *, int * ); +static AstSystemType ValidateSystem( AstFrame *, AstSystemType, const char *, int * ); +static const char *DefUnit( AstSystemType, const char *, const char *, 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 *SpecMapUnit( AstSystemType, const char *, const char *, int * ); +static const char *StdOfRestString( AstStdOfRestType, int * ); +static const char *SystemLabel( AstSystemType, int * ); +static const char *SystemString( AstFrame *, AstSystemType, int * ); +static double ConvertSourceVel( AstSpecFrame *, AstStdOfRestType, AstSystemType, int * ); +static int EqualSor( AstSpecFrame *, AstSpecFrame *, int * ); +static int GetActiveUnit( AstFrame *, int * ); +static int MakeSpecMapping( AstSpecFrame *, AstSpecFrame *, AstSpecFrame *, int, AstMapping **, int * ); +static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); +static int SorConvert( AstSpecFrame *, AstSpecFrame *, AstSpecMap *, int * ); +static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); +static int TestActiveUnit( AstFrame *, int * ); +static void ClearUnit( AstFrame *, int, int * ); +static void Copy( const AstObject *, AstObject *, int * ); +static void Delete( AstObject *, int * ); +static void Dump( AstObject *, AstChannel *, int * ); +static void GetRefPos( AstSpecFrame *, AstSkyFrame *, double *, double *, int * ); +static void Overlay( AstFrame *, const int *, AstFrame *, int * ); +static void SetRefPos( AstSpecFrame *, AstSkyFrame *, double, double, int * ); +static void SetUnit( AstFrame *, int, const char *, int * ); +static void VerifyAttrs( AstSpecFrame *, const char *, const char *, const char *, int * ); +static double ToUnits( AstSpecFrame *, const char *, double, const char *, int * ); +static void OriginStdOfRest( AstSpecFrame *, AstStdOfRestType, const char *, int * ); +static void OriginSystem( AstSpecFrame *, AstSystemType, const char *, int * ); + +static AstSystemType GetSystem( AstFrame *, int * ); +static void SetSystem( AstFrame *, AstSystemType, int * ); +static void ClearSystem( AstFrame *, 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 AstStdOfRestType GetAlignStdOfRest( AstSpecFrame *, int * ); +static int TestAlignStdOfRest( AstSpecFrame *, int * ); +static void ClearAlignStdOfRest( AstSpecFrame *, int * ); +static void SetAlignStdOfRest( AstSpecFrame *, AstStdOfRestType, int * ); + +static AstStdOfRestType GetStdOfRest( AstSpecFrame *, int * ); +static int TestStdOfRest( AstSpecFrame *, int * ); +static void ClearStdOfRest( AstSpecFrame *, int * ); +static void SetStdOfRest( AstSpecFrame *, AstStdOfRestType, int * ); + +static double GetRestFreq( AstSpecFrame *, int * ); +static int TestRestFreq( AstSpecFrame *, int * ); +static void ClearRestFreq( AstSpecFrame *, int * ); +static void SetRestFreq( AstSpecFrame *, double, int * ); + +static double GetSourceVel( AstSpecFrame *, int * ); +static int TestSourceVel( AstSpecFrame *, int * ); +static void ClearSourceVel( AstSpecFrame *, int * ); +static void SetSourceVel( AstSpecFrame *, double, int * ); + +static double GetRefRA( AstSpecFrame *, int * ); +static int TestRefRA( AstSpecFrame *, int * ); +static void ClearRefRA( AstSpecFrame *, int * ); +static void SetRefRA( AstSpecFrame *, double, int * ); + +static double GetRefDec( AstSpecFrame *, int * ); +static int TestRefDec( AstSpecFrame *, int * ); +static void ClearRefDec( AstSpecFrame *, int * ); +static void SetRefDec( AstSpecFrame *, double, int * ); + +static AstStdOfRestType GetSourceVRF( AstSpecFrame *, int * ); +static int TestSourceVRF( AstSpecFrame *, int * ); +static void ClearSourceVRF( AstSpecFrame *, int * ); +static void SetSourceVRF( AstSpecFrame *, AstStdOfRestType, int * ); + +static AstSystemType GetSourceSys( AstSpecFrame *, int * ); +static int TestSourceSys( AstSpecFrame *, int * ); +static void ClearSourceSys( AstSpecFrame *, int * ); +static void SetSourceSys( AstSpecFrame *, AstSystemType, int * ); + +static double GetSpecOrigin( AstSpecFrame *, int * ); +static int TestSpecOrigin( AstSpecFrame *, int * ); +static void ClearSpecOrigin( AstSpecFrame *, int * ); +static void SetSpecOrigin( AstSpecFrame *, double, int * ); +static double GetSpecOriginCur( AstSpecFrame *, int * ); + +static int GetAlignSpecOffset( AstSpecFrame *, int * ); +static int TestAlignSpecOffset( AstSpecFrame *, int * ); +static void SetAlignSpecOffset( AstSpecFrame *, int, int * ); +static void ClearAlignSpecOffset( AstSpecFrame *, int * ); + +/* Member functions. */ +/* ================= */ + +static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* ClearAttrib + +* Purpose: +* Clear an attribute value for a SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void ClearAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* SpecFrame 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 +* SpecFrame, so that the default value will subsequently be used. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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: */ + AstSpecFrame *this; /* Pointer to the SpecFrame 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 SpecFrame structure. */ + this = (AstSpecFrame *) 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 + SpecFrame 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 ); + } + +/* AlignStdOfRest. */ +/* --------------- */ + } else if ( !strcmp( attrib, "alignstdofrest" ) ) { + astClearAlignStdOfRest( this ); + +/* GeoLat. */ +/* ------- */ +/* Retained for backward compatibility with older versions of AST in which + SpecFrame had GeoLon/Lat attributes (now ObsLon/Lat are used instead). */ + } else if ( !strcmp( attrib, "geolat" ) ) { + astClearAttrib( this, "obslat" ); + +/* GeoLon. */ +/* ------- */ + } else if ( !strcmp( attrib, "geolon" ) ) { + astClearAttrib( this, "obslon" ); + +/* RefDec. */ +/* ---------- */ + } else if ( !strcmp( attrib, "refdec" ) ) { + astClearRefDec( this ); + +/* RefRA. */ +/* --------- */ + } else if ( !strcmp( attrib, "refra" ) ) { + astClearRefRA( this ); + +/* RestFreq. */ +/* --------- */ + } else if ( !strcmp( attrib, "restfreq" ) ) { + astClearRestFreq( this ); + +/* SourceVel. */ +/* ---------- */ + } else if ( !strcmp( attrib, "sourcevel" ) ) { + astClearSourceVel( this ); + +/* SpecOrigin. */ +/* ---------- */ + } else if ( !strcmp( attrib, "specorigin" ) ) { + astClearSpecOrigin( this ); + +/* AlignSpecOffset. */ +/* ---------------- */ + } else if ( !strcmp( attrib, "alignspecoffset" ) ) { + astClearAlignSpecOffset( this ); + +/* SourceVRF */ +/* --------- */ + } else if ( !strcmp( attrib, "sourcevrf" ) ) { + astClearSourceVRF( this ); + +/* SourceSys */ +/* --------- */ + } else if ( !strcmp( attrib, "sourcesys" ) ) { + astClearSourceSys( this ); + +/* StdOfRest. */ +/* ---------- */ + } else if ( !strcmp( attrib, "stdofrest" ) ) { + astClearStdOfRest( 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 SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void ClearSystem( AstFrame *this_frame, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the astClearSystem protected +* method inherited from the Frame class). + +* Description: +* This function clears the System attribute for a SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstSpecFrame *this; /* Pointer to SpecFrame structure */ + AstSystemType newsys; /* System after clearing */ + AstSystemType oldsys; /* System before clearing */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) 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 ); + +/* Get the default System. */ + newsys = astGetSystem( this_frame ); + +/* If the system has actually changed. */ + if( newsys != oldsys ) { + +/* Changing the System value will in general require the Units to change + as well. If the used has previously specified the units to be used with + the new system, then re-instate them (they are stored in the "usedunits" + array in the SpecFrame structure). Otherwise, clear the units so that + the default units will eb used with the new System. */ + if( (int) newsys < this->nuunits && this->usedunits && + this->usedunits[ (int) newsys ] ) { + astSetUnit( this, 0, this->usedunits[ (int) newsys ] ); + } else { + astClearUnit( this, 0 ); + } + +/* Also, clear all attributes which have system-specific defaults. */ + astClearLabel( this_frame, 0 ); + astClearSymbol( this_frame, 0 ); + astClearTitle( this_frame ); + +/* Modify the SpecOrigin value to use the new System */ + OriginSystem( this, oldsys, "astClearSystem", status ); + + } + +} + +static void ClearStdOfRest( AstSpecFrame *this, int *status ) { +/* +*+ +* Name: +* astClearStdOfRest + +* Purpose: +* Clear the StdOfRest attribute for a SpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "timeframe.h" +* void astClearStdOfRest( AstSpecFrame *this ) + +* Class Membership: +* SpecFrame virtual function + +* Description: +* This function clears the StdOfRest attribute for a SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. + +*- +*/ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Modify the SpecOrigin value stored in the SpecFrame structure to refer to the + default rest frame (heliocentric). */ + OriginStdOfRest( this, AST__HLSOR, "astClearStdOfRest", status ); + +/* Store a bad value for the standard of rest in the SpecFrame structure. */ + this->stdofrest = AST__BADSOR; +} + + +static void ClearUnit( AstFrame *this_frame, int axis, int *status ) { +/* +* Name: +* ClearUnit + +* Purpose: +* Clear the value of the Unit string for a SpecFrame's axis. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void ClearUnit( AstFrame *this_frame, int axis ) + +* Class Membership: +* SpecFrame member function (over-rides the astClearUnit method inherited +* from the Frame class). + +* Description: +* This function clears the Unit string for a specified axis of a +* SpecFrame. It also clears the UsedUnit item in the SpecFrame +* structure corresponding to the current System. + +* Parameters: +* this +* Pointer to the SpecFrame. +* axis +* The number of the axis (zero-based). +*/ + +/* Local Variables: */ + AstSpecFrame *this; /* Pointer to the SpecFrame structure */ + int system; /* The SpecFrame's System value */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) this_frame; + +/* Validate the axis index. */ + astValidateAxis( this, axis, 1, "astClearUnit" ); + +/* Clear the UsedUnit item for the current System, if current set. */ + system = (int) astGetSystem( this ); + if( system < this->nuunits && this->usedunits ) { + this->usedunits[ system ] = astFree( this->usedunits[ system ] ); + } + +/* Use the parent method to clear the Unit attribute of the axis. */ + (*parent_clearunit)( this_frame, axis, status ); +} + +static double ConvertSourceVel( AstSpecFrame *this, AstStdOfRestType newsor, + AstSystemType newsys, int *status ) { +/* +* Name: +* ConvertSourceVel + +* Purpose: +* Convert the SourceVel value to a specified rest frame and spectral +* system. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* double ConvertSourceVel( AstSpecFrame *this, AstStdOfRestType newsor, +* AstSystemType newsys, int *status ) + +* Class Membership: +* SpecFrame member function + +* Description: +* This function convert the SourceVel value to a specified rest frame +* and spectral system, and returns the new value. + +* Parameters: +* this +* Pointer to the SpecFrame. +* newsor +* The rest frame in which the source velocity is required. +* newsys +* The spectral system (AST__VREL or AST__REDSHIFT) in which the +* source velocity is required. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The converted source velocity (m/s), or redshift. + +* Notes: +* - This function returns zero if an error occurs. +*/ + +/* Local Variables: */ + AstSpecFrame *from; /* Pointer to a source SpecFrame */ + AstSpecFrame *to; /* Pointer to a destination SpecFrame */ + AstSpecMap *specmap; /* Pointer to a SpecMap */ + AstStdOfRestType sor; /* Standard of rest in which SourceVel is defined */ + AstSystemType sys; /* Spectral system in which SourceVel is defined */ + double ret; /* The returned value */ + double rf; /* Rest frequency (Hz) */ + double temp; /* Temporary storage */ + +/* Initialise */ + ret = 0.0; + +/* Check the global error status. */ + if ( !astOK ) return ret; + +/* Get the value of the SourceVel attribute. This will be a velocity in m/s + (relativistic, radio or optical), or unitless redshift or beta factor, + depending on the current value of SourceSys. */ + ret = astGetSourceVel( this ); + +/* Check it can be used (depends on whether a value has been set and + whether the UseDefs attribute is zero). */ + VerifyAttrs( this, "convert source velocity to a new standard of rest", + "SourceVel", "astMatch", status ); + +/* Get the rest frame and spectral system to which value refers. */ + sor = astGetSourceVRF( this ); + sys = astGetSourceSys( this ); + +/* If necessary, convert to the requested rest frame and spectral system. */ + if( sor != newsor || sys != newsys ) { + +/* Verify that usable value is available for the RestFreq attribute. An + error is reported if not. */ + VerifyAttrs( this, "convert source velocity to a new standard of rest", + "RestFreq", "astMatch", status ); + +/* Take two copies of the supplied SpecFrame and set their StdOfRest + attributes to the required values. */ + from = astCopy( this ); + astSetStdOfRest( from, sor ); + + to = astCopy( this ); + astSetStdOfRest( to, newsor ); + +/* Initialise a new SpecMap to describe the conversion. The new SpecMap + initially represents a UnitMap. */ + specmap = astSpecMap( 1, 0, "", status ); + +/* Add a conversion from the spectral system in which the SourceVEl value + is stored, to relativistic velocity. */ + if( sys == AST__VRADIO ) { + astSpecAdd( specmap, "VRTOVL", 0, NULL ); + + } else if( sys == AST__VOPTICAL ) { + astSpecAdd( specmap, "VOTOVL", 0, NULL ); + + } else if( sys == AST__REDSHIFT ) { + astSpecAdd( specmap, "ZOTOVL", 0, NULL ); + + } else if( sys == AST__BETA ) { + astSpecAdd( specmap, "BTTOVL", 0, NULL ); + } + +/* Add a conversion from velocity to frequency since SorConvert converts + frequencies. */ + rf = astGetRestFreq( this ); + astSpecAdd( specmap, "VLTOFR", 1, &rf ); + +/* Now add a conversion from frequency in the SourveVRF standard of rest to + frequency in the required rest frame. */ + SorConvert( from, to, specmap, status ); + +/* Add a conversion from frequency back to velocity. Note, the value of the + rest frequency does not affect the overall conversion. */ + astSpecAdd( specmap, "FRTOVL", 1, &rf ); + +/* Add a conversion from relativistic velocity to the required spectral + system, if needed. */ + if( newsys == AST__VRADIO ) { + astSpecAdd( specmap, "VLTOVR", 0, NULL ); + + } else if( newsys == AST__VOPTICAL ) { + astSpecAdd( specmap, "VLTOVO",0, NULL ); + + } else if( newsys == AST__REDSHIFT ) { + astSpecAdd( specmap, "VLTOZO",0, NULL ); + + } else if( newsys == AST__BETA ) { + astSpecAdd( specmap, "VLTOBT",0, NULL ); + } + +/* Use the SpecMap to convert the source velocity in the SourceVRF + standard of rest and SourceSys spectral system to the required rest + frame and spectral system. */ + temp = ret; + astTran1( specmap, 1, &temp, 1, &ret ); + +/* Free resources */ + specmap = astAnnul( specmap ); + to = astAnnul( to ); + from = astAnnul( from ); + } + +/* Return zero if an error has occurred. */ + if( !astOK ) ret = 0.0; + +/* Return the answer. */ + return ret; + +} + +static const char *DefUnit( AstSystemType system, const char *method, + const char *class, int *status ){ +/* +* Name: +* DefUnit + +* Purpose: +* Return the default units for a spectral coordinate system type. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *DefUnit( AstSystemType system, const char *method, +* const char *class, int *status ) + +* Class Membership: +* SpecFrame member function. + +* Description: +* This function returns a textual representation of the default +* units associated with the specified spectral coordinate system. + +* Parameters: +* system +* The spectral 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: +* As tring 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__FREQ ) { + result = "GHz"; + } else if( system == AST__ENERGY ) { + result = "J"; + } else if( system == AST__WAVENUM ) { + result = "1/m"; + } else if( system == AST__WAVELEN ) { + result = "Angstrom"; + } else if( system == AST__AIRWAVE ) { + result = "Angstrom"; + } else if( system == AST__VRADIO ) { + result = "km/s"; + } else if( system == AST__VOPTICAL ) { + result = "km/s"; + } else if( system == AST__REDSHIFT ) { + result = ""; + } else if( system == AST__BETA ) { + result = ""; + } else if( system == AST__VREL ) { + result = "km/s"; + +/* 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 EqualSor( AstSpecFrame *this, AstSpecFrame *that, int *status ) { +/* +* Name: +* EqualSor + +* Purpose: +* Do two SpecFrames use the same standard of rest? + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* int EqualSor( AstSpecFrame *this, AstSpecFrame *that, int *status ) + +* Class Membership: +* SpecFrame member function + +* Description: +* This function returns non-zero if the two supplied SpecFrames use +* the same standard of rest. + +* Parameters: +* this +* Pointer to the first SpecFrame. +* that +* Pointer to the second SpecFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Non-zero if the two SpecFrames use the same standard of rest. Zero +* otherwise. + +*/ + +/* Local Variables: */ + AstStdOfRestType sor; /* Standard of rest */ + int result; /* Value to return */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Initialise. */ + result = 1; + +/* Compare StdOfRest attributes. */ + sor = astGetStdOfRest( this ); + if( astGetStdOfRest( that ) != sor ) { + result = 0; + +/* If the standards of rest are equal we need to check the the attributes + which specify the precise rest frame. */ + } else { + +/* The reference RA and Dec need to be equal */ + if( !astEQUAL( astGetRefRA( this ), astGetRefRA( that ) ) || + !astEQUAL( astGetRefDec( this ), astGetRefDec( that ) ) ) { + result = 0; + +/* For source rest frame, the source velocities, rest frames and systems must + be equal */ + } else if( sor == AST__SCSOR ){ + if( !astEQUAL( astGetSourceVel( this ), astGetSourceVel( that ) ) || + astGetSourceVRF( this ) != astGetSourceVRF( that ) || + astGetSourceSys( this ) != astGetSourceSys( that ) ) { + result = 0; + } + +/* For geocentric, barycentric and heliocentric rest frames, the epochs must + be the same */ + } else if( sor == AST__GESOR || sor == AST__BYSOR || sor == AST__HLSOR ){ + if( !astEQUAL( astGetEpoch( this ), astGetEpoch( that ) ) ) result = 0; + +/* For topocentric rest frame, the epoch and position of the observer must be + the same */ + } else if( sor == AST__TPSOR ){ + if( !astEQUAL( astGetEpoch( this ), astGetEpoch( that ) ) || + !astEQUAL( astGetObsAlt( this ), astGetObsAlt( that ) ) || + !astEQUAL( astGetObsLon( this ), astGetObsLon( that ) ) || + !astEQUAL( astGetObsLat( this ), astGetObsLat( that ) ) ) result = 0; + + } else if( sor != AST__LKSOR && sor != AST__LDSOR && + sor != AST__GLSOR && sor != AST__LGSOR && astOK ) { + astError( AST__INTER, "SorEqual(SpecFrame): Function SorEqual " + "does not yet support rest frame %d (AST internal " + "programming error)", status, sor ); + } + } + +/* Return the result */ + return result; +} + +static int GetObjSize( AstObject *this_object, int *status ) { +/* +* Name: +* GetObjSize + +* Purpose: +* Return the in-memory size of an Object. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* int GetObjSize( AstObject *this, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the astGetObjSize protected +* method inherited from the parent class). + +* Description: +* This function returns the in-memory size of the supplied SpecFrame, +* in bytes. + +* Parameters: +* this +* Pointer to the SpecFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The Object size, in bytes. + +* Notes: +* - A value of zero will be returned if this function is invoked +* with the global status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + AstSpecFrame *this; /* Pointer to SpecFrame structure */ + int result; /* Result value to return */ + int i; + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointers to the SpecFrame structure. */ + this = (AstSpecFrame *) this_object; + +/* Invoke the GetObjSize method inherited from the parent class, and then + add on any components of the class structure defined by thsi class + which are stored in dynamically allocated memory. */ + result = (*parent_getobjsize)( this_object, status ); + if( this->usedunits ) { + for( i = 0; i < this->nuunits; i++ ) { + result += astTSizeOf( this->usedunits[ i ] ); + } + result += astTSizeOf( this->usedunits ); + } + +/* If an error occurred, clear the result value. */ + if ( !astOK ) result = 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 SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* int GetActiveUnit( AstFrame *this_frame, int *status ) + +* Class Membership: +* SpecFrame 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 +* SpecFrame, which is always 1. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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 SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *GetAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* SpecFrame 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 SpecFrame, formatted as a character string. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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 SpecFrame, 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 SpecFrame. A copy of the string should +* therefore be made if necessary. +* - A NULL pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Declare the thread specific global data */ + AstSpecFrame *this; /* Pointer to the SpecFrame structure */ + AstStdOfRestType sor; /* Standard of rest */ + AstSystemType sys; /* Spectral system */ + char *new_attrib; /* Pointer value to new attribute name */ + const char *result; /* Pointer value to return */ + double dval; /* Attribute value */ + int ival; /* 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 SpecFrame structure. */ + this = (AstSpecFrame *) this_object; + +/* Create an FK5 J2000 SkyFrame which will be used for formatting and + unformatting sky positions, etc. */ + LOCK_MUTEX2 + if( !skyframe ) { + astBeginPM; + skyframe = astSkyFrame( "system=FK5,equinox=J2000", status ); + astEndPM; + } + UNLOCK_MUTEX2 + +/* 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 + SpecFrame 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 ); + } + +/* AlignStdOfRest. */ +/* --------------- */ +/* Obtain the AlignStdOfRest code and convert to a string. */ + } else if ( !strcmp( attrib, "alignstdofrest" ) ) { + sor = astGetAlignStdOfRest( this ); + if ( astOK ) { + result = StdOfRestString( sor, status ); + +/* Report an error if the value was not recognised. */ + if ( !result ) { + astError( AST__SCSIN, + "astGetAttrib(%s): Corrupt %s contains invalid AlignStdOfRest " + "identification code (%d).", status, astGetClass( this ), + astGetClass( this ), (int) sor ); + } + } + +/* AlignSpecOffset */ +/* --------------- */ + } else if ( !strcmp( attrib, "alignspecoffset" ) ) { + ival = astGetAlignSpecOffset( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* GeoLat. */ +/* ------- */ +/* Retained for backward compatibility with older versions of AST in which + SpecFrame had GeoLon/Lat attributes (now ObsLon/Lat are used instead). */ + } else if ( !strcmp( attrib, "geolat" ) ) { + result = astGetAttrib( this, "obslat" ); + +/* GeoLon. */ +/* ------- */ + } else if ( !strcmp( attrib, "geolon" ) ) { + result = astGetAttrib( this, "obslon" ); + +/* RefDec. */ +/* ------- */ +/* Convert to a string using the SkyFrame Format method. */ + } else if ( !strcmp( attrib, "refdec" ) ) { + dval = astGetRefDec( this ); + if ( astOK ) { + result = astFormat( skyframe, 1, dval ); + } + +/* RefRA. */ +/* ------ */ +/* Convert to a string using the SkyFrame Format method. */ + } else if ( !strcmp( attrib, "refra" ) ) { + dval = astGetRefRA( this ); + if ( astOK ) { + result = astFormat( skyframe, 0, dval ); + } + +/* RestFreq. */ +/* --------- */ + } else if ( !strcmp( attrib, "restfreq" ) ) { + dval = astGetRestFreq( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval*1.0E-9 ); + result = getattrib_buff; + } + +/* SourceVel */ +/* --------- */ + } else if ( !strcmp( attrib, "sourcevel" ) ) { + dval = astGetSourceVel( this ); + if ( astOK ) { + +/* Convert from m/s to km/s if the SourceVel value is a velocity. . */ + if( astGetSourceSys( this ) == AST__VREL || + astGetSourceSys( this ) == AST__VRADIO || + astGetSourceSys( this ) == AST__VOPTICAL ) dval *= 1.0E-3; + +/* Format */ + (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval ); + result = getattrib_buff; + + } + +/* SpecOrigin. */ +/* ----------- */ + } else if ( !strcmp( attrib, "specorigin" ) ) { + dval = GetSpecOriginCur( this, status ); + if( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval ); + result = getattrib_buff; + } + + +/* SourceVRF */ +/* ----------*/ + } else if ( !strcmp( attrib, "sourcevrf" ) ) { + sor = astGetSourceVRF( this ); + if ( astOK ) { + result = StdOfRestString( sor, status ); + +/* Report an error if the value was not recognised. */ + if ( !result ) { + astError( AST__SCSIN, + "astGetAttrib(%s): Corrupt %s contains invalid SourceVRF " + "identification code (%d).", status, astGetClass( this ), + astGetClass( this ), (int) sor ); + } + } + +/* SourceSys */ +/* ----------*/ + } else if ( !strcmp( attrib, "sourcesys" ) ) { + sys = astGetSourceSys( this ); + if ( astOK ) { + result = SystemString( (AstFrame *) this, sys, status ); + +/* Report an error if the value was not recognised. */ + if ( !result ) { + astError( AST__SCSIN, + "astGetAttrib(%s): Corrupt %s contains invalid SourceSys " + "identification code (%d).", status, astGetClass( this ), + astGetClass( this ), (int) sys ); + } + } + +/* StdOfRest. */ +/* ---------- */ +/* Obtain the StdOfRest code and convert to a string. */ + } else if ( !strcmp( attrib, "stdofrest" ) ) { + sor = astGetStdOfRest( this ); + if ( astOK ) { + result = StdOfRestString( sor, status ); + +/* Report an error if the value was not recognised. */ + if ( !result ) { + astError( AST__SCSIN, + "astGetAttrib(%s): Corrupt %s contains invalid StdOfRest " + "identification code (%d).", status, astGetClass( this ), + astGetClass( this ), (int) sor ); + } + } + +/* 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 const char *GetDomain( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetDomain + +* Purpose: +* Obtain a pointer to the Domain attribute string for a SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *GetDomain( AstFrame *this, int *status ) + +* Class Membership: +* SpecFrame 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 SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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 SpecFrame. +* - 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: */ + AstSpecFrame *this; /* Pointer to SpecFrame 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 SpecFrame structure. */ + this = (AstSpecFrame *) 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 = "SPECTRUM"; + } + +/* Return the result. */ + return result; +} + +static const char *GetLabel( AstFrame *this, int axis, int *status ) { +/* +* Name: +* GetLabel + +* Purpose: +* Access the Label string for a SpecFrame axis. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *GetLabel( AstFrame *this, int axis, int *status ) + +* Class Membership: +* SpecFrame 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 SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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 spectral coordinates */ + char *new_lab; /* Modified label string */ + const char *result; /* Pointer to label string */ + double orig; /* Spec origin */ + +/* 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, identify the spectral coordinate system described by the + SpecFrame. */ + } 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 SpecOrigin has been specified, include the offset now. */ + orig = GetSpecOriginCur( (AstSpecFrame *) this, status ); + if( orig != 0.0 ) { + sprintf( getlabel_buff + strlen( getlabel_buff ), " offset from %s", + astFormat( this, 0, orig ) ); + } + +/* 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 "Hz" and the actual units is "log(Hz)", then the default label + of "Frequency" is changed to "log( frequency )". */ + 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 ); + + } + } + } + +/* Return the result. */ + return result; +} + +static void GetRefPos( AstSpecFrame *this, AstSkyFrame *frm, double *lon, + double *lat, int *status ){ +/* +*++ +* Name: +c astGetRefPos +f AST_GETREFPOS + +* Purpose: +* Return the reference position in a specified celestial coordinate system. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "specframe.h" +c void astGetRefPos( AstSpecFrame *this, AstSkyFrame *frm, double *lon, +c double *lat ) +f CALL AST_GETREFPOS( THIS, FRM, LON, LAT, STATUS ) + +* Class Membership: +* Frame method. + +* Description: +c This function +f This routine +* returns the reference position (specified by attributes RefRA and +* RefDec) converted to the celestial coordinate system represented by +* a supplied SkyFrame. The celestial longitude and latitude values +* are returned in radians. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the SpecFrame. +c frm +f FRM = INTEGER (Given) +* Pointer to the SkyFrame which defines the required celestial +* coordinate system. +c If NULL +f If AST__NULL +* is supplied, then the longitude and latitude values are returned +* as FK5 J2000 RA and Dec values. +c lon +f LON = DOUBLE PRECISION (Returned) +c A pointer to a double in which to store the +f The +* longitude of the reference point, in the coordinate system +* represented by the supplied SkyFrame (radians). +c lat +f LAT = DOUBLE PRECISION (Returned) +c A pointer to a double in which to store the +f The +* latitude of the reference point, in the coordinate system +* represented by the supplied SkyFrame (radians). +f STATUS = INTEGER (Given and Returned) +f The global status. + +* 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. +*-- +*/ + +/* Local Variables: */ + AstFrameSet *fs; /* Conversion FrameSet */ + AstFrame *fb; /* Base Frame */ + AstFrame *fc; /* Current Frame */ + double xin[ 1 ]; /* Axis 1 values */ + double yin[ 1 ]; /* Axis 2 values */ + double xout[ 1 ]; /* Axis 1 values */ + double yout[ 1 ]; /* Axis 2 values */ + +/* Initialise. */ + if( lon ) *lon = AST__BAD; + if( lat ) *lat = AST__BAD; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* If no SkyFrame was supplied, just return the stored RefRA and RefDec + values. */ + if( !frm ) { + if( lon ) *lon = astGetRefRA( this ); + if( lat ) *lat = astGetRefDec( this ); + +/* Otherwise, convert the stored values to the requested system. */ + } else { + +/* Create an FK5 J2000 SkyFrame which will be used for formatting and + unformatting sky positions, etc. */ + LOCK_MUTEX2 + if( !skyframe ) { + astBeginPM; + skyframe = astSkyFrame( "system=FK5,equinox=J2000", status ); + astEndPM; + } + UNLOCK_MUTEX2 + +/* Find the Mapping from the SkyFrame which describes the internal format + in which the RefRA and RefDec attribute values are stored, to the + supplied Frame. */ + fs = astFindFrame( skyframe, frm, "" ); + +/* If alignment was possible, use the Mapping to transform the internal + RefRA and RefDec values. Check for axis permutatuion. */ + if( fs ) { + fb = astGetFrame( fs, AST__BASE ); + if( astGetLonAxis( fb ) == 0 ) { + xin[ 0 ] = astGetRefRA( this ); + yin[ 0 ] = astGetRefDec( this ); + } else { + yin[ 0 ] = astGetRefRA( this ); + xin[ 0 ] = astGetRefDec( this ); + } + astTran2( fs, 1, xin, yin, 1, xout, yout ); + +/* Store the returned values, checking to see if the axes of the supplied + SkyFrame have been permuted. */ + fc = astGetFrame( fs, AST__CURRENT ); + if( astGetLonAxis( fc ) == 0 ) { + if( lon ) *lon = xout[ 0 ]; + if( lat ) *lat = yout[ 0 ]; + } else { + if( lon ) *lon = yout[ 0 ]; + if( lat ) *lat = xout[ 0 ]; + } + +/* Annul object references. */ + fc = astAnnul( fc ); + fb = astAnnul( fb ); + fs = astAnnul( fs ); + } + } +} + +static const char *GetSymbol( AstFrame *this, int axis, int *status ) { +/* +* Name: +* GetSymbol + +* Purpose: +* Obtain a pointer to the Symbol string for a SpecFrame axis. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *GetSymbol( AstFrame *this, int axis, int *status ) + +* Class Membership: +* SpecFrame 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 SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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 SpecFrame. */ + } else { + system = astGetSystem( this ); + +/* If OK, supply a pointer to a suitable default Symbol string. */ + if ( astOK ) { + + if( system == AST__FREQ ) { + result = "FREQ"; + } else if( system == AST__ENERGY ) { + result = "ENER"; + } else if( system == AST__WAVENUM ) { + result = "WAVN"; + } else if( system == AST__WAVELEN ) { + result = "WAVE"; + } else if( system == AST__AIRWAVE ) { + result = "AWAV"; + } else if( system == AST__VRADIO ) { + result = "VRAD"; + } else if( system == AST__VOPTICAL ) { + result = "VOPT"; + } else if( system == AST__REDSHIFT ) { + result = "ZOPT"; + } else if( system == AST__BETA ) { + result = "BETA"; + } else if( system == AST__VREL ) { + result = "VELO"; + +/* 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 "Hz" and the actual units is "log(Hz)", then the default symbol + of "nu" is changed to "log( nu )". */ + 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 SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "Specframe.h" +* AstSystemType GetAlignSystem( AstFrame *this_frame, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the astGetAlignSystem protected +* method inherited from the Frame class). + +* Description: +* This function returns the AlignSystem attribute for a SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The AlignSystem value. + +*/ + +/* Local Variables: */ + AstSpecFrame *this; /* Pointer to SpecFrame structure */ + AstSystemType result; /* Value to return */ + +/* Initialise. */ + result = AST__BADSYSTEM; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) 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__WAVELEN; + } + +/* Return the result. */ + return result; +} + +static AstSystemType GetSystem( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetSystem + +* Purpose: +* Obtain the System attribute for a SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* AstSystemType GetSystem( AstFrame *this_frame, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the astGetSystem protected +* method inherited from the Frame class). + +* Description: +* This function returns the System attribute for a SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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: */ + AstSpecFrame *this; /* Pointer to SpecFrame structure */ + AstSystemType result; /* Value to return */ + +/* Initialise. */ + result = AST__BADSYSTEM; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) 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__WAVELEN; + } + +/* 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 SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *GetTitle( AstFrame *this_frame, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the astGetTitle method inherited +* from the Frame class). + +* Description: +* This function returns a pointer to the Title string for a SpecFrame. +* A pointer to a suitable default string is returned if no Title value has +* previously been set. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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 */ + AstSpecFrame *this; /* Pointer to SpecFrame structure */ + AstStdOfRestType sor; /* Code identifying standard of rest */ + AstSystemType system; /* Code identifying type of coordinates */ + const char *sor_string; /* Pointer to SOR description */ + const char *result; /* Pointer to result string */ + double rf; /* Rest frequency */ + int nc; /* No. of characters added */ + 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 SpecFrame structure. */ + this = (AstSpecFrame *) 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 + SpecFrame's attributes that determine what this string will be. */ + } else { + system = astGetSystem( this ); + sor = astGetStdOfRest( this ); + sor_string = StdOfRestString( sor, status ); + rf = astGetRestFreq( this ); + +/* Classify the coordinate system type and create an appropriate Title + string. (Note that when invoking the astFmtDecimalYr function we must + use a separate sprintf on each occasion so as not to over-write its + internal buffer before the result string has been used.) */ + 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 standard of rest in parentheses, if set. */ + if( astTestStdOfRest( this ) ) { + nc = sprintf( gettitle_buff+pos, " (%s)", sor_string ); + pos += nc; + } + +/* Append the rest frequency if relevant. */ + if( !ABS_SYSTEM(system) && ( astTestRestFreq( this ) || + astGetUseDefs( this ) ) ) { + pos += sprintf( gettitle_buff+pos, ", rest frequency = %g GHz", rf*1.0E-9 ); + } + } + } + +/* If an error occurred, clear the returned pointer value. */ + if ( !astOK ) result = NULL; + +/* Return the result. */ + return result; +} + +static double GetSpecOriginCur( AstSpecFrame *this, int *status ) { +/* +* Name: +* GetSpecOriginCur + +* Purpose: +* Obtain the SpecOrigin attribute for a SpecFrame in current units. + +* Type: +* Private function. + +* Synopsis: +* #include "timeframe.h" +* double GetSpecOriginCur( AstSpecFrame *this, int *status ) + +* Class Membership: +* SpecFrame virtual function + +* Description: +* This function returns the SpecOrigin attribute for a SpecFrame, in +* the current units of the SpecFrame. The protected astGetSpecOrigin +* method can be used to obtain the time origin in the default units of +* the SpecFrame's System. + +* Parameters: +* this +* Pointer to the SpecFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* The SpecOrigin value, in the units, system and rest frame specified +* by the current values of the Unit, System and StdOfRest 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 = astGetSpecOrigin( this ); + +/* If SpecOrigin is non-zero and non-BAD we convert it to the current units.*/ + if( result != 0.0 && result != AST__BAD ) { + +/* Get the default units for the SpecFrame's System. */ + def = DefUnit( astGetSystem( this ), "astGetSpecOrigin", "SpecFrame", status ); + +/* Get the current units from the SpecFrame. */ + 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 SpecFrame.", status, "astGetSpecOrigin", 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 *GetUnit( AstFrame *this_frame, int axis, int *status ) { +/* +* Name: +* GetUnit + +* Purpose: +* Obtain a pointer to the Unit string for a SpecFrame's axis. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *GetUnit( AstFrame *this_frame, int axis ) + +* Class Membership: +* SpecFrame 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 SpecFrame. 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 SpecFrame. +* 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: */ + AstSpecFrame *this; /* Pointer to the SpecFrame structure */ + AstSystemType system; /* The SpecFrame's System value */ + const char *result; /* Pointer value to return */ + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) 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 spectral coordinate system described by the + SpecFrame. */ + } 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 astInitSpecFrameVtab_( AstSpecFrameVtab *vtab, const char *name, int *status ) { +/* +*+ +* Name: +* astInitSpecFrameVtab + +* Purpose: +* Initialise a virtual function table for a SpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "specframe.h" +* void astInitSpecFrameVtab( AstSpecFrameVtab *vtab, const char *name ) + +* Class Membership: +* SpecFrame vtab initialiser. + +* Description: +* This function initialises the component of a virtual function +* table which is used by the SpecFrame 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 */ + AstObjectVtab *object; /* Pointer to Object component of Vtab */ + +/* Check the local error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Initialize the component of the virtual function table used by the + parent class. */ + astInitFrameVtab( (AstFrameVtab *) vtab, name ); + +/* Store a unique "magic" value in the virtual function table. This + will be used (by astIsASpecFrame) 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->GetRefPos = GetRefPos; + vtab->SetRefPos = SetRefPos; + + vtab->ClearAlignStdOfRest = ClearAlignStdOfRest; + vtab->TestAlignStdOfRest = TestAlignStdOfRest; + vtab->GetAlignStdOfRest = GetAlignStdOfRest; + vtab->SetAlignStdOfRest = SetAlignStdOfRest; + + vtab->ClearSourceVRF = ClearSourceVRF; + vtab->TestSourceVRF = TestSourceVRF; + vtab->GetSourceVRF = GetSourceVRF; + vtab->SetSourceVRF = SetSourceVRF; + + vtab->ClearSourceSys = ClearSourceSys; + vtab->TestSourceSys = TestSourceSys; + vtab->GetSourceSys = GetSourceSys; + vtab->SetSourceSys = SetSourceSys; + + vtab->ClearRefDec = ClearRefDec; + vtab->TestRefDec = TestRefDec; + vtab->GetRefDec = GetRefDec; + vtab->SetRefDec = SetRefDec; + + vtab->ClearRefRA = ClearRefRA; + vtab->TestRefRA = TestRefRA; + vtab->GetRefRA = GetRefRA; + vtab->SetRefRA = SetRefRA; + + vtab->ClearRestFreq = ClearRestFreq; + vtab->TestRestFreq = TestRestFreq; + vtab->GetRestFreq = GetRestFreq; + vtab->SetRestFreq = SetRestFreq; + + vtab->ClearStdOfRest = ClearStdOfRest; + vtab->TestStdOfRest = TestStdOfRest; + vtab->GetStdOfRest = GetStdOfRest; + vtab->SetStdOfRest = SetStdOfRest; + + vtab->ClearSourceVel = ClearSourceVel; + vtab->TestSourceVel = TestSourceVel; + vtab->GetSourceVel = GetSourceVel; + vtab->SetSourceVel = SetSourceVel; + + vtab->ClearSpecOrigin = ClearSpecOrigin; + vtab->TestSpecOrigin = TestSpecOrigin; + vtab->GetSpecOrigin = GetSpecOrigin; + vtab->SetSpecOrigin = SetSpecOrigin; + + vtab->TestAlignSpecOffset = TestAlignSpecOffset; + vtab->SetAlignSpecOffset = SetAlignSpecOffset; + vtab->GetAlignSpecOffset = GetAlignSpecOffset; + vtab->ClearAlignSpecOffset = ClearAlignSpecOffset; + +/* Save the inherited pointers to methods that will be extended, and + replace them with pointers to the new member functions. */ + object = (AstObjectVtab *) vtab; + frame = (AstFrameVtab *) vtab; + parent_getobjsize = object->GetObjSize; + object->GetObjSize = GetObjSize; + + 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_clearunit = frame->ClearUnit; + frame->ClearUnit = ClearUnit; + + 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; + +/* 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. */ + astSetCopy( vtab, Copy ); + astSetDelete( vtab, Delete ); + astSetDump( vtab, Dump, "SpecFrame", + "Description of spectral coordinate system" ); + +/* If we have just initialised the vtab for the current class, indicate + that the vtab is now initialised, and store a pointer to the class + identifier in the base "object" level of the vtab. */ + if( vtab == &class_vtab ) { + class_init = 1; + astSetVtabClassIdentifier( vtab, &(vtab->id) ); + } +} + +static int MakeSpecMapping( AstSpecFrame *target, AstSpecFrame *result, + AstSpecFrame *align_frm, int report, + AstMapping **map, int *status ) { +/* +* Name: +* MakeSpecMapping + +* Purpose: +* Generate a Mapping between two SpecFrames. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* int MakeSpecMapping( AstSpecFrame *target, AstSpecFrame *result, +* AstSpecFrame *align_frm, int report, +* AstMapping **map, int *status ) { + +* Class Membership: +* SpecFrame member function. + +* Description: +* This function takes two SpecFrames and generates a Mapping that +* converts between them, taking account of differences in their +* coordinate systems, rest frequency, standard of rest, etc. +* +* In order to cut down the number of transformations to be considered, +* the scheme works by first converting from the target frame to an +* "alignment" Frame, using the attributes of the target to define the +* transformation. A transformation is then found from the alignment +* frame to the required result Frame, using the attributes of the +* result to define the transformation. The alignment Frame is +* described by the AlignSystem and AlignStdOfRest attributes of the +* "align_frm" SpecFrame. +* +* Thus, different forms of alignment can be obtained by suitable +* choice of the attributes of "align_frm". For instance, to compare the +* radio velocity dispersion of two lines at different rest frequencies, +* you would set "system=radio velocity" and (probably) "stdofrest=local +* group" in "align_frm". On the other hand if you wanted to re-calibrate +* an existing radio velocity Frame within a FrameSet to use a different +* rest frequency, you would make the SpecFrame the current Frame and then +* set the rest frequency attribute for the FrameSet. The "integrity +* checking" system in the FrameSet class would then get the Mapping +* between the original and the modified SpecFrames. In this case, the +* "alignment system" needs to be "frequency" since you want the original +* and modified SpecFrames to be aligned in frequency, not radio velocity. + +* Parameters: +* target +* Pointer to the first SpecFrame. +* result +* Pointer to the second SpecFrame. +* align_frm +* A SpecFrame defining the system and standard of rest in which to +* align the target and result SpecFrames. +* 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 +* SpecFrames 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 Constants: */ +#define MAX_ARGS 1 /* Max arguments for an SpecMap conversion */ + +/* Local Variables: */ + AstMapping *map1; /* Intermediate Mapping */ + AstMapping *map2; /* Intermediate Mapping */ + AstMapping *umap1; /* First Units Mapping */ + AstMapping *umap2; /* Second Units Mapping */ + AstSpecMap *specmap; /* Pointer to SpecMap */ + AstShiftMap *sm; /* ShiftMap pointer */ + AstSpecFrame *align_target; /* Alignment Frame with target properties */ + AstSpecFrame *align_result; /* Alignment Frame with result properties */ + AstSystemType serr; /* Erroneous system */ + AstSystemType align_system; /* Code to identify alignment system */ + AstSystemType target_system; /* Code to identify target system */ + AstSystemType result_system; /* Code to identify result system */ + const char *uerr; /* Erroneous units */ + const char *ures; /* Results units */ + const char *utarg; /* Target units */ + const char *vmess; /* Text for use in error messages */ + double args[ MAX_ARGS ]; /* Conversion argument array */ + double target_rf; /* Target rest frequency (Hz) */ + double result_rf; /* Result rest frequency (Hz) */ + double target_origin; /* Target origin */ + double result_origin; /* Result origin */ + int match; /* Mapping can be generated? */ + int step2; /* Perform the 2nd step in the Mapping? */ + int step3; /* Perform the 3rd step in the Mapping? */ + int step4; /* Perform the 4th step in the Mapping? */ + int step5; /* Perform the 5th step in the Mapping? */ + int step6; /* Perform the 6th step in the Mapping? */ + int step7; /* Perform the 7th step in the Mapping? */ + +/* Check the global error status. */ + if ( !astOK ) return 0; + +/* Initialise the returned values. */ + match = 1; + *map = NULL; + +/* Create an initial (null) SpecMap. This is a 1D Mapping which converts + spectral axis values between different systems and standard of rest. + The axis units used by the SpecMap class match the default units used + by this class. Any discrepancy between units is taken into account at + the end of this function, once the total SpecMap has been created. */ + specmap = astSpecMap( 1, 0, "", status ); + +/* Define local macros as shorthand for adding spectral coordinate + conversions to this SpecMap. Each macro simply stores details of + the additional arguments in the "args" array and then calls + astSpecAdd. The macros differ in the number of additional argument + values. */ +#define TRANSFORM_0(cvt) \ + astSpecAdd( specmap, cvt, 0, NULL ); + +#define TRANSFORM_1(cvt,arg0) \ + args[ 0 ] = arg0; \ + astSpecAdd( specmap, cvt, 1, args ); + +/* Get all the necessary attributes from the result, target and alignment + Frames. */ + target_rf = astGetRestFreq( target ); + result_rf = astGetRestFreq( result ); + + target_system = astGetSystem( target ); + result_system = astGetSystem( result ); + align_system = astGetSystem( align_frm ); + +/* Define text for error messages.*/ + vmess = "convert between spectral systems"; + +/* Verify that values for the standard of rest have been set if required + (i.e if the UseDefs attribute of either SpecFrame is false). */ + VerifyAttrs( result, vmess, "StdOfRest", "astMatch", status ); + VerifyAttrs( target, vmess, "StdOfRest", "astMatch", status ); + +/* There are two different strategies for alignment. I'll use the Source + rest frame as an example, although the same argument applies to other + rest frames. In the first strategy, all "Source" rest frames are + considered equal. That is, if two SpecFrames respresent (for example) + frequencies in the source frame, then the SpecFrames are aligned using + a UnitMap even if the details of the two source rest frames differ. + This is usually what users want to see when (for instance) aligning + plots of two spectra which both represent source frequencies but where + the source frames details differ. In the second strategy, "Source" + rest frames are aligned using a SpecMap that takes into account any + differences in the properties of the source rest frames. This is what + should happen when changes are made to the properties of a SpecFrame + within a FrameSet. For instance, if the user changes the SourceVel + attribute of the current Frame (assumed here to be a SpecFrame) in a + FrameSet, then the process of restoring the integrity of the FrameSet + (see frameset.c for details of integrity restoration) should cause the + base->current Mapping in the FrameSet to be modified to reflect the + new SourceVel value. + + So if the current call to this function is part of the process of + restoring a FrameSet's integrity following changes to the FrameSet's + current Frame, then we want to retain the properties of the supplied + alignment Frame. So we use clones of the supplied alignment Frame. */ + if( astGetFrameFlags( target ) & AST__INTFLAG ) { + align_target = astClone( align_frm ); + align_result = astClone( align_frm ); + +/* Buf if we are not restoring the integrity of a FrameSet, we want + to ignore any differences in the properties that define the available + rest frames. So create copies of the alignment Frame in which the + properies defining the available rest frames are the same as in the + target and result Frames. */ + } else { + align_target = astCopy( align_frm ); + astSetEpoch( align_target, astGetEpoch( target ) ); + astSetRefRA( align_target, astGetRefRA( target ) ); + astSetRefDec( align_target, astGetRefDec( target ) ); + astSetSourceVRF( align_target, astGetSourceVRF( target ) ); + astSetSourceVel( align_target, astGetSourceVel( target ) ); + astSetObsLat( align_target, astGetObsLat( target ) ); + astSetObsLon( align_target, astGetObsLon( target ) ); + astSetObsAlt( align_target, astGetObsAlt( target ) ); + + align_result = astCopy( align_frm ); + astSetEpoch( align_result, astGetEpoch( result ) ); + astSetRefRA( align_result, astGetRefRA( result ) ); + astSetRefDec( align_result, astGetRefDec( result ) ); + astSetSourceVRF( align_result, astGetSourceVRF( result ) ); + astSetSourceVel( align_result, astGetSourceVel( result ) ); + astSetObsLat( align_result, astGetObsLat( result ) ); + astSetObsLon( align_result, astGetObsLon( result ) ); + astSetObsAlt( align_result, astGetObsAlt( result ) ); + } + +/* The supported spectral coordinate systems fall into two groups; + "relative", and "absolute". The relative systems define each axis + value with respect to the rest frequency, whereas the absolute systems + have axis values which do not depend on the rest frequency. In order + to convert an axis value from a system in one group to a system in the + other group, the rest frequency must be known. However, the rest + frequency is not necessary in order to convert axis values between two + systems belonging to the same group. Determine if the alignment system + is absolute or relative. If absolute, we ignore the system of the supplied + "align_frm" and align in frequency, since aligning in any absolute system + will automatically ensure that all the other absolute systems are aligned. + Similarly, aligning in any relative system will automatically ensure that + all the other relative systems are aligned. Doing this cuts down the + complexity of the conversion process since we do not need to check every + possible alignment system. */ + align_system = ( ABS_SYSTEM( align_system ) ) ? AST__FREQ : AST__VREL; + +/* The total Mapping is made up of the following steps in series: + + 0) Convert from an offset value to an absolute value (if SpecOrigin set) + 1) Convert target units to default units for the targets system + 2) Convert from target system in target SOR to frequency in target SOR + 3) Convert from freq in target SOR to freq in alignment SOR + 4) Convert from freq in alignment SOR to alignment system in alignment SOR + 5) Convert from alignment system in alignment SOR to freq in alignment SOR + 6) Convert from freq in alignment SOR to freq in result SOR + 7) Convert from freq in result SOR to result system in result SOR + 8) Convert default units for the result system to results unit + 9) Convert from an absolute value to an offset value (if SpecOrigin set) + + Steps 1,2,3,4 are performed using the attributes of the target (rest + frequency, reference farem, etc), whilst steps 5,6,7,8 are performed + using the attributes of the target (rest frequency, reference frame, + etc). It is necessary to go from target system to alignment system + via frequency because SOR conversion can only be performed in the + frequency domain. + + Some of these steps may not be necessary. Initially assume all steps + are necessary (we leave steps 0, 1, 8 and 9 out of this process and + implement them once all other steps have been done). */ + step2 = 1; + step3 = 1; + step4 = 1; + step5 = 1; + step6 = 1; + step7 = 1; + +/* Step 2 is not necessary if the target system is frequency. */ + if( target_system == AST__FREQ ) step2 = 0; + +/* Step 3 is not necessary if the alignment SOR is the same as the target + SOR. */ + if( EqualSor( target, align_target, status ) ) step3 = 0; + +/* Step 6 is not necessary if the alignment SOR is the same as the result + SOR. */ + if( EqualSor( result, align_result, status ) ) step6 = 0; + +/* Step 7 is not necessary if the result system is frequency. */ + if( result_system == AST__FREQ ) step7 = 0; + +/* Steps 4 and 5 are not necessary if the alignment system is frequency, + or if the target and result rest frequencies are equal. */ + if( align_system == AST__FREQ || result_rf == target_rf ) step4 = step5 = 0; + +/* Steps 3 and 6 are not necessary if steps 4 and 5 are not necessary, and + the target sor equals the result sor. */ + if( !step4 && !step5 && EqualSor( target, result, status ) ) step3 = step6 = 0; + +/* Steps 2 and 7 are not necessary if steps 3, 4, 5 and 6 are not necessary, + and the target sor equals the result sor, and the target and results + systems are equal (if the systems are relative they must also have equal + rest frequencies). */ + if( !step3 && !step4 && !step5 && !step6 && EqualSor( target, result, status ) && + target_system == result_system ) { + if( !ABS_SYSTEM( target_system ) && result_rf == target_rf ) step2 = step7 = 0; + } + + +/* Now we know which steps are needed, let's do them (we delay unit + conversion to the end)... */ + +/* Step 2: target system in target rest frame to frequency in target rest + frame. */ + if( step2 ) { + if( target_system != AST__FREQ ) { + +/* If the target system is absolute, we can convert directly to frequency. */ + if ( target_system == AST__ENERGY ) { + TRANSFORM_0( "ENTOFR" ) + + } else if ( target_system == AST__WAVENUM ) { + TRANSFORM_0( "WNTOFR" ) + + } else if ( target_system == AST__WAVELEN ) { + TRANSFORM_0( "WVTOFR" ) + + } else if ( target_system == AST__AIRWAVE ) { + TRANSFORM_0( "AWTOFR" ) + +/* If the target target_system is relative, we first need to convert to + apparent radial velocity, and then to frequency using the rest frequency. */ + } else { + + if ( target_system == AST__VRADIO ) { + TRANSFORM_0( "VRTOVL" ) + + } else if ( target_system == AST__VOPTICAL ) { + TRANSFORM_0( "VOTOVL" ) + + } else if ( target_system == AST__REDSHIFT ) { + TRANSFORM_0( "ZOTOVL" ) + + } else if ( target_system == AST__BETA ) { + TRANSFORM_0( "BTTOVL" ) + } + + VerifyAttrs( target, vmess, "RestFreq", "astMatch", status ); + TRANSFORM_1( "VLTOFR", target_rf ) + } + } + } + +/* Step 3: frequency in target rest frame to frequency in alignment rest + frame. */ + if( step3 ) match = SorConvert( target, align_target, specmap, status ); + +/* Step 4: frequency in alignment rest frame to alignment system in alignment + rest frame. The alignment will be either relativistic velocity or + frequency. */ + if( step4 ) { + if( align_system == AST__VREL ) { + VerifyAttrs( target, vmess, "RestFreq", "astMatch", status ); + TRANSFORM_1( "FRTOVL", target_rf ) + } + } + +/* Step 5: Alignment system in alignment rest frame to frequency in alignment + rest frame (from now on use the attributes of the result SpecFrame to + define the conversion parameters). */ + if( step5 ) { + if( align_system == AST__VREL ) { + VerifyAttrs( result, vmess, "RestFreq", "astMatch", status ); + TRANSFORM_1( "VLTOFR", result_rf ) + } + } + +/* Step 6: frequency in alignment rest frame to frequency in result rest + frame. */ + if( step6 ) match = SorConvert( align_result, result, specmap, status ); + +/* Step 7: frequency in result rest frame to result system in result rest + frame. */ + if( step7 ) { + if( result_system != AST__FREQ ) { + +/* If the results system is absolute, we can convert directly. */ + if ( result_system == AST__ENERGY ) { + TRANSFORM_0( "FRTOEN" ) + + } else if ( result_system == AST__WAVENUM ) { + TRANSFORM_0( "FRTOWN" ) + + } else if ( result_system == AST__WAVELEN ) { + TRANSFORM_0( "FRTOWV" ) + + } else if ( result_system == AST__AIRWAVE ) { + TRANSFORM_0( "FRTOAW" ) + +/* If the result system is relative, we first need to convert to apparent + radial velocity from frequency using the rest frequency. Report an error + if the rest frequency is undefined. */ + } else { + VerifyAttrs( result, vmess, "RestFreq", "astMatch", status ); + TRANSFORM_1( "FRTOVL", result_rf ) + +/* Now convert from apparent radial velocity to the required result system. */ + if ( result_system == AST__VRADIO ) { + TRANSFORM_0( "VLTOVR" ) + + } else if ( result_system == AST__VOPTICAL ) { + TRANSFORM_0( "VLTOVO" ) + + } else if ( result_system == AST__REDSHIFT ) { + TRANSFORM_0( "VLTOZO" ) + + } else if ( result_system == AST__BETA ) { + TRANSFORM_0( "VLTOBT" ) + } + } + } + } + +/* The SpecMap created above class assumes that the axis values supplied to + its Transform method are in units which correspond to the default units + for its class (the returned values also use these units). However, + the Unit attributes of the supplied Frames may have been set to some + non-default value, and so we need to add Mappings before and after the + SpecMap which convert to and from the default units. Find the Mapping + from the target Frame Units to the default Units for the target's system. */ + utarg = astGetUnit( target, 0 ); + umap1 = astUnitMapper( utarg, SpecMapUnit( target_system, "MakeSpecMap", + "SpecFrame", status ), NULL, NULL ); + +/* Find the Mapping from the default Units for the result's system to the + Units of the result Frame. */ + ures = astGetUnit( result, 0 ); + umap2 = astUnitMapper( SpecMapUnit( result_system, "MakeSpecMap", + "SpecFrame", status ), ures, NULL, NULL ); + +/* If both units Mappings were created OK, sandwich the SpecMap between + them. */ + if( umap1 && umap2 ) { + map1 = (AstMapping *) astCmpMap( umap1, specmap, 1, "", status ); + map2 = (AstMapping *) astCmpMap( map1, umap2, 1, "", status ); + map1 = astAnnul( map1 ); + +/* If the simplified SpecMap is a UnitMap, and the target and result + units are the same, we do not need to know the mapping between units. + Otherwise, report an error and indicate that we cannot convert between + the Frames. */ + } else { + map2 = astSimplify( specmap ); + if( !astIsAUnitMap( map2 ) || strcmp( ures, utarg ) ) { + match = 0; + if( astOK && report ) { + if( !umap1 ) { + uerr = utarg; + serr = astGetSystem( target ); + } else { + uerr = ures; + serr = astGetSystem( result ); + } + astError( AST__BADUN, "astMatch(SpecFrame): Inappropriate units (%s) " + "specified for a %s axis.", status, uerr, SystemLabel( serr, status ) ); + } + } + } + +/* Step 0: offset to absolute value in target system. Prepend the Maping created + above with a ShiftMap that does the required shift of origin. */ + target_origin = GetSpecOriginCur( target, status ); + if( target_origin != 0.0 ) { + sm = astShiftMap( 1, &target_origin, "", status ); + map1 = (AstMapping *) astCmpMap( sm, map2, 1, "", status ); + sm = astAnnul( sm ); + } else { + map1 = astClone( map2 ); + } + map2 = astAnnul( map2 ); + +/* Step 9: absolute value to offset in result system. If we are aligning in the + offset system, use the transformed target origin as the new zero point. + Otherwise use the origin from the result frame. First get the origin for the + result system. */ + if( astGetAlignSpecOffset( target ) && astGetAlignSpecOffset( result ) ) { + result_origin = 0.0; + astTran1( map1, 1, &result_origin, 1, &result_origin ); + } else { + result_origin = GetSpecOriginCur( result, status ); + } + +/* Now create the ShiftMap and apend it to the end of the Maping. */ + if( result_origin != 0.0 ) { + result_origin = -result_origin; + sm = astShiftMap( 1, &result_origin, "", status ); + map2 = (AstMapping *) astCmpMap( map1, sm, 1, "", status ); + sm = astAnnul( sm ); + } else { + map2 = astClone( map1 ); + } + map1 = astAnnul( map1 ); + +/* Return the simplified Mapping. */ + *map = astSimplify( map2 ); + +/* Annul remaining resources. */ + map2 = astAnnul( map2 ); + specmap = astAnnul( specmap ); + if( umap1 ) umap1 = astAnnul( umap1 ); + if( umap2 ) umap2 = astAnnul( umap2 ); + align_result = astAnnul( align_result ); + align_target = astAnnul( align_target ); + +/* 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; + +/* Undefine macros local to this function. */ +#undef MAX_ARGS +#undef TRANSFORM_0 +#undef TRANSFORM_1 +} + +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 "specframe.h" +* int Match( AstFrame *template, AstFrame *target, int matchsub, +* int **template_axes, int **target_axes, +* AstMapping **map, AstFrame **result, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the protected astMatch method +* inherited from the Frame class). + +* Description: +* This function matches a "template" SpecFrame 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 SpecFrame. 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 SpecFrame axis from +* which it is derived. If it is not derived from any template +* SpecFrame 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 SpecFrame class +* object to any other class of Frame. A SpecFrame will match any class +* of SpecFrame (i.e. possibly from a derived class) but will not match +* a less specialised class of Frame. +*/ + +/* Local Variables: */ + AstFrame *frame0; /* Pointer to Frame underlying axis 0 */ + AstSpecFrame *template; /* Pointer to template SpecFrame structure */ + int iaxis0; /* Axis index underlying axis 0 */ + int iaxis; /* Axis index */ + int match; /* Coordinate conversion possible? */ + int target_axis0; /* Index of SpecFrame 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 SpecFrame structure. */ + template = (AstSpecFrame *) 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 SpecFrame axis is found. */ + if ( match && astOK ) { + match = 0; + for( iaxis = 0; iaxis < target_naxes; iaxis++ ) { + astPrimaryFrame( target, iaxis, &frame0, &iaxis0 ); + if( astIsASpecFrame( frame0 ) ) { + frame0 = astAnnul( frame0 ); + target_axis0 = iaxis; + match = 1; + break; + } else { + frame0 = astAnnul( frame0 ); + } + } + + } + +/* Check at least one SpecFrame 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 OriginStdOfRest( AstSpecFrame *this, AstStdOfRestType newsor, + const char *method, int *status ){ +/* +* Name: +* OriginStdOfRest + +* Purpose: +* Convert the SpecOrigin in a SpecFrame to a new rest frame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void OriginStdOfRest( AstSpecFrame *this, AstStdOfRestType newsor, +* const char *method, int *status ) + +* Class Membership: +* SpecFrame member function + +* Description: +* This function converts the value of the SpecOrigin attribute stored +* within a supplied SpecFrame from the rest frame currently associated +* with the SpecFrame, to the new rest frame indicated by "newsor". + +* Parameters: +* this +* Point to the SpecFrame. On entry, the SpecOrigin value is +* assumed to refer to the re st frame given by the astGetStdOfRest +* method. On exit, the SpecOrigin value refers to the rest frame +* supplied in "newsor". The StdOfRest attribute of the SpecFrame +* should then be modified in order to keep things consistent. +* newsor +* The rest frame to which the SpecOrigin 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: */ + AstSpecFrame *sf; + AstFrameSet *fs; + double origin; + double neworigin; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Do nothing if the SpecOrigin attribute has not been assigned a value. */ + if( astTestSpecOrigin( this ) ) { + +/* Do nothing if the rest frame will not change. */ + if( newsor != astGetStdOfRest( this ) ) { + +/* Save the original SpecOrigin value (in the current SpecFrame units) and then + clear it. */ + origin = GetSpecOriginCur( this, status ); + astClearSpecOrigin( this ); + +/* Take a copy of the SpecFrame and set the new StdOfRest. */ + sf = astCopy( this ); + astSetStdOfRest( sf, newsor ); + +/* Create a Mapping to perform the rest frame change, then use it to convert + the value to the new rest frame. */ + fs = astConvert( this, sf, "" ); + neworigin = AST__BAD; + if( fs ) { + astTran1( fs, 1, &origin, 1, &neworigin ); + fs = astAnnul( fs ); + } + +/* If succesful, convert from the current units to the default units, and store + in "this". */ + if( neworigin != AST__BAD ) { + astSetSpecOrigin( this, ToUnits( this, astGetUnit( this, 0 ), neworigin, + method, status ) ); + + } else if( astOK ) { + astError( AST__ATSER, "%s(%s): Cannot convert the SpecOrigin " + "value to a different rest frame.", status, method, + astGetClass( this ) ); + } + } + } +} + +static void OriginSystem( AstSpecFrame *this, AstSystemType oldsys, + const char *method, int *status ){ +/* +* Name: +* OriginSystem + +* Purpose: +* Convert the SpecOrigin in a SpecFrame to a new System. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void OriginSystem( AstSpecFrame *this, AstSystemType oldsys, +* const char *method, int *status ) + +* Class Membership: +* SpecFrame member function + +* Description: +* This function converts the value of the SpecOrigin attribute stored +* within a supplied SpecFrame from its original System, etc, to the +* System, etc, currently associated with the SpecFrame. + +* Parameters: +* this +* Point to the SpecFrame. On entry, the SpecOrigin value is +* assumed to refer to the System given by "oldsys", etc. On exit, the +* SpecOrigin value refers to the System returned by the astGetSystem +* method, etc. +* oldsys +* The System to which the SpecOrigin 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: */ + AstSpecFrame *sf1; + AstSpecFrame *sf2; + AstFrameSet *fs; + double origin; + double neworigin; + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Do nothing if the SpecOrigin attribute has not been assigned a value. */ + if( astTestSpecOrigin( this ) ) { + +/* Do nothing if the System will not change. */ + if( oldsys != astGetSystem( this ) ) { + +/* Note the original SpecOrigin value, in the SpecFrame's default units. */ + origin = astGetSpecOrigin( this ); + +/* Take a copy of the original SpecFrame and ensure the Units, SpecOrigin and + AlignSpecOffset attributes are cleared. */ + sf1 = astCopy( this ); + astClearUnit( sf1, 0 ); + astClearSpecOrigin( sf1 ); + astClearAlignSpecOffset( sf1 ); + +/* Take another copy of the SpecFrame and set the old system. */ + sf2 = astCopy( sf1 ); + astSetSystem( sf2, oldsys ); + +/* Create a Mapping to perform the rest frame change, then use it to convert + the value to the current system. */ + fs = astConvert( sf2, sf1, "" ); + neworigin = AST__BAD; + if( fs ) { + astTran1( fs, 1, &origin, 1, &neworigin ); + fs = astAnnul( fs ); + } + +/* Free resources */ + sf1 = astAnnul( sf1 ); + sf2 = astAnnul( sf2 ); + +/* If succesful, store it in "this". */ + if( neworigin != AST__BAD ) { + astSetSpecOrigin( this, neworigin ); + + } else if( astOK ) { + astError( AST__ATSER, "%s(%s): Cannot convert the SpecOrigin " + "value to a different spectral system.", 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 SpecFrame on to another Frame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void Overlay( AstFrame *template, const int *template_axes, +* AstFrame *result, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the protected astOverlay method +* inherited from the Frame class). + +* Description: +* This function overlays attributes of a SpecFrame (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 SpecFrame and a change of spectral +* 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 SpecFrame, 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 SpecFrame, or from a class derived from it, then attributes may +* exist in the template SpecFrame which do not exist in the result Frame. +* In this case, these attributes will not be transferred. +*/ + +/* Local Variables: */ + AstFrame *templt; /* Copy of supplied template Frame */ + AstSystemType new_system; /* Code identifying new cordinates */ + AstSystemType old_system; /* Code identifying old coordinates */ + const char *method; /* Pointer to method string */ + const char *new_class; /* Pointer to template class string */ + const char *old_class; /* Pointer to result class string */ + int specframe; /* Result Frame is a SpecFrame? */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Initialise strings used in error messages. */ + new_class = astGetClass( template ); + old_class = astGetClass( result ); + method = "astOverlay"; + +/* Get the old and new systems. */ + old_system = astGetSystem( result ); + new_system = astGetSystem( template ); + +/* It may be necessary to make temporary changes to the template Frame + below. In order to ensure that we make no permanent changes to the + supplied frame, we will, if necessary, take a deep copy of the + supplied Frame, storing a pointer to the copy in "templt". If it is + not necessary to make any changes to the template, we still want + "templt" to hold a usable pointer, so we initialise it now to hold a + clone of the supplied pointer. This pointer will be replaced by a + pointer to a deep copy (if required) below. */ + templt = astClone( template ); + +/* If the result Frame is a SpecFrame, 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 + SpecFrames. */ + specframe = astIsASpecFrame( result ); + if( specframe ) { + +/* If the coordinate system will change, any value already set for the result + SpecFrame's Title will no longer be appropriate, so clear it. */ + if ( new_system != old_system ) { + astClearTitle( result ); + +/* If the systems have the same default units, we can retain the current + Unit value. */ + if( strcmp( DefUnit( new_system, method, new_class, status ), + DefUnit( old_system, method, old_class, status ) ) ) { + astClearUnit( result, 0 ); + } + +/* If necessary, clear inappropriate values for all those axis attributes + whose access functions are over-ridden by this class (these access functions + will then provide suitable defaults appropriate to the new coordinate system + instead). */ + astClearLabel( result, 0 ); + astClearSymbol( result, 0 ); + } + +/* If the result Frame is not a SpecFrame, we must temporarily clear the + System and AlignSystem values since the values used by this class + are only appropriate to this class. Use a deep copy to avoid the danger + of making any permanent changes to the suppied Frame. */ + } else { + if( astTestSystem( template ) ) { + templt = astAnnul( templt ); + templt = astCopy( template ); + astClearSystem( templt ); + astClearAlignSystem( templt ); + } + } + +/* Invoke the parent class astOverlay method to transfer attributes inherited + from the parent class. */ + (*parent_overlay)( templt, template_axes, result, status ); + +/* Check if the result Frame is a SpecFrame or from a class derived from + SpecFrame. If not, we cannot transfer SpecFrame attributes to it as it is + insufficiently specialised. In this case simply omit these attributes. */ + if ( specframe && 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 SpecFrame 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(AlignStdOfRest) + OVERLAY(AlignSpecOffset); + OVERLAY(RefDec) + OVERLAY(RefRA) + OVERLAY(RestFreq) + OVERLAY(SourceSys) + OVERLAY(SourceVRF) + OVERLAY(SourceVel) + OVERLAY(StdOfRest) + OVERLAY(SpecOrigin) + } + +/* Free resources */ + templt = astAnnul( templt ); + +/* 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 SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void SetAttrib( AstObject *this, const char *setting, int *status ) + +* Class Membership: +* SpecFrame member function (extends the astSetAttrib method inherited from +* the Mapping class). + +* Description: +* This function assigns an attribute value for a SpecFrame, 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 SpecFrame. +* 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: */ + AstMapping *umap; /* Mapping between units */ + AstSpecFrame *this; /* Pointer to the SpecFrame structure */ + AstStdOfRestType sor; /* Standard of rest type code */ + AstSystemType sys; /* Spectral system type code */ + char *a; /* Pointer to next character */ + char *new_setting; /* Pointer value to new attribute setting */ + double dval; /* Double atribute value */ + double dtemp; /* Temporary double atribute value */ + int ival; /* Integer attribute value */ + int len; /* Length of setting string */ + int ulen; /* Used 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 */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) this_object; + +/* Create an FK5 J2000 SkyFrame which will be used for formatting and + unformatting sky positions, etc. */ + LOCK_MUTEX2 + if( !skyframe ) { + astBeginPM; + skyframe = astSkyFrame( "system=FK5,equinox=J2000", status ); + astEndPM; + } + UNLOCK_MUTEX2 + +/* Obtain the length of the setting string. */ + len = strlen( setting ); + +/* Obtain the used length of the setting string. */ + ulen = astChrLen( 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 + SpecFrame 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 ); + } + +/* AlignStdOfRest. */ +/* --------------- */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "alignstdofrest=%n%*s %n", &off, &nc ) ) + && ( nc >= len ) ) { + +/* Convert the string to a StdOfRest code before use. */ + sor = StdOfRestCode( setting + off, status ); + if ( sor != AST__BADSOR ) { + astSetAlignStdOfRest( this, sor ); + +/* Report an error if the string value wasn't recognised. */ + } else { + astError( AST__ATTIN, "astSetAttrib(%s): Invalid standard of rest " + "description \"%s\".", status, astGetClass( this ), setting+off ); + } + +/* GeoLat. */ +/* ------- */ +/* Retained for backward compatibility with older versions of AST in which + SpecFrame had GeoLon/Lat attributes (now ObsLon/Lat are used instead). */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "geolat=%n%*s %n", &off, &nc ) ) + && ( nc >= 7 ) ) { + new_setting = astStore( NULL, setting, len + 1 ); + new_setting[ 0 ] = 'o'; + new_setting[ 1 ] = 'b'; + new_setting[ 2 ] = 's'; + astSetAttrib( this, new_setting ); + new_setting = astFree( new_setting ); + +/* GeoLon. */ +/* ------- */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "geolon=%n%*s %n", &off, &nc ) ) + && ( nc >= 7 ) ) { + new_setting = astStore( NULL, setting, len + 1 ); + new_setting[ 0 ] = 'o'; + new_setting[ 1 ] = 'b'; + new_setting[ 2 ] = 's'; + astSetAttrib( this, new_setting ); + new_setting = astFree( new_setting ); + +/* RefDec. */ +/* ------- */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "refdec=%n%*s %n", &off, &nc ) ) + && ( nc >= 7 ) ) { + +/* Convert the string to a radians value before use. */ + ival = astUnformat( skyframe, 1, setting + off, &dval ); + if ( ival == ulen - off ) { + astSetRefDec( this, dval ); + +/* Report an error if the string value wasn't recognised. */ + } else { + astError( AST__ATTIN, "astSetAttrib(%s): Invalid reference " + "declination \"%s\".", status, astGetClass( this ), setting + off ); + } + +/* RefRA. */ +/* ------ */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "refra=%n%*s %n", &off, &nc ) ) + && ( nc >= 6 ) ) { + +/* Convert the string to a radians value before use. */ + ival = astUnformat( skyframe, 0, setting + off, &dval ); + if ( ival == ulen - off ) { + astSetRefRA( this, dval ); + +/* Report an error if the string value wasn't recognised. */ + } else { + astError( AST__ATTIN, "astSetAttrib(%s): Invalid reference right " + "ascension \"%s\".", status, astGetClass( this ), setting + off ); + } + +/* AlignSpecOffset. */ +/* ---------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "alignspecoffset= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetAlignSpecOffset( this, ival ); + +/* RestFreq. */ +/* --------- */ +/* Without any units indication - assume GHz. Convert to Hz for storage. */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "restfreq= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + astSetRestFreq( this, dval*1.0E9 ); + +/* With units indication. */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "restfreq= %lg %n%*s %n", &dval, &off, &nc ) ) + && ( nc >= len ) ) { + dtemp = AST__BAD; + +/* Is there a Mapping from the supplied units to Hz? If so, use the + Mapping to convert the supplied value to Hz. */ + if( ( umap = astUnitMapper( setting + off, "Hz", NULL, NULL ) ) ) { + astTran1( umap, 1, &dval, 1, &dtemp ); + umap = astAnnul( umap ); + +/* Otherwise, if there is a Mapping from the supplied units to metre, + assume the supplied unit is a vacuum wavelength. */ + } else if( ( umap = astUnitMapper( setting + off, "m", NULL, NULL ) ) ) { + +/* Convert the supplied wavelength to metres. */ + astTran1( umap, 1, &dval, 1, &dtemp ); + umap = astAnnul( umap ); + +/* Convert the wavelength (m) to frequency (Hz). */ + if( dtemp != AST__BAD && dtemp != 0.0 ) { + dtemp = AST__C/dtemp; + } else if( astOK ) { + astError( AST__ATTIN, "astSetAttrib(%s): Invalid rest wavelength " + "\"%g %s\" supplied.", status, astGetClass( this ), dval, setting + off ); + } + +/* Otherwise, if there is a Mapping from the supplied units to Joule, + assume the supplied unit is an energy. */ + } else if( ( umap = astUnitMapper( setting + off, "J", NULL, NULL ) ) ) { + +/* Convert the supplied energy to Joules. */ + astTran1( umap, 1, &dval, 1, &dtemp ); + umap = astAnnul( umap ); + +/* Convert the energy (J) to frequency (Hz). */ + if( dtemp != AST__BAD ) { + dtemp *= 1.0/AST__H; + } else if( astOK ) { + astError( AST__ATTIN, "astSetAttrib(%s): Invalid rest energy " + "\"%g %s\" supplied.", status, astGetClass( this ), dval, setting + off ); + } + +/* Otherwise report an error. */ + } else if( astOK ) { + astError( AST__ATTIN, "astSetAttrib(%s): Rest frequency given in an " + "unsupported system of units \"%g %s\".", status, + astGetClass( this ), dval, setting + off ); + } + +/* Set the rest frequency. */ + astSetRestFreq( this, dtemp ); + +/* SourceVel. */ +/* ---------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "sourcevel= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + +/* Convert from km/s to m/s if the SourceVel value is a velocity. */ + if( astGetSourceSys( this ) == AST__VREL || + astGetSourceSys( this ) == AST__VRADIO || + astGetSourceSys( this ) == AST__VOPTICAL ) dval *= 1.0E3; + +/* Store the value */ + astSetSourceVel( this, dval ); + +/* SourceVRF */ +/* --------- */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "sourcevrf=%n%*s %n", &off, &nc ) ) + && ( nc >= len ) ) { + +/* Convert the string to a StdOfRest code before use. */ + sor = StdOfRestCode( setting + off, status ); + if ( sor != AST__BADSOR ) { + astSetSourceVRF( this, sor ); + +/* Report an error if the string value wasn't recognised. */ + } else { + astError( AST__ATTIN, "astSetAttrib(%s): Invalid standard of rest " + "description \"%s\".", status, astGetClass( this ), setting+off ); + } + +/* SourceSys */ +/* --------- */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "sourcesys=%n%*s %n", &off, &nc ) ) + && ( nc >= len ) ) { + +/* Convert the string to a System code before use. */ + sys = SystemCode( (AstFrame *) this, setting + off, status ); + astSetSourceSys( this, sys ); + +/* StdOfRest. */ +/* ---------- */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "stdofrest=%n%*s %n", &off, &nc ) ) + && ( nc >= len ) ) { + +/* Convert the string to a StdOfRest code before use. */ + sor = StdOfRestCode( setting + off, status ); + if ( sor != AST__BADSOR ) { + astSetStdOfRest( this, sor ); + +/* Report an error if the string value wasn't recognised. */ + } else { + astError( AST__ATTIN, "astSetAttrib(%s): Invalid standard of rest " + "description \"%s\".", status, astGetClass( this ), setting + off ); + } + +/* SpecOrigin */ +/* ---------- */ + +/* Floating-point without any units indication - assume the current Unit + value. Convert from current units to default units for current system. */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "specorigin= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + + astSetSpecOrigin( this, ToUnits( this, astGetUnit( this, 0 ), dval, + "astSetSpecOrigin", status ) ); + +/* Floating-point with units. Convert the supplied value to the default units + for the SpecFrame's System. */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "specorigin= %lg %n%*s %n", &dval, &off, &nc ) ) + && ( nc >= len ) ) { + astSetSpecOrigin( this, ToUnits( this, setting + off, dval, "astSetSpecOrigin", status ) ); + +/* Pass any unrecognised setting to the parent method for further + interpretation. */ + } else { + (*parent_setattrib)( this_object, setting, status ); + } +} + +static void SetRefPos( AstSpecFrame *this, AstSkyFrame *frm, double lon, + double lat, int *status ){ +/* +*++ +* Name: +c astSetRefPos +f AST_SETREFPOS + +* Purpose: +* Set the reference position in a specified celestial coordinate system. + +* Type: +* Public virtual function. + +* Synopsis: +c #include "specframe.h" +c void astSetRefPos( AstSpecFrame *this, AstSkyFrame *frm, double lon, +c double lat ) +f CALL AST_SETREFPOS( THIS, FRM, LON, LAT, STATUS ) + +* Class Membership: +* Frame method. + +* Description: +c This function +f This routine +* sets the reference position (see attributes RefRA and RefDec) using +* axis values (in radians) supplied within the celestial coordinate +* system represented by a supplied SkyFrame. + +* Parameters: +c this +f THIS = INTEGER (Given) +* Pointer to the SpecFrame. +c frm +f FRM = INTEGER (Given) +* Pointer to the SkyFrame which defines the celestial coordinate +* system in which the longitude and latitude values are supplied. +c If NULL +f If AST__NULL +* is supplied, then the supplied longitude and latitude values are +* assumed to be FK5 J2000 RA and Dec values. +c lon +f LON = DOUBLE PRECISION (Given) +* The longitude of the reference point, in the coordinate system +* represented by the supplied SkyFrame (radians). +c lat +f LAT = DOUBLE PRECISION (Given) +* The latitude of the reference point, in the coordinate system +* represented by the supplied SkyFrame (radians). +f STATUS = INTEGER (Given and Returned) +f The global status. + +*-- +*/ + +/* Local Variables: */ + AstFrameSet *fs; /* Conversion FrameSet */ + AstFrame *fb; /* Base Frame */ + AstFrame *fc; /* Current Frame */ + double xin[ 1 ]; /* Axis 1 values */ + double yin[ 1 ]; /* Axis 2 values */ + double xout[ 1 ]; /* Axis 1 values */ + double yout[ 1 ]; /* Axis 2 values */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* If no SkyFrame was supplied, just store the supplied RefRA and RefDec + values. */ + if( !frm ) { + astSetRefRA( this, lon ); + astSetRefDec( this, lat ); + +/* Otherwise, convert the supplied values from the requested system. */ + } else { + +/* Create an FK5 J2000 SkyFrame which will be used for formatting and + unformatting sky positions, etc. */ + LOCK_MUTEX2 + if( !skyframe ) { + astBeginPM; + skyframe = astSkyFrame( "system=FK5,equinox=J2000", status ); + astEndPM; + } + UNLOCK_MUTEX2 + +/* Find the Mapping from the supplied SkyFrame, to the SkyFrame which + describes the internal format in which the RefRA and RefDec attribute + values are stored. */ + fs = astFindFrame( frm, skyframe, "" ); + +/* If alignment was possible, use the Mapping to transform the supplied + axis values, checking to see if the axes of the supplied SkyFrame have + been permuted. */ + if( fs ) { + +/* Find the longitude axis in the Base Frame, and store the supplied + longitude and latitude values. */ + fb = astGetFrame( fs, AST__BASE ); + if( astGetLonAxis( fb ) == 0 ) { + xin[ 0 ] = lon; + yin[ 0 ] = lat; + } else { + xin[ 0 ] = lat; + yin[ 0 ] = lon; + } + astTran2( fs, 1, xin, yin, 1, xout, yout ); + +/* Store the corresponding RefRA and RefDec values. */ + fc = astGetFrame( fs, AST__CURRENT ); + if( astGetLonAxis( fc ) == 0 ) { + astSetRefRA( this, xout[ 0 ] ); + astSetRefDec( this, yout[ 0 ] ); + } else { + astSetRefRA( this, yout[ 0 ] ); + astSetRefDec( this, xout[ 0 ] ); + } + +/* Annul object references. */ + fc = astAnnul( fc ); + fb = astAnnul( fb ); + fs = astAnnul( fs ); + } + } +} + +static void SetStdOfRest( AstSpecFrame *this, AstStdOfRestType value, int *status ) { +/* +*+ +* Name: +* astSetStdOfRest + +* Purpose: +* Set the StdOfRest attribute for a SpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "specframe.h" +* void astSetStdOfRest( AstSpecFrame *this, AstStdOfRestType value ) + +* Class Membership: +* SpecFrame virtual function + +* Description: +* This function set a new value for the StdOfRest attribute for a +* SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* value +* The new value. + +*- +*/ + +/* Check the global error status. */ + if ( !astOK ) return; + + +/* Validate the StdOfRest value being set and report an error if necessary. */ + if( value < FIRST_SOR || value > LAST_SOR ) { + astError( AST__ATTIN, "%s(%s): Bad value (%d) given for StdOfRest attribute.", status, + "astSetStdOfRest", astGetClass( this ), (int) value ); + +/* Otherwise set the new StdOfRest */ + } else { + +/* Modify the SpecOrigin value stored in the SpecFrame structure to refer + to the new rest frame. */ + OriginStdOfRest( this, value, "astSetStdOfRest", status ); + +/* Store the new value for the rest frame in the SpecFrame structure. */ + this->stdofrest = value; + + } +} + +static void SetSystem( AstFrame *this_frame, AstSystemType newsys, int *status ) { +/* +* Name: +* SetSystem + +* Purpose: +* Set the System attribute for a SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void SetSystem( AstFrame *this_frame, AstSystemType newsys, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the astSetSystem protected +* method inherited from the Frame class). + +* Description: +* This function sets the System attribute for a SpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* newsys +* The new System value to be stored. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + AstSpecFrame *this; /* Pointer to SpecFrame structure */ + AstSystemType oldsys; /* Original System value */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) this_frame; + +/* 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 ) { + +/* Changing the System value will in general require the Units to change + as well. If the user has previously specified the units to be used with + the new system, then re-instate them (they are stored in the "usedunits" + array in the SpecFrame structure). Otherwise, clear the units so that + the default units will eb used with the new System. */ + if( (int) newsys < this->nuunits && this->usedunits && + this->usedunits[ (int) newsys ] ) { + astSetUnit( this, 0, this->usedunits[ (int) newsys ] ); + } else { + astClearUnit( this, 0 ); + } + +/* Modify the stored SpecOrigin. */ + OriginSystem( this, oldsys, "astSetSystem", status ); + +/* Also, clear all attributes which have system-specific defaults. */ + astClearLabel( this_frame, 0 ); + astClearSymbol( this_frame, 0 ); + astClearTitle( this_frame ); + } +} + +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 SpecFrame's axis. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void SetUnit( AstFrame *this_frame, int axis, const char *value ) + +* Class Membership: +* SpecFrame 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 SpecFrame. It also stores the string in the "usedunits" array +* in the SpecFrame structure, in the element associated with the +* current System. + +* Parameters: +* this +* Pointer to the SpecFrame. +* axis +* The number of the axis (zero-based) for which information is required. +* unit +* The new string to store. +*/ + +/* Local Variables: */ + AstSpecFrame *this; /* Pointer to the SpecFrame structure */ + int i; /* Loop counter */ + int system; /* The SpecFrame's System value */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) this_frame; + +/* Validate the axis index. */ + astValidateAxis( this, axis, 1, "astSetUnit" ); + +/* Store the supplied value as the UsedUnit for the current System. First + ensure the array is big enough. Free any previous value stored for the + current system. */ + system = (int) astGetSystem( this ); + if( system >= this->nuunits ) { + this->usedunits = astGrow( this->usedunits, system + 1, + sizeof(char *) ); + if( astOK ) { + for( i = this->nuunits; i < system + 1; i++ ) this->usedunits[ i ] = NULL; + this->nuunits = system + 1; + } + } + +/* Now store a copy of the value, if it is different to the stored string. */ + if( astOK && ( !this->usedunits[ system ] || + strcmp( this->usedunits[ system ], value ) ) ) { + this->usedunits[ system ] = astStore( this->usedunits[ system ], + value, strlen( value ) + 1 ); + } + +/* Now use the parent SetUnit method to store the value in the Axis + structure */ + (*parent_setunit)( this_frame, axis, value, status ); + +} + +static int SorConvert( AstSpecFrame *this, AstSpecFrame *that, + AstSpecMap *specmap, int *status ) { +/* +* Name: +* SorConvert + +* Purpose: +* Add a conversion to a SpecMap which transforms between two +* standards of rest. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* int SorConvert( AstSpecFrame *this, AstSpecFrame *that, +* AstSpecMap *specmap, int *status ) + +* Class Membership: +* SpecFrame member function. + +* Description: +* This function adds a conversion to a SpecMap which transforms +* frequencies from the standard of rest specified by "this" to +* the standard of rest specified by "that". Note the conversion is +* always between frequency in the two rest frames no matter what the +* System attributes of the two SpecFrames may be (which are ignored). + +* Parameters: +* this +* The SpecFrame which defines the input rest frame. +* that +* The SpecFrame which defines the output rest frame. +* specmap +* The SpecMap to which the conversion is to be added. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Zero is returned if the conversion could not be performed. One is +* returned otherwise. + +*/ + +/* Local Constants: */ +#define MAX_ARGS 7 /* Max arguments for an SpecMap conversion */ + +/* Local Variables: */ + AstStdOfRestType from; /* Input standard of rest */ + AstStdOfRestType to; /* Output standard of rest */ + const char *vmess; /* Text for use in error messages */ + double args[ MAX_ARGS ]; /* Conversion argument array */ + double dec; /* DEC of source (radians, FK5 J2000) */ + double epoch; /* Epoch of observation (MJD) */ + double alt; /* Observers geodetic altitude (radians) */ + double lat; /* Observers geodetic latitude (radians) */ + double lon; /* Observers geodetic longitude (radians) */ + double ra; /* RA of source (radians, FK5 J2000) */ + int result; /* Returned value */ + +/* Initialise */ + result = 1; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* No conversion is required if the rest frames are equal. */ + if( !EqualSor( this, that, status ) ) { + +/* Define local macros as shorthand for adding spectral coordinate + conversions to the SpecMap. Each macro simply stores details of + the additional arguments in the "args" array and then calls + astSpecAdd. The macros differ in the number of additional argument + values. */ +#define TRANSFORM_2(cvt,arg0,arg1) \ + args[ 0 ] = arg0; \ + args[ 1 ] = arg1; \ + astSpecAdd( specmap, cvt, 2, args ); + +#define TRANSFORM_3(cvt,arg0,arg1,arg2) \ + args[ 0 ] = arg0; \ + args[ 1 ] = arg1; \ + args[ 2 ] = arg2; \ + astSpecAdd( specmap, cvt, 3, args ); + +#define TRANSFORM_6(cvt,arg0,arg1,arg2,arg3,arg4,arg5) \ + args[ 0 ] = arg0; \ + args[ 1 ] = arg1; \ + args[ 2 ] = arg2; \ + args[ 3 ] = arg3; \ + args[ 4 ] = arg4; \ + args[ 5 ] = arg5; \ + astSpecAdd( specmap, cvt, 6, args ); + +/* A string for use in error messages. */ + vmess = "convert between different standards of rest"; + +/* Get the required values from "this". */ + from = astGetStdOfRest( this ); + ra = astGetRefRA( this ); + dec = astGetRefDec( this ); + lon = astGetObsLon( this ); + lat = astGetObsLat( this ); + alt = astGetObsAlt( this ); + epoch = astGetEpoch( this ); + +/* Verify that the reference RA and DEC can be used (they are needed by all + the conversions used below). */ + VerifyAttrs( this, vmess, "RefRA RefDec", "astMatch", status ); + +/* Convert from the "this" rest frame to heliographic. */ + if( from == AST__TPSOR ) { + VerifyAttrs( this, vmess, "ObsLon ObsLat ObsAlt Epoch", "astMatch", status ); + TRANSFORM_6( "TPF2HL", lon, lat, alt, epoch, ra, dec ) + + } else if( from == AST__GESOR ) { + VerifyAttrs( this, vmess, "Epoch", "astMatch", status ); + TRANSFORM_3( "GEF2HL", epoch, ra, dec ) + + } else if( from == AST__BYSOR ) { + VerifyAttrs( this, vmess, "Epoch", "astMatch", status ); + TRANSFORM_3( "BYF2HL", epoch, ra, dec ) + + } else if( from == AST__LKSOR ) { + TRANSFORM_2( "LKF2HL", ra, dec ) + + } else if( from == AST__LDSOR ) { + TRANSFORM_2( "LDF2HL", ra, dec ) + + } else if( from == AST__LGSOR ) { + TRANSFORM_2( "LGF2HL", ra, dec ) + + } else if( from == AST__GLSOR ) { + TRANSFORM_2( "GLF2HL", ra, dec ) + + } else if( from == AST__SCSOR ) { + TRANSFORM_3( "USF2HL", ConvertSourceVel( this, AST__HLSOR, AST__VREL, status ), + ra, dec ) + } + +/* Now go from heliocentric to the "to" frame. */ + to = astGetStdOfRest( that ); + ra = astGetRefRA( that ); + dec = astGetRefDec( that ); + lon = astGetObsLon( that ); + lat = astGetObsLat( that ); + alt = astGetObsAlt( that ); + epoch = astGetEpoch( that ); + VerifyAttrs( that, vmess, "RefRA RefDec", "astMatch", status ); + + if( to == AST__TPSOR ) { + VerifyAttrs( that, vmess, "ObsLon ObsLat ObsAlt Epoch", "astMatch", status ); + TRANSFORM_6( "HLF2TP", lon, lat, alt, epoch, ra, dec ) + + } else if( to == AST__GESOR ) { + VerifyAttrs( that, vmess, "Epoch", "astMatch", status ); + TRANSFORM_3( "HLF2GE", epoch, ra, dec ) + + } else if( to == AST__BYSOR ) { + VerifyAttrs( that, vmess, "Epoch", "astMatch", status ); + TRANSFORM_3( "HLF2BY", epoch, ra, dec ) + + } else if( to == AST__LKSOR ) { + TRANSFORM_2( "HLF2LK", ra, dec ) + + } else if( to == AST__LDSOR ) { + TRANSFORM_2( "HLF2LD", ra, dec ) + + } else if( to == AST__LGSOR ) { + TRANSFORM_2( "HLF2LG", ra, dec ) + + } else if( to == AST__GLSOR ) { + TRANSFORM_2( "HLF2GL", ra, dec ) + + } else if( to == AST__SCSOR ) { + TRANSFORM_3( "HLF2US", ConvertSourceVel( that, AST__HLSOR, AST__VREL, status ), + ra, dec ) + } + } + +/* Return the result. */ + return result; + +/* Undefine macros local to this function. */ +#undef MAX_ARGS +#undef TRANSFORM_2 +#undef TRANSFORM_3 +#undef TRANSFORM_6 +} + +static const char *SpecMapUnit( AstSystemType system, const char *method, + const char *class, int *status ){ +/* +* Name: +* SpecMapUnit + +* Purpose: +* Return the default units for a spectral coordinate system type used +* by the SpecMap class. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *SpecMapUnit( AstSystemType system, const char *method, +* const char *class, int *status ) + +* Class Membership: +* SpecFrame member function. + +* Description: +* This function returns a textual representation of the +* units used by the SpecMap class for the specified spectral +* coordinate system. In general, the SpecMap class uses SI units +* (m/s, Hz, m, etc), but this class (SpecFrame) has default units +* more appropriate to astronomers (km/s, GHz, Angstroms, etc). + +* Parameters: +* system +* The spectral 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__FREQ ) { + result = "Hz"; + } else if( system == AST__ENERGY ) { + result = "J"; + } else if( system == AST__WAVENUM ) { + result = "1/m"; + } else if( system == AST__WAVELEN ) { + result = "m"; + } else if( system == AST__AIRWAVE ) { + result = "m"; + } else if( system == AST__VRADIO ) { + result = "m/s"; + } else if( system == AST__VOPTICAL ) { + result = "m/s"; + } else if( system == AST__REDSHIFT ) { + result = ""; + } else if( system == AST__BETA ) { + result = ""; + } else if( system == AST__VREL ) { + result = "m/s"; + +/* 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 AstStdOfRestType StdOfRestCode( const char *sor, int *status ) { +/* +* Name: +* StdOfRestCode + +* Purpose: +* Convert a string into a standard of rest type code. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* AstStdOfRestType StdOfRestCode( const char *sor ) + +* Class Membership: +* SpecFrame member function. + +* Description: +* This function converts a string used for the external description of +* a standard of rest into a SpecFrame standard of rest type code +* (StdOfRest attribute value). It is the inverse of the +* StdOfRestString function. + +* Parameters: +* sor +* Pointer to a constant null-terminated string containing the +* external description of the standard of rest. + +* Returned Value: +* The StdOfRest type code. + +* Notes: +* - A value of AST__BADSOR is returned if the standard of rest +* description was not recognised. This does not produce an error. +* - A value of AST__BADSOR is also returned if this function +* is invoked with the global error status set or if it should fail +* for any reason. +*/ + +/* Local Variables: */ + AstStdOfRestType result; /* Result value to return */ + +/* Initialise. */ + result = AST__BADSOR; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Match the "sor" string against each possibility and assign the + result. */ + if ( astChrMatch( "TOPO", sor ) || astChrMatch( "TOPOCENT", sor ) || astChrMatch( "TOPOCENTRIC", sor ) ) { + result = AST__TPSOR; + + } else if ( astChrMatch( "GEO", sor ) || astChrMatch( "GEOCENTR", sor ) || astChrMatch( "GEOCENTRIC", sor ) ) { + result = AST__GESOR; + + } else if ( astChrMatch( "BARY", sor ) || astChrMatch( "BARYCENT", sor ) || astChrMatch( "BARYCENTRIC", sor ) ) { + result = AST__BYSOR; + + } else if ( astChrMatch( "HELIO", sor ) || astChrMatch( "HELIOCEN", sor ) || astChrMatch( "HELIOCENTRIC", sor ) ) { + result = AST__HLSOR; + + } else if ( astChrMatch( "LSRK", sor ) || astChrMatch( "LSR", sor ) ) { + result = AST__LKSOR; + + } else if ( astChrMatch( "LSRD", sor ) ) { + result = AST__LDSOR; + + } else if ( astChrMatch( "GAL", sor ) || astChrMatch( "GALACTOC", sor ) || astChrMatch( "GALACTIC", sor ) ) { + result = AST__GLSOR; + + } else if ( astChrMatch( "LG", sor ) || astChrMatch( "LOCALGRP", sor ) || + astChrMatch( "LOCAL_GROUP", sor ) || astChrMatch( "LOCAL-GROUP", sor ) ) { + result = AST__LGSOR; + + } else if ( astChrMatch( "SOURCE", sor ) || astChrMatch( "SRC", sor ) ) { + result = AST__SCSOR; + + } + +/* Return the result. */ + return result; +} + +static const char *StdOfRestString( AstStdOfRestType sor, int *status ) { +/* +* Name: +* StdOfRestString + +* Purpose: +* Convert a standard of rest type code into a string. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* const char *StdOfRestString( AstStdOfRestType sor, int *status ) + +* Class Membership: +* SpecFrame member function. + +* Description: +* This function converts a SpecFrame standard of rest type code +* (StdOfRest attribute value) into a string suitable for use as an +* external representation of the standard of rest type. + +* Parameters: +* sor +* The standard of rest 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 standard of rest +* 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 "sor" 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 standard of rest). */ + switch ( sor ) { + + case AST__TPSOR: + result = "Topocentric"; + break; + + case AST__GESOR: + result = "Geocentric"; + break; + + case AST__BYSOR: + result = "Barycentric"; + break; + + case AST__HLSOR: + result = "Heliocentric"; + break; + + case AST__LDSOR: + result = "LSRD"; + break; + + case AST__LKSOR: + result = "LSRK"; + break; + + case AST__LGSOR: + result = "Local_group"; + break; + + case AST__GLSOR: + result = "Galactic"; + break; + + case AST__SCSOR: + result = "Source"; + 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 SpecFrame and convert to the new coordinate +* system. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.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: +* SpecFrame 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" SpecFrame 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 SpecFrame, 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 SpecFrame. 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 +* SpecFrame 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 +* SpecFrame object. This results in another object of the same class +* only if the single SpecFrame axis is selected exactly once. +* Otherwise, the result is a Frame class object which inherits the +* SpecFrame's axis information (if appropriate) but none of the other +* properties of a SpecFrame. +* - In the event that a SpecFrame 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: */ + AstSpecFrame *target; /* Pointer to the SpecFrame structure */ + AstSpecFrame *temp; /* Pointer to copy of target SpecFrame */ + AstSpecFrame *align_frm; /* Frame in which to align the SpecFrames */ + int match; /* Coordinate conversion is possible? */ + int report; /* Report errors if SpecFrames cannot be aligned? */ + +/* 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 SpecFrame structure. */ + target = (AstSpecFrame *) target_frame; + +/* Result is a SpecFrame. */ +/* -------------------------- */ +/* Check if the result Frame is to have one axis obtained by selecting + the single target SpecFrame axis. If so, the result will also be + a SpecFrame. */ + if ( ( result_naxes == 1 ) && ( target_axes[ 0 ] == 0 ) ) { + +/* Form the result from a copy of the target. */ + *result = astCopy( target ); + +/* Initialise a flag to indicate that MakeSpecMapping should not report + errors if no Mapping can be created. */ + report = 0; + +/* If required, overlay the template attributes on to the result SpecFrame. + Also get the system and standard of rest in which to align the two + SpecFrames. These are the values from the template (if there is a + template). */ + if ( template ) { + astOverlay( template, template_axes, *result ); + if( astIsASpecFrame( template ) ) { + align_frm = astCopy( template ); + +/* Since we now know that both the template and target are SpecFrames, it + should usually be possible to convert betwen them. If conversion is + *not* possible (fpr instance if no rest frequency is availalbe, etc) + then the user will probably be interested in knowing the reason why + conversion is not possible. Therefore, indicate that MakeSpecMapping + should report errors if no Mapping can be created. */ + report = 1; + + } else { + align_frm = astCopy( target ); + } + +/* If no template was supplied, align in the System and StdOfRest of the + target. */ + } else { + VerifyAttrs( target, "convert between different spectral systems", + "StdOfRest", "astMatch", status ); + align_frm = astCopy( target ); + } + +/* The MakeSpecMapping function uses the System and StdOfRest attributes to + define the alignment frame. But the AlignSystem and AlignStdOfRest + attributes should be used for this purpose. Therefore, copy the values + of the AlignSystem and AlignStdOfRest attributes to the System and + StdOfRest attribute. */ + astSetSystem( align_frm, astGetAlignSystem( align_frm ) ); + astSetStdOfRest( align_frm, astGetAlignStdOfRest( align_frm ) ); + +/* Generate a Mapping that takes account of changes in the sky coordinate + system (equinox, epoch, etc.) between the target SpecFrame and the result + SpecFrame. If this Mapping can be generated, set "match" to indicate that + coordinate conversion is possible. If the template is a specframe, + report errors if a match is not possible. */ + match = ( MakeSpecMapping( target, (AstSpecFrame *) *result, + align_frm, report, map, status ) != 0 ); + +/* Free resources. */ + align_frm = astAnnul( align_frm ); + +/* Result is not a SpecFrame. */ +/* ------------------------------ */ +/* 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 SpecFrame, default attribute values may differ + if the methods for obtaining them were over-ridden by the SpecFrame + 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 SpecFrame. 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 + SpecFrame class. */ + SET(Domain) + SET(Title) + +/* Define a macro to test if an attribute is set for axis zero (the only + axis of a SpecFrame). 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 SpecFrame 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 SpecFrame. */ + 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 "specframe.h" +* AstSystemType SystemCode( AstFrame *this, const char *system, int *status ) + +* Class Membership: +* SpecFrame 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 SpecFrame +* 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( "FREQ", system ) ) { + result = AST__FREQ; + + } else if ( astChrMatch( "ENER", system ) || astChrMatch( "ENERGY", system ) ) { + result = AST__ENERGY; + + } else if ( astChrMatch( "WAVN", system ) || astChrMatch( "WAVENUM", system ) ) { + result = AST__WAVENUM; + + } else if ( astChrMatch( "WAVE", system ) || astChrMatch( "WAVELEN", system ) ) { + result = AST__WAVELEN; + + } else if ( astChrMatch( "AWAV", system ) || astChrMatch( "AIRWAVE", system ) ) { + result = AST__AIRWAVE; + + } else if ( astChrMatch( "VRAD", system ) || astChrMatch( "VRADIO", system ) ) { + result = AST__VRADIO; + + } else if ( astChrMatch( "VOPT", system ) || astChrMatch( "VOPTICAL", system ) ) { + result = AST__VOPTICAL; + + } else if ( astChrMatch( "ZOPT", system ) || astChrMatch( "REDSHIFT", system ) ) { + result = AST__REDSHIFT; + + } else if ( astChrMatch( "BETA", system ) ) { + result = AST__BETA; + + } else if ( astChrMatch( "VELO", system ) || astChrMatch( "VREL", system ) ) { + result = AST__VREL; + + } + +/* 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 "specframe.h" +* const char *SystemLabel( AstSystemType system, int *status ) + +* Class Membership: +* SpecFrame member function. + +* Description: +* This function converts a SpecFrame 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__FREQ: + result = "frequency"; + break; + + case AST__ENERGY: + result = "energy"; + break; + + case AST__WAVENUM: + result = "wave-number"; + break; + + case AST__WAVELEN: + result = "wavelength"; + break; + + case AST__AIRWAVE: + result = "wavelength in air"; + break; + + case AST__VRADIO: + result = "radio velocity"; + break; + + case AST__VOPTICAL: + result = "optical velocity"; + break; + + case AST__REDSHIFT: + result = "redshift"; + break; + + case AST__BETA: + result = "beta factor"; + break; + + case AST__VREL: + result = "apparent radial velocity"; + 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 "specframe.h" +* const char *SystemString( AstFrame *this, AstSystemType system, int *status ) + +* Class Membership: +* SpecFrame member function (over-rides the astSystemString method +* inherited from the Frame class). + +* Description: +* This function converts a SpecFrame 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__FREQ: + result = "FREQ"; + break; + + case AST__ENERGY: + result = "ENER"; + break; + + case AST__WAVENUM: + result = "WAVN"; + break; + + case AST__WAVELEN: + result = "WAVE"; + break; + + case AST__AIRWAVE: + result = "AWAV"; + break; + + case AST__VRADIO: + result = "VRAD"; + break; + + case AST__VOPTICAL: + result = "VOPT"; + break; + + case AST__REDSHIFT: + result = "ZOPT"; + break; + + case AST__BETA: + result = "BETA"; + break; + + case AST__VREL: + result = "VELO"; + break; + } + +/* Return the result pointer. */ + return result; +} + +static int TestActiveUnit( AstFrame *this_frame, int *status ) { +/* +* Name: +* TestActiveUnit + +* Purpose: +* Test the ActiveUnit flag for a SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* int TestActiveUnit( AstFrame *this_frame, int *status ) + +* Class Membership: +* SpecFrame 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 SpecFrame, +* which is always "unset". + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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 SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* int TestAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* SpecFrame 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 SpecFrame's attributes. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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: */ + AstSpecFrame *this; /* Pointer to the SpecFrame 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 SpecFrame structure. */ + this = (AstSpecFrame *) 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 + SpecFrame 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 ); + } + +/* AlignStdOfRest. */ +/* --------------- */ + } else if ( !strcmp( attrib, "alignstdofrest" ) ) { + result = astTestAlignStdOfRest( this ); + +/* GeoLat. */ +/* ------- */ +/* Retained for backward compatibility with older versions of AST in which + SpecFrame had GeoLon/Lat attributes (now ObsLon/Lat are used instead). */ + } else if ( !strcmp( attrib, "geolat" ) ) { + result = astTestAttrib( this, "obslat" ); + +/* GeoLon. */ +/* ------- */ + } else if ( !strcmp( attrib, "geolon" ) ) { + result = astTestAttrib( this, "obslon" ); + +/* RefDec. */ +/* ------- */ + } else if ( !strcmp( attrib, "refdec" ) ) { + result = astTestRefDec( this ); + +/* RefRA. */ +/* ------ */ + } else if ( !strcmp( attrib, "refra" ) ) { + result = astTestRefRA( this ); + +/* RestFreq. */ +/* --------- */ + } else if ( !strcmp( attrib, "restfreq" ) ) { + result = astTestRestFreq( this ); + +/* SourceVel. */ +/* ---------- */ + } else if ( !strcmp( attrib, "sourcevel" ) ) { + result = astTestSourceVel( this ); + +/* SourceVRF */ +/* --------- */ + } else if ( !strcmp( attrib, "sourcevrf" ) ) { + result = astTestSourceVRF( this ); + +/* SourceSys */ +/* --------- */ + } else if ( !strcmp( attrib, "sourcesys" ) ) { + result = astTestSourceSys( this ); + +/* StdOfRest. */ +/* ---------- */ + } else if ( !strcmp( attrib, "stdofrest" ) ) { + result = astTestStdOfRest( this ); + +/* SpecOrigin. */ +/* --------- */ + } else if ( !strcmp( attrib, "specorigin" ) ) { + result = astTestSpecOrigin( this ); + +/* AlignSpecOffset */ +/* --------------- */ + } else if ( !strcmp( attrib, "alignspecoffset" ) ) { + result = astTestAlignSpecOffset( 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 ToUnits( AstSpecFrame *this, const char *oldunit, double oldval, + const char *method, int *status ){ +/* +* +* Name: +* ToUnits + +* Purpose: +* Convert a supplied spectral value to the default units of the supplied +* SpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "timeframe.h" +* double ToUnits( AstSpecFrame *this, const char *oldunit, double oldval, +* const char *method, int *status ) + +* Class Membership: +* SpecFrame member function + +* Description: +* This function converts the supplied value from the supplied units to +* the default units associated with the supplied SpecFrame's System. + +* Parameters: +* this +* Pointer to the SpecFrame. +* 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 + SpecFrame, and find a Mapping from the old units to the default. */ + defunit = DefUnit( astGetSystem( this ), method, "SpecFrame", 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 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 "specframe.h" +* int ValidateSystem( AstFrame *this, AstSystemType system, +* const char *method, int *status ) + +* Class Membership: +* SpecFrame 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( AstSpecFrame *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 "specframe.h" +* void VerifyAttrs( AstSpecFrame *this, const char *purp, +* const char *attrs, const char *method, int *status ) + +* Class Membership: +* SpecFrame 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 SpecFrame 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 SpecFrame. +* 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; + +/* If the SpecFrame 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 ) ) { + +/* Stop compiler warnings about uninitialised variables */ + a = NULL; + desc = NULL; + len = 0; + set = 0; + +/* 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's latitude"; + + } else if( !strncmp( "ObsLon", a, len ) ) { + set = astTestObsLon( this ); + desc = "observer's longitude"; + + } else if( !strncmp( "ObsAlt", a, len ) ) { + set = astTestObsAlt( this ); + desc = "observer's altitude"; + + } else if( !strncmp( "RefRA", a, len ) ) { + set = astTestRefRA( this ); + desc = "source RA"; + + } else if( !strncmp( "RefDec", a, len ) ) { + set = astTestRefDec( this ); + desc = "source Dec"; + + } else if( !strncmp( "RestFreq", a, len ) ) { + set = astTestRestFreq( this ); + desc = "rest frequency"; + + } else if( !strncmp( "SourceVel", a, len ) ) { + set = astTestSourceVel( this ); + desc = "source velocity"; + + } else if( !strncmp( "StdOfRest", a, len ) ) { + set = astTestStdOfRest( this ); + desc = "spectral standard of rest"; + + } else if( !strncmp( "Epoch", a, len ) ) { + set = astTestEpoch( this ); + desc = "epoch of observation"; + + } else { + astError( AST__INTER, "VerifyAttrs(SpecFrame): " + "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: +* AlignSpecOffset + +* Purpose: +* Align SpecFrames using the offset coordinate system? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute is a boolean value which controls how a SpecFrame +* 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) +* SpecFrame. It determines whether alignment occurs between the offset +* values defined by the current value of the SpecOffset attribute, or +* between the corresponding absolute spectral values. +* +* The default value of zero results in the two SpecFrames being aligned +* so that a given absolute spectral value in one is mapped to the same +* absolute value in the other. A non-zero value results in the SpecFrames +* being aligned so that a given offset value in one is mapped to the same +* offset value in the other. + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. +*att-- +*/ +astMAKE_CLEAR(SpecFrame,AlignSpecOffset,alignspecoffset,-INT_MAX) +astMAKE_GET(SpecFrame,AlignSpecOffset,int,0,( ( this->alignspecoffset != -INT_MAX ) ? + this->alignspecoffset : 0 )) +astMAKE_SET(SpecFrame,AlignSpecOffset,int,alignspecoffset,( value != 0 )) +astMAKE_TEST(SpecFrame,AlignSpecOffset,( this->alignspecoffset != -INT_MAX )) + + + +/* +*att++ +* Name: +* AlignStdOfRest + +* Purpose: +* Standard of rest to use when aligning SpecFrames. + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute controls how a SpecFrame 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) +* SpecFrame. It identifies the standard of rest in which alignment is +* to occur. See the StdOfRest attribute for a desription of the values +* which may be assigned to this attribute. The default AlignStdOfRest +* value is "Helio" (heliographic). +* +c When astFindFrame or astConvert is used on two SpecFrames (potentially +f When AST_FindFrame or AST_CONVERT is used on two SpecFrames (potentially +* describing different spectral coordinate systems), it returns a Mapping +* which can be used to transform a position in one SpecFrame 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 (wavelength, +* apparent radial velocity, etc) to the system specified by the +* AlignSystem attribute, using the target's rest frequency if necessary. +* +* - Map these values from the target's standard of rest to the standard of +* rest specified by the AlignStdOfRest attribute, using the Epoch, ObsLat, +* ObsLon, ObsAlt, RefDec and RefRA attributes of the target to define the +* two standards of rest. +* +* - Map these values from the standard of rest specified by the +* AlignStdOfRest attribute, to the template's standard of rest, using the +* Epoch, ObsLat, ObsLon, ObsAlt, RefDec and RefRA attributes of the +* template to define the two standards of rest. +* +* - Map these values from the system specified by the AlignSystem +* attribute, to the system used by the template, using the template's +* rest frequency if necessary. + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +*att-- +*/ +/* The AlignStdOfRest value has a value of AST__BADSOR when not set yielding + a default of AST__HLSOR. */ +astMAKE_TEST(SpecFrame,AlignStdOfRest,( this->alignstdofrest != AST__BADSOR )) +astMAKE_CLEAR(SpecFrame,AlignStdOfRest,alignstdofrest,AST__BADSOR) +astMAKE_GET(SpecFrame,AlignStdOfRest,AstStdOfRestType,AST__BADSOR,( + ( this->alignstdofrest == AST__BADSOR ) ? AST__HLSOR : this->alignstdofrest ) ) + +/* Validate the AlignStdOfRest value being set and report an error if necessary. */ +astMAKE_SET(SpecFrame,AlignStdOfRest,AstStdOfRestType,alignstdofrest,( + ( ( value >= FIRST_SOR ) && ( value <= LAST_SOR ) ) ? + value : + ( astError( AST__ATTIN, "%s(%s): Bad value (%d) " + "given for AlignStdOfRest attribute.", status, + "astSetAlignStdOfRest", astGetClass( this ), (int) value ), + +/* Leave the value unchanged on error. */ + this->alignstdofrest ) ) ) + +/* +*att++ +* Name: +* RefDec + +* Purpose: +* The declination of the reference point + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute specifies the FK5 J2000.0 declination of a reference +* point on the sky. See the description of attribute RefRA for details. +* The default RefDec is "0:0:0". + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +*att-- +*/ +/* The reference declination (FK5 J2000, radians). Clear the RefDec value by + setting it to AST__BAD, which results in a default value of zero. Any + value is acceptable. */ +astMAKE_CLEAR(SpecFrame,RefDec,refdec,AST__BAD) +astMAKE_GET(SpecFrame,RefDec,double,0.0,((this->refdec!=AST__BAD)?this->refdec:0.0)) +astMAKE_SET(SpecFrame,RefDec,double,refdec,value) +astMAKE_TEST(SpecFrame,RefDec,( this->refdec != AST__BAD )) + +/* +*att++ +* Name: +* RefRA + +* Purpose: +* The right ascension of the reference point + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute, together with the RefDec attribute, specifies the FK5 +* J2000.0 coordinates of a reference point on the sky. For 1-dimensional +* spectra, this should normally be the position of the source. For +* spectral data with spatial coverage (spectral cubes, etc), this should +* be close to centre of the spatial coverage. It is used to define the +* correction for Doppler shift to be applied when using the +c astFindFrame or astConvert +f AST_FINDFRAME or AST_CONVERT +* method to convert between different standards of rest. +* +* The SpecFrame class assumes this velocity correction is spatially +* invariant. If a single SpecFrame is used (for instance, as a +* component of a CmpFrame) to describe spectral values at different +* points on the sky, then it is assumes that the doppler shift at any +* spatial position is the same as at the reference position. The +* maximum velocity error introduced by this assumption is of the order +* of V*SIN(FOV), where FOV is the angular field of view, and V is the +* relative velocity of the two standards of rest. As an example, when +* correcting from the observers rest frame (i.e. the topocentric rest +* frame) to the kinematic local standard of rest the maximum value of V +* is about 20 km/s, so for 5 arc-minute field of view the maximum velocity +* error introduced by the correction will be about 0.03 km/s. As another +* example, the maximum error when correcting from the observers rest frame +* to the local group is about 5 km/s over a 1 degree field of view. +* +* The RefRA and RefDec attributes are stored internally in radians, but +* are converted to and from a string for access. The format "hh:mm:ss.ss" +* is used for RefRA, and "dd:mm:ss.s" is used for RefDec. The methods +c astSetRefPos and astGetRefPos may be used to access the values of +f AST_SETREFPOS and AST_GETREFPOS may be used to access the value of +* these attributes directly as unformatted values in radians. +* +* The default for RefRA is "0:0:0". + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +*att-- +*/ +/* The reference right ascension (FK5 J2000, radians). Clear the RefRA value + by setting it to AST__BAD, which gives a default value of 0.0. Any + value is acceptable. */ +astMAKE_CLEAR(SpecFrame,RefRA,refra,AST__BAD) +astMAKE_GET(SpecFrame,RefRA,double,0.0,((this->refra!=AST__BAD)?this->refra:0.0)) +astMAKE_SET(SpecFrame,RefRA,double,refra,value) +astMAKE_TEST(SpecFrame,RefRA,( this->refra != AST__BAD )) + + +/* +*att++ +* Name: +* RestFreq + +* Purpose: +* The rest frequency. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute specifies the frequency corresponding to zero +* velocity. It is used when converting between between velocity-based +* coordinate systems and and other coordinate systems (such as frequency, +* wavelength, energy, etc). The default value is 1.0E5 GHz. +* +* When setting a new value for this attribute, the new value can be +* supplied either directly as a frequency, or indirectly as a wavelength +* or energy, in which case the supplied value is converted to a frequency +* before being stored. The nature of the supplied value is indicated by +* appending text to the end of the numerical value indicating the units in +* which the value is supplied. If the units are not specified, then the +* supplied value is assumed to be a frequency in units of GHz. If the +* supplied unit is a unit of frequency, the supplied value is assumed to +* be a frequency in the given units. If the supplied unit is a unit of +* length, the supplied value is assumed to be a (vacuum) wavelength. If +* the supplied unit is a unit of energy, the supplied value is assumed to +* be an energy. For instance, the following strings all result in +* a rest frequency of around 1.4E14 Hz being used: "1.4E5", "1.4E14 Hz", +* "1.4E14 s**-1", "1.4E5 GHz", "2.14E-6 m", "21400 Angstrom", "9.28E-20 J", +* "9.28E-13 erg", "0.58 eV", etc. +* +* When getting the value of this attribute, the returned value is +* always a frequency in units of GHz. + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +*att-- +*/ +/* The rest frequency (Hz). Clear the RestFreq value by setting it to AST__BAD, + which gives 1.0E14 as the default value. Any value is acceptable. */ +astMAKE_CLEAR(SpecFrame,RestFreq,restfreq,AST__BAD) +astMAKE_GET(SpecFrame,RestFreq,double,1.0E14,((this->restfreq!=AST__BAD)?this->restfreq:1.0E14)) +astMAKE_SET(SpecFrame,RestFreq,double,restfreq,value) +astMAKE_TEST(SpecFrame,RestFreq,( this->restfreq != AST__BAD )) + +/* +*att++ +* Name: +* SourceVel + +* Purpose: +* The source velocity. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute (together with SourceSys, SourceVRF, RefRA and RefDec) +* defines the "Source" standard of rest (see attribute StdOfRest). This is +* a rest frame which is moving towards the position given by RefRA and +* RefDec at a velocity given by SourceVel. A positive value means +* the source is moving away from the observer. When a new value is +* assigned to this attribute, the supplied value is assumed to refer +* to the spectral system specified by the SourceSys attribute. For +* instance, the SourceVel value may be supplied as a radio velocity, a +* redshift, a beta factor, etc. Similarly, when the current value of +* the SourceVel attribute is obtained, the returned value will refer +* to the spectral system specified by the SourceSys value. If the +* SourceSys value is changed, any value previously stored for the SourceVel +* attribute will be changed automatically from the old spectral system +* to the new spectral system. +* +* When setting a value for SourceVel, the value should be supplied in the +* rest frame specified by the SourceVRF attribute. Likewise, when getting +* the value of SourceVel, it will be returned in the rest frame specified +* by the SourceVRF attribute. +* +* The default SourceVel value is zero. + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +* Notes: +* - It is important to set an appropriate value for SourceVRF and +* SourceSys before setting a value for SourceVel. If a new value is later +* set for SourceVRF or SourceSys, the value stored for SourceVel will +* simultaneously be changed to the new standard of rest or spectral +* system. + +*att-- +*/ +/* The source velocity (velocities are stored internally in m/s). Clear it + by setting it to AST__BAD, which returns a default value of zero. Any + value is acceptable. */ +astMAKE_CLEAR(SpecFrame,SourceVel,sourcevel,AST__BAD) +astMAKE_SET(SpecFrame,SourceVel,double,sourcevel,value) +astMAKE_TEST(SpecFrame,SourceVel,( this->sourcevel != AST__BAD )) +astMAKE_GET(SpecFrame,SourceVel,double,0.0,((this->sourcevel!=AST__BAD)?this->sourcevel:0.0)) + +/* +*att++ +* Name: +* SourceVRF + +* Purpose: +* Rest frame in which the source velocity is stored. + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute identifies the rest frame in which the source +* velocity or redshift is stored (the source velocity or redshift is +* accessed using attribute SourceVel). When setting a new value for the +* SourceVel attribute, the source velocity or redshift should be supplied +* in the rest frame indicated by this attribute. Likewise, when getting +* the value of the SourceVel attribute, the velocity or redshift will be +* returned in this rest frame. +* +* If the value of SourceVRF is changed, the value stored for SourceVel +* will be converted from the old to the new rest frame. +* +* The values which can be supplied are the same as for the StdOfRest +* attribute (except that SourceVRF cannot be set to "Source"). The +* default value is "Helio". + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +*att-- +*/ +/* The SourceVRF value has a value of AST__BADSOR when not set yielding + a default of AST__HLSOR. */ +astMAKE_TEST(SpecFrame,SourceVRF,( this->sourcevrf != AST__BADSOR )) +astMAKE_GET(SpecFrame,SourceVRF,AstStdOfRestType,AST__BADSOR,( + ( this->sourcevrf == AST__BADSOR ) ? AST__HLSOR : this->sourcevrf ) ) + +/* When clearing SourceVRF, convert the SourceVel value to heliocentric + (but only if set)*/ +astMAKE_CLEAR(SpecFrame,SourceVRF,sourcevrf,((astTestSourceVel( this )? + (void)(astSetSourceVel( this, ConvertSourceVel( this, AST__HLSOR, + astGetSourceSys( this ), status ) ),NULL): + NULL),AST__BADSOR)) + +/* Validate the SourceVRF value being set and report an error if necessary. + If OK, convert the stored SourceVel value into the new rest frame (but +only if set)*/ +astMAKE_SET(SpecFrame,SourceVRF,AstStdOfRestType,sourcevrf,( + ( ( value >= FIRST_SOR ) && ( value <= LAST_SOR ) && value != AST__SCSOR ) ? + (astTestSourceVel( this )? + (void)(astSetSourceVel( this,ConvertSourceVel(this,value,astGetSourceSys( this ), status )),NULL): + NULL), value:( astError( AST__ATTIN, "%s(%s): Bad value (%d) " + "given for SourceVRF attribute.", status, + "astSetSourceVRF", astGetClass( this ), (int) value ), + +/* Leave the value unchanged on error. */ + this->sourcevrf ) ) ) + +/* +*att++ +* Name: +* SourceSys + +* Purpose: +* Spectral system in which the source velocity is stored. + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute identifies the spectral system in which the +* SourceVel attribute value (the source velocity) is supplied and +* returned. It can be one of the following: +* +* - "VRAD" or "VRADIO": Radio velocity (km/s) +* - "VOPT" or "VOPTICAL": Optical velocity (km/s) +* - "ZOPT" or "REDSHIFT": Redshift (dimensionless) +* - "BETA": Beta factor (dimensionless) +* - "VELO" or "VREL": Apparent radial ("relativistic") velocity (km/s) +* +* When setting a new value for the SourceVel attribute, the source +* velocity should be supplied in the spectral system indicated +* by this attribute. Likewise, when getting the value of the SourceVel +* attribute, the velocity will be returned in this spectral system. +* +* If the value of SourceSys is changed, the value stored for SourceVel +* will be converted from the old to the new spectral systems. +* +* The default value is "VELO" (apparent radial velocity). + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +*att-- +*/ +/* The SourceSys value has a value of AST__BADSYS when not set yielding + a default of AST__VREL. */ +astMAKE_TEST(SpecFrame,SourceSys,( this->sourcesys != AST__BADSYSTEM )) +astMAKE_GET(SpecFrame,SourceSys,AstSystemType,AST__BADSYSTEM,( + ( this->sourcesys == AST__BADSYSTEM ) ? AST__VREL : this->sourcesys ) ) + +/* When clearing SourceSys, convert the SourceVel value to relativistic + velocity (but only if set) */ +astMAKE_CLEAR(SpecFrame,SourceSys,sourcesys,((astTestSourceVel( this )? +(void)(astSetSourceVel( this, ConvertSourceVel( this, astGetSourceVRF( this ), + AST__VREL, status ) ),NULL):NULL),AST__BADSYSTEM)) + +/* Validate the SourceSys value being set and report an error if necessary. + If OK, convert the stored SourceVel value into the new rest frame (but + only if set)*/ +astMAKE_SET(SpecFrame,SourceSys,AstSystemType,sourcesys,( + ( ( value == AST__VREL ) || ( value == AST__BETA ) || + ( value == AST__VRADIO ) || ( value == AST__REDSHIFT ) || + ( value == AST__VOPTICAL ) ) ? + (astTestSourceVel( this )? + (void)(astSetSourceVel( this, ConvertSourceVel( this, astGetSourceVRF( this ), + value, status )),NULL):NULL), + value: + ( astError( AST__ATTIN, "%s(%s): Bad value (%d) " + "given for SourceSys attribute.", status, + "astSetSourceSys", astGetClass( this ), (int) value ), + +/* Leave the value unchanged on error. */ + this->sourcesys ) ) ) + +/* +*att++ +* Name: +* StdOfRest + +* Purpose: +* Standard of rest. + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute identifies the standard of rest to which the spectral +* axis values of a SpecFrame refer, and may take any of the values +* listed in the "Standards of Rest" section (below). +* +* The default StdOfRest value is "Helio". + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +* Standards of Rest: +* The SpecFrame class supports the following StdOfRest values (all are +* case-insensitive): +* +* - "Topocentric", "Topocent" or "Topo": The observers rest-frame (assumed +* to be on the surface of the earth). Spectra recorded in this standard of +* rest suffer a Doppler shift which varies over the course of a day +* because of the rotation of the observer around the axis of the earth. +* This standard of rest must be qualified using the ObsLat, ObsLon, +* ObsAlt, Epoch, RefRA and RefDec attributes. +* +* - "Geocentric", "Geocentr" or "Geo": The rest-frame of the earth centre. +* Spectra recorded in this standard of rest suffer a Doppler shift which +* varies over the course of a year because of the rotation of the earth +* around the Sun. This standard of rest must be qualified using the Epoch, +* RefRA and RefDec attributes. +* +* - "Barycentric", "Barycent" or "Bary": The rest-frame of the solar-system +* barycentre. Spectra recorded in this standard of rest suffer a Doppler +* shift which depends both on the velocity of the Sun through the Local +* Standard of Rest, and on the movement of the planets through the solar +* system. This standard of rest must be qualified using the Epoch, RefRA +* and RefDec attributes. +* +* - "Heliocentric", "Heliocen" or "Helio": The rest-frame of the Sun. +* Spectra recorded in this standard of rest suffer a Doppler shift which +* depends on the velocity of the Sun through the Local Standard of Rest. +* This standard of rest must be qualified using the RefRA and RefDec +* attributes. +* +* - "LSRK", "LSR": The rest-frame of the kinematical Local Standard of +* Rest. Spectra recorded in this standard of rest suffer a Doppler shift +* which depends on the velocity of the kinematical Local Standard of Rest +* through the galaxy. This standard of rest must be qualified using the +* RefRA and RefDec attributes. +* +* - "LSRD": The rest-frame of the dynamical Local Standard of Rest. Spectra +* recorded in this standard of rest suffer a Doppler shift which depends +* on the velocity of the dynamical Local Standard of Rest through the +* galaxy. This standard of rest must be qualified using the RefRA and +* RefDec attributes. +* +* - "Galactic", "Galactoc" or "Gal": The rest-frame of the galactic centre. +* Spectra recorded in this standard of rest suffer a Doppler shift which +* depends on the velocity of the galactic centre through the local group. +* This standard of rest must be qualified using the RefRA and RefDec +* attributes. +* +* - "Local_group", "Localgrp" or "LG": The rest-frame of the local group. +* This standard of rest must be qualified using the RefRA and RefDec +* attributes. +* +* - "Source", or "src": The rest-frame of the source. This standard of +* rest must be qualified using the RefRA, RefDec and SourceVel attributes. +* +* Where more than one alternative System value is shown above, the +* first of these will be returned when an enquiry is made. +*att-- +*/ +/* The StdOfRest value has a value of AST__BADSOR when not set yielding + a default of AST__HLSOR. */ +astMAKE_TEST(SpecFrame,StdOfRest,( this->stdofrest != AST__BADSOR )) +astMAKE_GET(SpecFrame,StdOfRest,AstStdOfRestType,AST__BADSOR,( + ( this->stdofrest == AST__BADSOR ) ? AST__HLSOR : this->stdofrest ) ) + +/* +*att++ +* Name: +* SpecOrigin + +* Purpose: +* The zero point for SpecFrame axis values + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This specifies the origin from which all spectral values are measured. +* The default value (zero) results in the SpecFrame describing +* absolute spectral values in the system given by the System attribute +* (e.g. frequency, velocity, etc). If a SpecFrame is to be used to +* describe offset from some origin, the SpecOrigin attribute +* should be set to hold the required origin value. The SpecOrigin value +* stored inside the SpecFrame structure is modified whenever SpecFrame +* attribute values are changed so that it refers to the original spectral +* position. +* +* When setting a new value for this attribute, the supplied value is assumed +* to be in the system, units and standard of rest described by the SpecFrame. +* Likewise, when getting the value of this attribute, the value is returned +* in the system, units and standard of rest described by the SpecFrame. If +* any of these attributes are changed, then any previously stored SpecOrigin +* value will also be changed so that refers to the new system, units or +* standard of rest. + +* Applicability: +* SpecFrame +* All SpecFrames have this attribute. + +*att-- +*/ +/* The spec origin, stored internally in the default units associated + with the current System value. Clear the SpecOrigin value by setting it + to AST__BAD, which gives 0.0 as the default value. Any value is acceptable. */ +astMAKE_CLEAR(SpecFrame,SpecOrigin,specorigin,AST__BAD) +astMAKE_GET(SpecFrame,SpecOrigin,double,0.0,((this->specorigin!=AST__BAD)?this->specorigin:0.0)) +astMAKE_SET(SpecFrame,SpecOrigin,double,specorigin,value) +astMAKE_TEST(SpecFrame,SpecOrigin,( this->specorigin != AST__BAD )) + +/* Copy constructor. */ +/* ----------------- */ +static void Copy( const AstObject *objin, AstObject *objout, int *status ) { +/* +* Name: +* Copy + +* Purpose: +* Copy constructor for SpecFrame objects. + +* Type: +* Private function. + +* Synopsis: +* void Copy( const AstObject *objin, AstObject *objout, int *status ) + +* Description: +* This function implements the copy constructor for SpecFrame objects. + +* Parameters: +* objin +* Pointer to the object to be copied. +* objout +* Pointer to the object being constructed. +* status +* Pointer to the inherited status variable. + +* Notes: +* - This constructor makes a deep copy. +*/ + +/* Local Variables: */ + AstSpecFrame *in; /* Pointer to input SpecFrame */ + AstSpecFrame *out; /* Pointer to output SpecFrame */ + char *usedunit; /* Pointer to an element of usedunits array */ + int i; /* Loop count */ + int nused; /* Size of "usedunits" array */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain pointers to the input and output SpecFrames. */ + in = (AstSpecFrame *) objin; + out = (AstSpecFrame *) objout; + +/* Nullify the pointers stored in the output object since these will + currently be pointing at the input data (since the output is a simple + byte-for-byte copy of the input). Otherwise, the input data could be + freed by accidient if the output object is deleted due to an error + occuring in this function. */ + out->usedunits = NULL; + +/* Store the last used units in the output SpecMap. */ + if( in && in->usedunits ) { + nused = in->nuunits; + out->usedunits = astMalloc( nused*sizeof( char * ) ); + if( out->usedunits ) { + for( i = 0; i < nused; i++ ) { + usedunit = in->usedunits[ i ]; + if( usedunit ) { + out->usedunits[ i ] = astStore( NULL, usedunit, + strlen( usedunit ) + 1 ); + } else { + out->usedunits[ i ] = NULL; + } + } + } + } + +/* If an error has occurred, free the output resources. */ + if( !astOK ) Delete( (AstObject *) out, status ); + +} + +/* Destructor. */ +/* ----------- */ +static void Delete( AstObject *obj, int *status ) { +/* +* Name: +* Delete + +* Purpose: +* Destructor for SpecFrame objects. + +* Type: +* Private function. + +* Synopsis: +* void Delete( AstObject *obj, int *status ) + +* Description: +* This function implements the destructor for SpecFrame objects. + +* Parameters: +* obj +* Pointer to the object to be deleted. +* status +* Pointer to the inherited status variable. + +* Notes: +* This function attempts to execute even if the global error status is +* set. +*/ + +/* Local Variables: */ + AstSpecFrame *this; + int i; + +/* Release the memory referred to in the SpecFrame structure. */ + this = (AstSpecFrame *) obj; + if( this && this->usedunits ) { + for( i = 0; i < this->nuunits; i++ ) { + this->usedunits[ i ] = astFree( this->usedunits[ i ] ); + } + this->usedunits = astFree( this->usedunits ); + } +} + +/* Dump function. */ +/* -------------- */ +static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { +/* +* Name: +* Dump + +* Purpose: +* Dump function for SpecFrame 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 SpecFrame class to an output Channel. + +* Parameters: +* this +* Pointer to the SpecFrame 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: */ + AstSpecFrame *this; /* Pointer to the SpecFrame structure */ + AstStdOfRestType sor; /* StdOfRest attribute value */ + AstSystemType sys; /* Spectral system value */ + char buff[ 20 ]; /* Buffer for item name */ + char comm[ 50 ]; /* Buffer for comment */ + const char *sval; /* Pointer to string value */ + double dval; /* Double value */ + int i; /* Loop count */ + int ival; /* int value */ + int j; /* Loop count */ + int set; /* Attribute value set? */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstSpecFrame *) this_object; + +/* Write out values representing the instance variables for the + SpecFrame 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. */ + +/* StdOfRest. */ +/* ---------- */ + set = TestStdOfRest( this, status ); + sor = set ? GetStdOfRest( this, status ) : astGetStdOfRest( this ); + +/* If set, convert explicitly to a string for the external + representation. */ + sval = ""; + if ( set ) { + if ( astOK ) { + sval = StdOfRestString( sor, status ); + +/* Report an error if the StdOfRest value was not recognised. */ + if ( !sval ) { + astError( AST__SCSIN, + "%s(%s): Corrupt %s contains invalid standard of rest " + "identification code (%d).", status, "astWrite", + astGetClass( channel ), astGetClass( this ), (int) sor ); + } + } + +/* If not set, use astGetAttrib which returns a string value using + (possibly over-ridden) methods. */ + } else { + sval = astGetAttrib( this_object, "stdofrest" ); + } + +/* Write out the value. */ + astWriteString( channel, "SoR", set, 1, sval, "Standard of rest" ); + +/* AlignStdOfRest. */ +/* --------------- */ + set = TestAlignStdOfRest( this, status ); + sor = set ? GetAlignStdOfRest( this, status ) : astGetAlignStdOfRest( this ); + +/* If set, convert explicitly to a string for the external representation. */ + if ( set ) { + if ( astOK ) { + sval = StdOfRestString( sor, status ); + +/* Report an error if the StdOfRest value was not recognised. */ + if ( !sval ) { + astError( AST__SCSIN, + "%s(%s): Corrupt %s contains invalid alignment standard " + "of rest identification code (%d).", status, "astWrite", + astGetClass( channel ), astGetClass( this ), (int) sor ); + } + } + +/* If not set, use astGetAttrib which returns a string value using + (possibly over-ridden) methods. */ + } else { + sval = astGetAttrib( this_object, "alignstdofrest" ); + } + +/* Write out the value. */ + astWriteString( channel, "AlSoR", set, 0, sval, "Alignment standard of rest" ); + +/* RefRA. */ +/* ------ */ + set = TestRefRA( this, status ); + dval = set ? GetRefRA( this, status ) : astGetRefRA( this ); + astWriteDouble( channel, "RefRA", set, 0, dval, "Reference RA (rads, FK5 J2000)" ); + +/* RefDec. */ +/* ------- */ + set = TestRefDec( this, status ); + dval = set ? GetRefDec( this, status ) : astGetRefDec( this ); + astWriteDouble( channel, "RefDec", set, 0, dval, "Reference Dec (rads, FK5 J2000)" ); + +/* RestFreq. */ +/* --------- */ + set = TestRestFreq( this, status ); + dval = set ? GetRestFreq( this, status ) : astGetRestFreq( this ); + astWriteDouble( channel, "RstFrq", set, 0, dval, "Rest frequency (Hz)" ); + +/* SourceVel. */ +/* ---------- */ + set = TestSourceVel( this, status ); + dval = set ? GetSourceVel( this, status ) : astGetSourceVel( this ); + astWriteDouble( channel, "SrcVel", set, 0, dval, "Source velocity (m/s)" ); + +/* SourceVRF. */ +/* ---------- */ + set = TestSourceVRF( this, status ); + sor = set ? GetSourceVRF( this, status ) : astGetSourceVRF( this ); + +/* If set, convert explicitly to a string for the external representation. */ + if ( set ) { + if ( astOK ) { + sval = StdOfRestString( sor, status ); + +/* Report an error if the value was not recognised. */ + if ( !sval ) { + astError( AST__SCSIN, + "%s(%s): Corrupt %s contains invalid source velocity " + "rest frame identification code (%d).", status, "astWrite", + astGetClass( channel ), astGetClass( this ), (int) sor ); + } + } + +/* If not set, use astGetAttrib which returns a string value using + (possibly over-ridden) methods. */ + } else { + sval = astGetAttrib( this_object, "sourcevrf" ); + } + +/* Write out the value. */ + astWriteString( channel, "SrcVRF", set, 0, sval, "Source velocity rest frame" ); + +/* SourceSys. */ +/* ---------- */ + set = TestSourceSys( this, status ); + sys = set ? GetSourceSys( this, status ) : astGetSourceSys( this ); + +/* If set, convert explicitly to a string for the external representation. */ + if ( set ) { + if ( astOK ) { + sval = SystemString( (AstFrame *) this, sys, status ); + +/* Report an error if the value was not recognised. */ + if ( !sval ) { + astError( AST__SCSIN, + "%s(%s): Corrupt %s contains invalid source velocity " + "spectral system identification code (%d).", status, "astWrite", + astGetClass( channel ), astGetClass( this ), (int) sys ); + } + } + +/* If not set, use astGetAttrib which returns a string value using + (possibly over-ridden) methods. */ + } else { + sval = astGetAttrib( this_object, "sourcesys" ); + } + +/* Write out the value. */ + astWriteString( channel, "SrcSys", set, 0, sval, "Source velocity spectral system" ); + +/* AlignSpecOffset. */ +/* ---------------- */ + set = TestAlignSpecOffset( this, status ); + ival = set ? GetAlignSpecOffset( this, status ) : astGetAlignSpecOffset( this ); + astWriteInt( channel, "AlSpOf", set, 0, ival, + ival ? "Align in offset coords" : + "Align in system coords" ); + +/* UsedUnits */ +/* --------- */ + if( this->usedunits ) { + for( i = 0; i < this->nuunits; i++ ) { + if( this->usedunits[ i ] ) { + sprintf( buff, "U%s", astSystemString( this, (AstSystemType) i )); + for( j = 2; j < strlen( buff ); j++ ) buff[ j ] = tolower( buff[ j ] ); + sprintf( comm, "Preferred units for %s", SystemLabel( (AstSystemType) i, status ) ); + astWriteString( channel, buff, 1, 0, this->usedunits[ i ], comm ); + } + } + } + +/* SpecOrigin. */ +/* ----------- */ + set = TestSpecOrigin( this, status ); + dval = set ? GetSpecOrigin( this, status ) : astGetSpecOrigin( this ); + if( dval != AST__BAD ) { + astWriteDouble( channel, "SpOrg", set, 0, dval, "Spec offset" ); + } + +} + +/* Standard class functions. */ +/* ========================= */ +/* Implement the astIsASpecFrame and astCheckSpecFrame functions using the + macros defined for this purpose in the "object.h" header file. */ +astMAKE_ISA(SpecFrame,Frame) +astMAKE_CHECK(SpecFrame) + +AstSpecFrame *astSpecFrame_( const char *options, int *status, ...) { +/* +*+ +* Name: +* astSpecFrame + +* Purpose: +* Create a SpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "specframe.h" +* AstSpecFrame *astSpecFrame( const char *options, int *status, ... ) + +* Class Membership: +* SpecFrame constructor. + +* Description: +* This function creates a new SpecFrame 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 SpecFrame. 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 SpecFrame. + +* 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 SpecFrame constructor which +* is available via the protected interface to the SpecFrame class. +* A public interface is provided by the astSpecFrameId_ function. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstMapping *um; /* Mapping from default to actual units */ + AstSpecFrame *new; /* Pointer to new SpecFrame */ + 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 SpecFrame, allocating memory and initialising the virtual + function table as well if necessary. */ + new = astInitSpecFrame( NULL, sizeof( AstSpecFrame ), !class_init, + &class_vtab, "SpecFrame" ); + +/* 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 SpecFrame'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, "astSpecFrame", "SpecFrame", status ), + u, NULL, NULL ); + if( um ) { + um = astAnnul( um ); + } else { + astError( AST__BADUN, "astSpecFrame: 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 SpecFrame. */ + return new; +} + +AstSpecFrame *astInitSpecFrame_( void *mem, size_t size, int init, + AstSpecFrameVtab *vtab, const char *name, int *status ) { +/* +*+ +* Name: +* astInitSpecFrame + +* Purpose: +* Initialise a SpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "specframe.h" +* AstSpecFrame *astInitSpecFrame( void *mem, size_t size, int init, +* AstFrameVtab *vtab, const char *name ) + +* Class Membership: +* SpecFrame initialiser. + +* Description: +* This function is provided for use by class implementations to +* initialise a new SpecFrame object. It allocates memory (if +* necessary) to accommodate the SpecFrame plus any additional data +* associated with the derived class. It then initialises a +* SpecFrame 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 SpecFrame at the start of the memory passed via the +* "vtab" parameter. + +* Parameters: +* mem +* A pointer to the memory in which the SpecFrame is to be +* created. This must be of sufficient size to accommodate the +* SpecFrame data (sizeof(SpecFrame)) 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 SpecFrame (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 SpecFrame structure, so a valid value must be supplied +* even if not required for allocating memory. +* init +* A logical flag indicating if the SpecFrame'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 SpecFrame. +* 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 SpecFrame. + +* 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: */ + AstSpecFrame *new; /* Pointer to the new SpecFrame */ + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* If necessary, initialise the virtual function table. */ + if ( init ) astInitSpecFrameVtab( vtab, name ); + +/* Initialise a 1D Frame structure (the parent class) as the first component + within the SpecFrame structure, allocating memory if necessary. */ + new = (AstSpecFrame *) astInitFrame( mem, size, 0, + (AstFrameVtab *) vtab, name, 1 ); + + if ( astOK ) { + +/* Initialise the SpecFrame data. */ +/* ----------------------------- */ +/* Initialise all attributes to their "undefined" values. */ + new->alignstdofrest = AST__BADSOR; + new->refdec = AST__BAD; + new->refra = AST__BAD; + new->restfreq = AST__BAD; + new->sourcevel = AST__BAD; + new->sourcevrf = AST__BADSOR; + new->sourcesys = AST__BADSYSTEM; + new->stdofrest = AST__BADSOR; + new->nuunits = 0; + new->usedunits = NULL; + new->specorigin = AST__BAD; + new->alignspecoffset = -INT_MAX; + +/* 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; +} + +AstSpecFrame *astLoadSpecFrame_( void *mem, size_t size, + AstSpecFrameVtab *vtab, + const char *name, AstChannel *channel, int *status ) { +/* +*+ +* Name: +* astLoadSpecFrame + +* Purpose: +* Load a SpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "specframe.h" +* AstSpecFrame *astLoadSpecFrame( void *mem, size_t size, +* AstSpecFrameVtab *vtab, +* const char *name, AstChannel *channel ) + +* Class Membership: +* SpecFrame loader. + +* Description: +* This function is provided to load a new SpecFrame 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 +* SpecFrame structure in this memory, using data read from the +* input Channel. + +* Parameters: +* mem +* A pointer to the memory into which the SpecFrame is to be +* loaded. This must be of sufficient size to accommodate the +* SpecFrame data (sizeof(SpecFrame)) 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 SpecFrame (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 SpecFrame 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(AstSpecFrame) is used instead. +* vtab +* Pointer to the start of the virtual function table to be +* associated with the new SpecFrame. If this is NULL, a pointer +* to the (static) virtual function table for the SpecFrame 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 "SpecFrame" is used instead. + +* Returned Value: +* A pointer to the new SpecFrame. + +* 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 */ + AstSpecFrame *new; /* Pointer to the new SpecFrame */ + char buff[ 20 ]; /* Buffer for item name */ + char *sval; /* Pointer to string value */ + double obslat; /* Value for ObsLat attribute */ + double obslon; /* Get a pointer to the thread specific global data structure. */ + +/* Value for ObsLon attribute */ + int i; /* Loop count */ + int j; /* Loop count */ + int nc; /* String length */ + int sys; /* System value */ + + 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 SpecFrame. In this case the + SpecFrame belongs to this class, so supply appropriate values to be + passed to the parent class loader (and its parent, etc.). */ + if ( !vtab ) { + size = sizeof( AstSpecFrame ); + vtab = &class_vtab; + name = "SpecFrame"; + +/* If required, initialise the virtual function table for this class. */ + if ( !class_init ) { + astInitSpecFrameVtab( 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 SpecFrame. */ + 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, "SpecFrame" ); + +/* 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. */ + +/* StdOfRest. */ +/* ---------- */ +/* Set the default and read the external representation as a string. */ + new->stdofrest = AST__BADSOR; + sval = astReadString( channel, "sor", NULL ); + +/* If a value was read, convert from a string to a StdOfRest code. */ + if ( sval ) { + if ( astOK ) { + new->stdofrest = StdOfRestCode( sval, status ); + +/* Report an error if the value wasn't recognised. */ + if ( new->stdofrest == AST__BADSOR ) { + astError( AST__ATTIN, + "astRead(%s): Invalid standard of rest description " + "\"%s\".", status, astGetClass( channel ), sval ); + } + } + +/* Free the string value. */ + sval = astFree( sval ); + } + +/* AlignStdOfRest. */ +/* --------------- */ +/* Set the default and read the external representation as a string. */ + new->alignstdofrest = AST__BADSOR; + sval = astReadString( channel, "alsor", NULL ); + +/* If a value was read, convert from a string to a StdOfRest code. */ + if ( sval ) { + if ( astOK ) { + new->alignstdofrest = StdOfRestCode( sval, status ); + +/* Report an error if the value wasn't recognised. */ + if ( new->alignstdofrest == AST__BADSOR ) { + astError( AST__ATTIN, + "astRead(%s): Invalid alignment standard of rest " + "description \"%s\".", status, astGetClass( channel ), sval ); + } + } + +/* Free the string value. */ + sval = astFree( sval ); + } + +/* GeoLat. */ +/* ------- */ +/* Retained for backward compatibility with older versions of AST in + which SpecFrame had a GeoLat attribute (now ObsLat is used instead). */ + if( !astTestObsLat( new ) ) { + obslat = astReadDouble( channel, "geolat", AST__BAD ); + if ( obslat != AST__BAD ) astSetObsLat( new, obslat ); + } + +/* GeoLon. */ +/* ------- */ +/* Retained for backward compatibility with older versions of AST in + which SpecFrame had a GeoLon attribute (now ObsLon is used instead). */ + if( !astTestObsLon( new ) ) { + obslon = astReadDouble( channel, "geolon", AST__BAD ); + if ( obslon != AST__BAD ) astSetObsLon( new, obslon ); + } + +/* RefRA. */ +/* ------ */ + new->refra = astReadDouble( channel, "refra", AST__BAD ); + if ( TestRefRA( new, status ) ) SetRefRA( new, new->refra, status ); + +/* RefDec. */ +/* ------- */ + new->refdec = astReadDouble( channel, "refdec", AST__BAD ); + if ( TestRefDec( new, status ) ) SetRefDec( new, new->refdec, status ); + +/* RestFreq. */ +/* --------- */ + new->restfreq = astReadDouble( channel, "rstfrq", AST__BAD ); + if ( TestRestFreq( new, status ) ) SetRestFreq( new, new->restfreq, status ); + +/* AlignSpecOffset */ +/* --------------- */ + new->alignspecoffset = astReadInt( channel, "alspof", -INT_MAX ); + if ( TestAlignSpecOffset( new, status ) ) SetAlignSpecOffset( new, new->alignspecoffset, status ); + +/* SourceVel. */ +/* ---------- */ + new->sourcevel = astReadDouble( channel, "srcvel", AST__BAD ); + if ( TestSourceVel( new, status ) ) SetSourceVel( new, new->sourcevel, status ); + +/* SourceVRF */ +/* --------- */ +/* Set the default and read the external representation as a string. */ + new->sourcevrf = AST__BADSOR; + sval = astReadString( channel, "srcvrf", NULL ); + +/* If a value was read, convert from a string to a StdOfRest code. */ + if ( sval ) { + if ( astOK ) { + new->sourcevrf = StdOfRestCode( sval, status ); + +/* Report an error if the value wasn't recognised. */ + if ( new->sourcevrf == AST__BADSOR ) { + astError( AST__ATTIN, + "astRead(%s): Invalid source velocity rest frame " + "description \"%s\".", status, astGetClass( channel ), sval ); + } + } + +/* Free the string value. */ + sval = astFree( sval ); + } + +/* SourceSys */ +/* --------- */ +/* Set the default and read the external representation as a string. */ + new->sourcesys = AST__BADSYSTEM; + sval = astReadString( channel, "srcsys", NULL ); + +/* If a value was read, convert from a string to a System code. */ + if ( sval ) { + if ( astOK ) { + new->sourcesys = SystemCode( (AstFrame *) new, sval, status ); + +/* Report an error if the value wasn't recognised. */ + if ( new->sourcesys == AST__BADSYSTEM ) { + astError( AST__ATTIN, + "astRead(%s): Invalid source velocity spectral system " + "description \"%s\".", status, astGetClass( channel ), sval ); + } + } + +/* Free the string value. */ + sval = astFree( sval ); + } + +/* UsedUnits */ +/* --------- */ + new->nuunits = 0; + new->usedunits = NULL; + for( sys = FIRST_SYSTEM; sys <= LAST_SYSTEM; sys++ ) { + nc = sprintf( buff, "u%s", astSystemString( new, (AstSystemType) sys )); + for( j = 0; j < nc; j++ ) buff[ j ] = tolower( buff[ j ] ); + sval = astReadString( channel, buff, NULL ); + if( sval ) { + if( (int) sys >= new->nuunits ) { + new->usedunits = astGrow( new->usedunits, sys + 1, + sizeof(char *) ); + if( astOK ) { + for( i = new->nuunits; i < sys + 1; i++ ) new->usedunits[ i ] = NULL; + new->nuunits = sys + 1; + } + } else { + new->usedunits[ sys ] = astFree( new->usedunits[ sys ] ); + } + if( astOK ) { + new->usedunits[ sys ] = astStore( new->usedunits[ sys ], + sval, strlen( sval ) + 1 ); + } + sval = astFree( sval); + } + } + +/* SpecOrigin. */ +/* --------- */ + new->specorigin = astReadDouble( channel, "sporg", AST__BAD ); + if ( TestSpecOrigin( new, status ) ) SetSpecOrigin( new, new->specorigin, status ); + + +/* If an error occurred, clean up by deleting the new SpecFrame. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return the new SpecFrame 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 astGetRefPos_( AstSpecFrame *this, AstSkyFrame *frm, double *lon, + double *lat, int *status ){ + if ( !astOK ) return; + (**astMEMBER(this,SpecFrame,GetRefPos))(this,frm,lon,lat, status ); +} +void astSetRefPos_( AstSpecFrame *this, AstSkyFrame *frm, double lon, + double lat, int *status ){ + if ( !astOK ) return; + (**astMEMBER(this,SpecFrame,SetRefPos))(this,frm,lon,lat, status ); +} + +void astSetStdOfRest_( AstSpecFrame *this, AstStdOfRestType value, int *status ){ + if ( !astOK ) return; + (**astMEMBER(this,SpecFrame,SetStdOfRest))(this,value, status ); +} + +void astClearStdOfRest_( AstSpecFrame *this, int *status ){ + if ( !astOK ) return; + (**astMEMBER(this,SpecFrame,ClearStdOfRest))(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. */ +AstSpecFrame *astSpecFrameId_( const char *, ... ); + +/* Special interface function implementations. */ +/* ------------------------------------------- */ +AstSpecFrame *astSpecFrameId_( const char *options, ... ) { +/* +*++ +* Name: +c astSpecFrame +f AST_SPECFRAME + +* Purpose: +* Create a SpecFrame. + +* Type: +* Public function. + +* Synopsis: +c #include "specframe.h" +c AstSpecFrame *astSpecFrame( const char *options, ... ) +f RESULT = AST_SPECFRAME( OPTIONS, STATUS ) + +* Class Membership: +* SpecFrame constructor. + +* Description: +* This function creates a new SpecFrame and optionally initialises +* its attributes. +* +* A SpecFrame is a specialised form of one-dimensional Frame which +* represents various coordinate systems used to describe positions within +* an electro-magnetic spectrum. The particular coordinate system to be +* used is specified by setting the SpecFrame's System attribute (the +* default is wavelength) qualified, as necessary, by other attributes +* such as the rest frequency, the standard of rest, the epoch of +* observation, etc (see the description of the System attribute for +* details). +* +* By setting a value for thr SpecOrigin attribute, a SpecFrame can be made +* to represent offsets from a given spectral position, rather than absolute + +* 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 SpecFrame. 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 SpecFrame. 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 astSpecFrame() +f AST_SPECFRAME = INTEGER +* A pointer to the new SpecFrame. + +* Examples: +c frame = astSpecFrame( "" ); +f FRAME = AST_SPECFRAME( ' ', STATUS ) +* Creates a SpecFrame to describe the default wavelength spectral +* coordinate system. The RestFreq attribute (rest frequency) is +* unspecified, so it will not be possible to align this SpecFrame +* with another SpecFrame on the basis of a velocity-based system. The +* standard of rest is also unspecified. This means that alignment +* will be possible with other SpecFrames, but no correction will be +* made for Doppler shift caused by change of rest frame during the +* alignment. +c frame = astSpecFrame( "System=VELO, RestFreq=1.0E15, StdOfRest=LSRK" ); +f FRAME = AST_SPECFRAME( 'System=VELO, RestFreq=1.0E15, StdOfRest=LSRK', STATUS ) +* Creates a SpecFrame describing a apparent radial velocity ("VELO") axis +* with rest frequency 1.0E15 Hz (about 3000 Angstroms), measured +* in the kinematic Local Standard of Rest ("LSRK"). Since the +* source position has not been specified (using attributes RefRA and +* RefDec), it will only be possible to align this SpecFrame with +* other SpecFrames which are also measured in the LSRK standard of +* rest. + +* Notes: +* - When conversion between two SpecFrames is requested (as when +c supplying SpecFrames to astConvert), +f supplying SpecFrames AST_CONVERT), +* account will be taken of the nature of the spectral coordinate systems +* they represent, together with any qualifying rest frequency, standard +* of rest, epoch values, etc. The AlignSystem and AlignStdOfRest +* attributes will also be taken into account. The results will therefore +* fully reflect the relationship between positions measured in the two +* systems. In addition, any difference in the Unit attributes of the two +* systems 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 astSpecFrame constructor function. It returns an ID value +* (instead of a true C pointer) to external users, and must be +* provided because astSpecFrame_ 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 astSpecFrame_ 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 */ + AstSpecFrame *new; /* Pointer to new SpecFrame */ + AstSystemType s; /* System */ + const char *u; /* Units string */ + va_list args; /* Variable argument list */ + + int *status; /* Pointer to inherited status value */ + astGET_GLOBALS(NULL); /* Get a pointer to the thread specific global data structure. */ + +/* Get a pointer to the inherited status value. */ + status = astGetStatusPtr; + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* Initialise the SpecFrame, allocating memory and initialising the virtual + function table as well if necessary. */ + new = astInitSpecFrame( NULL, sizeof( AstSpecFrame ), !class_init, + &class_vtab, "SpecFrame" ); + +/* 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 SpecFrame'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, "astSpecFrame", "SpecFrame", status ), + u, NULL, NULL ); + if( um ) { + um = astAnnul( um ); + } else { + astError( AST__BADUN, "astSpecFrame: 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 SpecFrame. */ + return astMakeId( new ); +} + |