/* *class++ * Name: * XmlChan * Purpose: * I/O Channel using XML to represent Objects. * Constructor Function: c astXmlChan f AST_XMLCHAN * Description: * A XmlChan is a specialised form of Channel which supports XML I/O * operations. Writing an Object to an XmlChan (using c astWrite) will, if the Object is suitable, generate an f AST_WRITE) will, if the Object is suitable, generate an * XML description of that Object, and reading from an XmlChan will * create a new Object from its XML description. * * Normally, when you use an XmlChan, you should provide "source" c and "sink" functions which connect it to an external data store c by reading and writing the resulting XML text. These functions f and "sink" routines which connect it to an external data store f by reading and writing the resulting XML text. These routines * should perform any conversions needed between external character c encodings and the internal ASCII encoding. If no such functions f encodings and the internal ASCII encoding. If no such routines * are supplied, a Channel will read from standard input and write * to standard output. * * Alternatively, an XmlChan can be told to read or write from * specific text files using the SinkFile and SourceFile attributes, * in which case no sink or source function need be supplied. * Inheritance: * The XmlChan class inherits from the Channel class. * Attributes: * In addition to those attributes common to all Channels, every * XmlChan also has the following attributes: * * - XmlFormat: System for formatting Objects as XML * - XmlLength: Controls output buffer length * - XmlPrefix: The namespace prefix to use when writing * Functions: c The XmlChan class does not define any new functions beyond those f The XmlChan class does not define any new routines beyond those * which are applicable to all Mappings. * Copyright: * Copyright (C) 1997-2006 Council for the Central Laboratory of the * Research Councils * Copyright (C) 2009 Science & Technology Facilities Council. * All Rights Reserved. * 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 * . * Authors: * DSB: David Berry (Starlink) * History: * 10-OCT-2003 (DSB): * Original version. * 6-FEB-2004 (DSB): * Added XmlPrefix and XmlFormat attributes. * 10-FEB-2004 (DSB): * - Added debug conditional code to keep track of memory leaks. * - Fixed bug which prevented more than 1 object being read from * an XmlChan. * 7-DEC-2005 (DSB): * Free memory allocated by calls to astReadString. * 12-FEB-2010 (DSB): * Represent AST__BAD externally using the string "". *class-- * Further STC work: * - Speed up general STC processing (a lot of time seems to be spent * simplifying things) * - Document (including a complete description of what is and is not * supported in the reference docs for the XmlFormat attribute). * - Produce a schema describing the format which can in fact be read by * AST. * - Look at Jonathan McDowell's mini-STC schema (also STC stuff in * spectral data model) * - Web services. Read only: test STCs for overlap, test points for * inclusion/exclusion, plot a mask over an image, verification (can AST * read it & does it generate warnings?). Read/Write: convert FITS to STC, * transform STC into a new coord system. * - Add support for writing as well as reading * - Modify Stc... constructors to check that the supplied Frame is suitable. * - What about multiple AstroCoordFrames and AstroCoordAreas in a STC? * - Add support for generic CoordFrames * - What should be done with pixel coords info within STC? * - Extend coverage (e.g. to 3D space frames, etc) */ /* 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 XmlChan /* The XML element name used to store an AST attribute setting */ #define ATTR "_attribute" /* The XML element name used for an AST "isa" element */ #define ISA "_isa" /* The XML attribute name which holds the name of the AST class which defines the item contained in the element. */ #define DEFINEDBY "definedby" /* The XML attribute name which holds the name of the AST attribute */ #define NAME "name" /* The XML attribute name which holds the value of the AST attribute */ #define VALUE "value" /* The XML attribute name which indicates if the AST attribute value is a default value. */ #define DEFAULT "default" /* The XML attribute name which indicates if the AST attribute value was originally a string value. */ #define QUOTED "quoted" /* The XML attribute name which holds a description of the AST attribute. */ #define DESC "desc" /* The XML attribute name which holds the label associated with an AST Object (if any). */ #define LABEL "label" /* A string used to indicate atrue attribute value */ #define TRUE "true" /* Format identifiers and strings */ #define UNKNOWN_FORMAT -1 #define NATIVE_FORMAT 0 #define QUOTED_FORMAT 1 #define IVOA_FORMAT 2 #define MAX_FORMAT 2 #define UNKNOWN_STRING "UNKNOWN" #define NATIVE_STRING "NATIVE" #define QUOTED_STRING "QUOTED" #define IVOA_STRING "IVOA" /* Values representing message severities. */ #define WARNING 0 #define FAILURE 1 #define RESET 2 /* Known IVOA namespaces. When a new name is added, update the FindIVOAClass function. */ #define STC_URI "urn:nvo-stc" /* Known IVOA Classes and attributes. When a new name is added, it may be necessary to update the FindIVOAClass function. */ #define STC_RESOURCE_PROFILE "STCResourceProfile" #define SEARCH_LOCATION "SearchLocation" #define OBSERVATION_LOCATION "ObservationLocation" #define OBSERVATORY_LOCATION "ObservatoryLocation" #define CATALOG_ENTRY_LOCATION "CatalogEntryLocation" #define OBS_DATA_LOCATION "ObsDataLocation" #define ASTRO_COORD_SYSTEM "AstroCoordSystem" #define ASTRO_COORD_AREA "AstroCoordArea" #define ASTRO_COORDS "AstroCoords" #define TIME_FRAME "TimeFrame" #define SPACE_FRAME "SpaceFrame" #define SPECTRAL_FRAME "SpectralFrame" #define REDSHIFT_FRAME "RedshiftFrame" #define DOPPLER_DEFINITION "DopplerDefinition" /* Returns string "an" or "a" depending on whether the first character of the supplied string is a vowel or not. */ #define ANA(t) (t?(strchr("AaEeIiOoUu",t[0])?"an":"a"):"") /* String used to represent AST__BAD externally. */ #define BAD_STRING "" /* Include files. */ /* ============== */ /* Interface definitions. */ /* ---------------------- */ #include "globals.h" /* Thread-safe global data access */ #include "error.h" /* Error reporting facilities */ #include "memory.h" /* Memory allocation facilities */ #include "object.h" /* Base Object class */ #include "frame.h" /* Coordinate Frames */ #include "timeframe.h" /* Time coordinate Frames */ #include "cmpframe.h" /* Coordinate Frames */ #include "skyframe.h" /* Celestial coordinate Frames */ #include "specframe.h" /* Spectral coordinate Frames */ #include "region.h" /* Regions within coordinate Frames */ #include "ellipse.h" /* Ellipses within coordinate Frames */ #include "pointlist.h" /* Points within coordinate Frames */ #include "polygon.h" /* Polygons within coordinate Frames */ #include "circle.h" /* Circles within coordinate Frames */ #include "keymap.h" /* Mapping of keys to values */ #include "channel.h" /* Interface for parent class */ #include "xmlchan.h" /* Interface definition for this class */ #include "loader.h" /* Interface to the global loader */ #include "object.h" /* Base Object class */ #include "wcsmap.h" /* Angular conversion constants */ #include "xml.h" /* AST XML facilities */ #include "erfa.h" /* ERFA functions */ #include "stcresourceprofile.h" /* IVOA StcResourceProfile class */ #include "stcsearchlocation.h" /* IVOA SearchLocation class */ #include "stccatalogentrylocation.h"/* IVOA CatalogEntryLocation class */ #include "stcobsdatalocation.h" /* IVOA ObsDataLocation class */ #include "nullregion.h" /* Null regions */ #include "interval.h" /* Axis intervals */ #include "box.h" /* Box regions */ #include "cmpregion.h" /* Compound regions */ #include "prism.h" /* Prism regions */ #include "unitmap.h" /* Unit Mappings */ #include "unit.h" /* Unit handling utilities */ #include "pal.h" /* slalib functions */ #include "globals.h" /* Thread-safe global data access */ /* Error code definitions. */ /* ----------------------- */ #include "ast_err.h" /* AST error codes */ /* C header files. */ /* --------------- */ #include #include #include #include #include #include #include /* Type Definitions */ /* ================ */ /* A type for functions which read an IVOA element and return a corresponding AST Object. */ typedef AstObject *(*IVOAReader)( AstXmlChan *, AstXmlElement *, int * ); /* A structure to hold the result of scanning the content of an IVOA element.*/ typedef struct IVOAScan { int n; /* Number of element names described by this structure */ int *count; /* Array holding number of each element name found */ AstXmlElement ***el; /* Array holding pointers to each element found */ } IVOAScan; /* Module Variables. */ /* ================= */ /* Address of this static variable is used as a unique identifier for member of this class. */ static int class_check; /* Pointers to parent class methods which are extended by this class. */ static const char *(* parent_getattrib)( AstObject *, const char *, int * ); static int (* parent_testattrib)( AstObject *, const char *, int * ); static void (* parent_clearattrib)( AstObject *, const char *, int * ); static void (* parent_setattrib)( AstObject *, const char *, int * ); static int (* parent_getfull)( AstChannel *, int * ); static int (* parent_getcomment)( AstChannel *, int * ); static int (* parent_getindent)( AstChannel *, int * ); /* Text values used to represent XmlFormat values externally. These should be in the order defined by the associated constants above. */ static const char *xformat[3] = { NATIVE_STRING, QUOTED_STRING, IVOA_STRING }; /* 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->IsUsable_This = NULL; \ globals->GetAttrib_Buff[ 0 ] = 0; \ globals->GetNextChar_C = NULL; \ globals->GetNextChar_Buf = NULL; /* Create the function that initialises global data for this module. */ astMAKE_INITGLOBALS(XmlChan) /* Define macros for accessing each item of thread specific global data. */ #define class_init astGLOBAL(XmlChan,Class_Init) #define class_vtab astGLOBAL(XmlChan,Class_Vtab) #define isusable_this astGLOBAL(XmlChan,IsUsable_This) #define getattrib_buff astGLOBAL(XmlChan,GetAttrib_Buff) #define getnextchar_c astGLOBAL(XmlChan,GetNextChar_C) #define getnextchar_buf astGLOBAL(XmlChan,GetNextChar_Buf) /* If thread safety is not needed, declare and initialise globals at static variables. */ #else /* An XmlChan pointer use to communicate with the IsUsable function. */ static AstXmlChan *isusable_this = NULL; /* Buffer returned by GetAttrib. */ static char getattrib_buff[ 51 ]; /* Variables used in GetNextChar */ static char *getnextchar_c = NULL; /* Pointer to next character to read */ static char *getnextchar_buf = NULL; /* Pointer to previously read text */ /* Define the class virtual function table and its initialisation flag as static variables. */ static AstXmlChanVtab class_vtab; /* Virtual function table */ static int class_init = 0; /* Virtual function table initialised? */ #endif /* External 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. */ AstXmlChan *astXmlChanForId_( const char *(*)( void ), char *(*)( const char *(*)( void ), int * ), void (*)( const char * ), void (*)( void (*)( const char * ), const char *, int * ), const char *, ... ); AstXmlChan *astXmlChanId_( const char *(* source)( void ), void (* sink)( const char * ), const char *options, ... ); /* Prototypes for Private Member Functions. */ /* ======================================== */ static AstObject *AstroCoordSystemReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *MakeAstFromXml( AstXmlChan *, AstXmlElement *, int * ); static AstObject *ObsDataLocationReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *Read( AstChannel *, int * ); static AstObject *ReadObject( AstChannel *, const char *, AstObject *, int * ); static AstObject *RedshiftFrameReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *SpaceFrameReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *SpectralFrameReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *StcMetadataReader( AstXmlChan *, AstXmlElement *, int * ); static AstObject *TimeFrameReader( AstXmlChan *, AstXmlElement *, int * ); static AstPointList *ObservatoryLocationReader( AstXmlChan *, AstXmlElement *, AstStcObsDataLocation *, int * ); static AstRegion *AllSkyReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *AstroCoordAreaReader( AstXmlChan *, AstXmlElement *, AstFrame *, AstRegion *[4], int, AstKeyMap **, int * ); static AstRegion *BoxReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *CircleReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *ConstraintReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *ConvexReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *Coord2VecIntervalReader( AstXmlChan *, AstXmlElement *, const char *, AstFrame *, int * ); static AstRegion *Coord3VecIntervalReader( AstXmlChan *, AstXmlElement *, const char *, AstFrame *, int * ); static AstRegion *CoordScalarIntervalReader( AstXmlChan *, AstXmlElement *, const char *, AstFrame *, int * ); static AstRegion *EllipseReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *IntersectionReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *NegationReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *PolygonReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *Position2DReader( AstXmlChan *, AstXmlElement *, AstFrame *, double *, AstKeyMap **, int * ); static AstRegion *PositionIntervalReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *RedshiftIntervalReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *RedshiftReader( AstXmlChan *, AstXmlElement *, AstFrame *, AstKeyMap **, int * ); static AstRegion *StcRegionReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *RegionReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *SpectralIntervalReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *SpectralReader( AstXmlChan *, AstXmlElement *, AstFrame *, double *, AstKeyMap **, int * ); static AstRegion *SphereReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstRegion *TimeIntervalReader( AstXmlChan *, AstXmlElement *, AstTimeFrame *, int * ); static AstRegion *TimeReader( AstXmlChan *, AstXmlElement *, AstTimeFrame *, double *, AstKeyMap **, int * ); static AstRegion *UnionReader( AstXmlChan *, AstXmlElement *, AstFrame *, int * ); static AstSystemType RedshiftSys( AstXmlChan *, AstXmlElement *, char **, int, int * ); static AstSystemType SpecSys( AstXmlChan *, AstXmlElement *, const char *, int, int * ); static AstXmlElement *FindAttribute( AstXmlChan *, const char *, int * ); static AstXmlElement *FindElement( AstXmlChan *, AstXmlElement *, const char *, int * ); static AstXmlElement *FindObject( AstXmlChan *, const char *, int * ); static AstXmlElement *MakePos2D( AstXmlChan *, AstXmlElement *, int * ); static AstXmlElement *ReadXmlText( AstXmlChan *, int * ); static AstXmlElement *Remove( AstXmlChan *, AstXmlElement *, int * ); static IVOAReader FindIVOAClass( AstXmlElement *, int *, int * ); static IVOAScan *FreeIVOAScan( IVOAScan *, int * ); static IVOAScan *ScanIVOAElement( AstXmlChan *, AstXmlElement *, int, const char *[], int[], int[], int * ); static char *ReadString( AstChannel *, const char *, const char *, int * ); static char *SourceWrap( const char *(*)( void ), int * ); static char GetNextChar( void *, int * ); static const char *FindNextIsA( AstXmlElement *, int, int * ); static const char *GetAttrib( AstObject *, const char *, int * ); static const char *GetTag( AstXmlObject *, int, int * ); static double AstronTimeReader( AstXmlChan *, AstXmlElement *, AstTimeFrame *, int * ); static double AttrValueD( AstXmlChan *, AstXmlElement *, const char *, double, int * ); static double ElemValueD( AstXmlChan *, AstXmlElement *, double, int * ); static double Error2PAReader( AstXmlChan *, AstXmlElement *, double *, int * ); static double MakeMJD( AstTimeFrame *, double, int * ); static double PosAngleReader( AstXmlChan *, AstXmlElement *, int * ); static double ReadDouble( AstChannel *, const char *, double, int * ); static int AstroCoordsReader( AstXmlChan *, AstXmlElement *, AstFrame *, AstRegion *[4], AstKeyMap **, int * ); static int AttrValueB( AstXmlChan *, AstXmlElement *, const char *, int, int * ); static int AttrValueI( AstXmlChan *, AstXmlElement *, const char *, int, int * ); static int ElemListD( AstXmlChan *, AstXmlElement *, int, double *, int * ); static int FindString( int, const char *[], const char *, const char *, const char *, const char *, int * ); static int GetComment( AstChannel *, int * ); static int GetFull( AstChannel *, int * ); static int GetIndent( AstChannel *, int * ); static int IsUsable( AstXmlElement *, int * ); static int ReadInt( AstChannel *, const char *, int, int * ); static int TestAttrib( AstObject *, const char *, int * ); static int Use( AstXmlChan *, int, int, int * ); static int Ustrcmp( const char *, const char *, int * ); static int Ustrncmp( const char *, const char *, size_t, int * ); static int VertexReader( AstXmlChan *, AstXmlElement *, double *, double *, int * ); static void ClearAttrib( AstObject *, const char *, int * ); static void Copy( const AstObject *, AstObject *, int * ); static void Delete( AstObject *, int * ); static void Dump( AstObject *, AstChannel *, int * ); static void FillAndLims( AstXmlChan *, AstXmlElement *, AstRegion *, int * ); static void OutputText( AstXmlChan *, const char *, int, int * ); static void ReCentreAnc( AstRegion *, int, AstKeyMap **, int * ); static void ReadClassData( AstChannel *, const char *, int * ); static void Report( AstXmlChan *, AstXmlElement *, int, const char *, int * ); static void SetAttrib( AstObject *, const char *, int * ); static void SinkWrap( void (*)( const char * ), const char *, int * ); static void WriteBegin( AstChannel *, const char *, const char *, int * ); static void WriteDouble( AstChannel *, const char *, int, int, double, const char *, int * ); static void WriteEnd( AstChannel *, const char *, int * ); static void WriteInt( AstChannel *, const char *, int, int, int, const char *, int * ); static void WriteIsA( AstChannel *, const char *, const char *, int * ); static void WriteObject( AstChannel *, const char *, int, int, AstObject *, const char *, int * ); static void WriteString( AstChannel *, const char *, int, int, const char *, const char *, int * ); static AstTimeScaleType TimeScaleReader( AstXmlChan *, AstXmlElement *, int * ); static int TestXmlLength( AstXmlChan *, int * ); static void ClearXmlLength( AstXmlChan *, int * ); static void SetXmlLength( AstXmlChan *, int, int * ); static int GetXmlLength( AstXmlChan *, int * ); static int TestXmlFormat( AstXmlChan *, int * ); static void ClearXmlFormat( AstXmlChan *, int * ); static void SetXmlFormat( AstXmlChan *, int, int * ); static int GetXmlFormat( AstXmlChan *, int * ); static int TestXmlPrefix( AstXmlChan *, int * ); static void ClearXmlPrefix( AstXmlChan *, int * ); static void SetXmlPrefix( AstXmlChan *, const char *, int * ); static const char * GetXmlPrefix( AstXmlChan *, int * ); /* Member functions. */ /* ================= */ static AstRegion *AllSkyReader( AstXmlChan *this, AstXmlElement *elem, AstFrame *frm, int *status ){ /* * Name: * AllSkyReader * Purpose: * Make an AST Region from an IVOA AllSky element. * Type: * Private function. * Synopsis: * #include "xmlchan.h" * AstRegion *AllSkyReader( AstXmlChan *this, AstXmlElement *elem, * AstFrame *frm, int *status ) * Class Membership: * XmlChan member function. * Description: * This function makes a new AST Region from the supplied IVOA * AllSky element. * Parameters: * this * Pointer to the XmlChan. * elem * Pointer to the IVOA AllSky element. * frm * Pointer to the 2D Frame in which the returned Region should be * defined. If the Unit attribute is not set, this function will * set it to the value supplied in "unit" before returning. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new Region. */ /* Local Variables: */ AstRegion *new; /* Pointer to returned Region */ /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* Create a negated NullRegion (this is a boundless Region which includes all points in the Frame). */ new = (AstRegion *) astNullRegion( frm, NULL, "negated=1", status ); /* Get any fill factor from the element and assign to the returned Region. */ FillAndLims( this, elem, new, status ); /* Annul any returned Frame if an error has occurred. */ if( !astOK ) new = astAnnul( new ); /* Return the pointer to the new Region. */ return new; } static AstRegion *AstroCoordAreaReader( AstXmlChan *this, AstXmlElement *elem, AstFrame *frm, AstRegion *uncs[4], int nanc, AstKeyMap **ancs, int *status ) { /* * Name: * AstroCoordAreaReader * Purpose: * Make an AST Region from an IVOA AstroCoordArea element. * Type: * Private function. * Synopsis: * #include "xmlchan.h" * AstRegion *AstroCoordAreaReader( AstXmlChan *this, AstXmlElement *elem, * AstFrame *frm, AstRegion *uncs[4], * int nanc, AstKeyMap **ancs, int *status ) * Class Membership: * XmlChan member function. * Description: * This function makes a new AST Region from the supplied IVOA * AstroCoordArea element. * Parameters: * this * Pointer to the XmlChan. * elem * Pointer to the IVOA AstroCoordArea element. May be NULL, in * which case a NullRegion is returned. * frm * The Frame in which the returned Region is to be defined. If * Units or reference values (Epoch, RestFreq, RefRA, etc) are not set * for any axes, then they will be set by this function if possible. * uncs * Array holding pointers to the uncertainty Regions to be associated * with each of the four STC domains (space, time, spectral, redshift). * NULL should be suppied in any element for which no uncertainty is * available. * nanc * Number of KeyMap pointers stored in "ancs" * ancs * Pointer to an array of "nanc" elements, each being a pointer to * a KeyMap. Each one describes the ancilary information in an * AstroCoords element associated with the AstroCoordsArea decribed * by "region". Each KeyMap has elements with keys AST__STCERROR, * AST__STCRES, AST__STCSIZE, AST__STCPIXSZ, AST__STCVALUE each of * which holds a pointer to a Region. * status * Pointer to the inherited status variable. * Returned Value: * A pointer to the new Region. */ /* Local Variables: */ AstRegion *r; AstFrame *cfrm; AstFrame *fr; AstFrame *pfrm; AstFrame *red_frame; AstFrame *space_frame; AstFrame *spec_frame; AstFrameSet *fs; AstMapping *map; AstObject *o; AstRegion **red_list; AstRegion **spec_list; AstRegion **space_list; AstRegion **time_list; AstRegion *new; AstRegion *reg; AstRegion *rred; AstRegion *rspec; AstRegion *rspace; AstRegion *rtime; AstRegion *sum; AstRegion *tmp; AstTimeFrame *time_frame; IVOAScan *scan; char *decset; char *raset; char buff[ AST__DBL_WIDTH + 30 ]; char setting[ 100 ]; const char *dom; const char *id; const char *names[4]; const char *name; const char *old_units; const char *text; double decref; double lbnd[2]; double raref; double space_val[2]; double spec_val; double time_val; double ubnd[2]; int i; int ianc; int ired; int ispace; int ispec; int itime; int k; int l; int max[4]; int min[4]; int nax; int nred; int nspace; int nspec; int ntime; int paxis; static const char *key[ 5 ] = { AST__STCERROR, AST__STCRES, AST__STCSIZE, AST__STCPIXSZ, AST__STCVALUE }; /* Initialise. */ new = NULL; /* Check the global error status. */ if ( !astOK ) return new; /* If null AstroCoordArea element has been supplied, return a NullRegion. */ if( !elem ) { new = (AstRegion *) astNullRegion( frm, NULL, "", status ); /* Otherwise, create a Region of suitable class. */ } else { /* First identify the individual Frames within the supplied Frame. Current implementation for spatial axes is limited to celestial longitude and latitude. */ space_frame = NULL; spec_frame = NULL; red_frame = NULL; time_frame = NULL; nax = astGetNaxes( frm ); for( i = 0; i < nax; i++ ) { astPrimaryFrame( frm, i, &pfrm, &paxis ); dom = astGetDomain( pfrm ); if( !strcmp( dom, "SKY" ) ) { if( !space_frame ) { space_frame = astClone( pfrm ); } else if( pfrm != space_frame) { Report( this, elem, FAILURE, "contains more than 2 spatial axes", status ); } } else if( !strcmp( dom, "TIME" ) ) { if( !time_frame ) { if( astIsATimeFrame( pfrm ) ) { time_frame = (AstTimeFrame *) astClone( pfrm ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan): %s " "supplied where TimeFrame expected (internal " "AST programming error).", status, astGetClass( pfrm ) ); } } else { Report( this, elem, FAILURE, "contains more than 1 time axis", status ); } } else if( !strcmp( dom, "SPECTRUM" ) ) { if( !spec_frame ) { spec_frame = astClone( pfrm ); } else { Report( this, elem, FAILURE, "contains more than 1 spectral axis", status ); } } else if( !strcmp( dom, "REDSHIFT" ) ) { if( !red_frame ) { red_frame = astClone( pfrm ); } else { Report( this, elem, FAILURE, "contains more than 1 redshift axis", status ); } } else { Report( this, elem, FAILURE, "contains axes for an unsupported domain", status ); } pfrm = astAnnul( pfrm ); } /* Search the supplied element for the required sub-elements. */ names[ 0 ] = "Sphere|PositionInterval|Region"; names[ 1 ] = "TimeInterval"; names[ 2 ] = "SpectralInterval"; names[ 3 ] = "RedshiftInterval"; min[ 0 ] = 0; min[ 1 ] = 0; min[ 2 ] = 0; min[ 3 ] = 0; max[ 0 ] = INT_MAX; max[ 1 ] = INT_MAX; max[ 2 ] = INT_MAX; max[ 3 ] = INT_MAX; scan = ScanIVOAElement( this, elem, 4, names, min, max, status ); /* If succesfull.. */ if( scan ) { /* Create Regions for all the SpatialIntervals found in the supplied element. */ space_val[ 0 ] = AST__BAD; space_val[ 1 ] = AST__BAD; nspace = scan->count[ 0 ]; space_list = astMalloc( sizeof(AstRegion *)*(size_t)nspace ); if( space_list ) { for( ispace = 0; ispace < nspace; ispace++ ) { name = astXmlGetName( scan->el[ 0 ][ ispace ] ); if( !strcmp( name, "Sphere" ) ) { space_list[ ispace ] = SphereReader( this, scan->el[ 0 ][ ispace ], space_frame, status ); } else if( !strcmp( name, "PositionInterval" ) ) { space_list[ ispace ] = PositionIntervalReader( this, scan->el[ 0 ][ ispace ], space_frame, status ); } else if( !strcmp( name, "Region" ) ) { space_list[ ispace ] = StcRegionReader( this, scan->el[ 0 ][ ispace ], space_frame, status ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan): " "SpatialInterval type %s not yet supported " "(AST internal programming error).", status, name ); break; } /* Store any uncertainty region.*/ if( uncs[ 0 ] ) astSetUnc( space_list[ ispace ], uncs[ 0 ] ); } /* If the spatial region is a single point we will use the point as the reference position for any SpecFrames which are created. If there is just one spatial interval, and if it is bounded. and if the bounds are equal on both axes, note the mean position. */ if( nspace == 1 ){ if( astGetBounded( space_list[ 0 ] ) ) { astGetRegionBounds( space_list[ 0 ], lbnd, ubnd ); if( astEQUAL( lbnd[ 0 ], ubnd[ 0 ] ) && astEQUAL( lbnd[ 1 ], ubnd[ 1 ] ) ) { space_val[ 0 ] = 0.5*( lbnd[ 0 ] + ubnd[ 0 ] ); space_val[ 1 ] = 0.5*( lbnd[ 1 ] + ubnd[ 1 ] ); } } } } /* Create Regions for all the TimeIntervals found in the supplied element. */ time_val = AST__BAD; ntime = scan->count[ 1 ]; time_list = astMalloc( sizeof(AstRegion *)*(size_t)ntime ); if( time_list ) { for( itime = 0; itime < ntime; itime++ ) { time_list[ itime ] = TimeIntervalReader( this, scan->el[ 1 ][ itime ], time_frame, status ); /* Store any uncertainty region. Transfer the System and TimeOrigin values from the time region to the time uncertainty, if set. */ if( uncs[ 1 ] ) { if( astTestSystem( time_frame ) && astTestTimeOrigin( time_frame ) ) { sprintf( setting, "System=%s", astGetC( time_frame, "System" ) ); astRegSetAttrib( uncs[ 1 ], setting, NULL ); if( astTestUnit( time_frame, 0 ) ) { old_units = astGetUnit( time_frame, 0 ); old_units = astStore( NULL, old_units, strlen( old_units ) + 1 ); } else { old_units = NULL; } astSetUnit( time_frame, 0, astGetUnit( uncs[ 1 ], 0 ) ); sprintf( setting, "TimeOrigin=%s", astGetC( time_frame, "TimeOrigin" ) ); astRegSetAttrib( uncs[ 1 ], setting, NULL ); if( old_units ) { astSetUnit( time_frame, 0, old_units ); old_units = astFree( (void *) old_units ); } else { astClearUnit( time_frame, 0 ); } } astSetUnc( time_list[ itime ], uncs[ 1 ] ); } } /* Use the mid point as the Epoch for all Frames which are created. If either limit is not specified, use the specified limit. */ if( ntime > 0 ){ astGetRegionBounds( time_list[ 0 ], lbnd, ubnd ); if( fabs( lbnd[ 0 ] ) != DBL_MAX && lbnd[ 0 ] != AST__BAD ){ if( fabs( ubnd[ 0 ] ) != DBL_MAX && ubnd[ 0 ] != AST__BAD ){ time_val = 0.5*( lbnd[ 0 ] + ubnd[ 0 ] ); } else { time_val = lbnd[ 0 ]; } } else if( fabs( ubnd[ 0 ] ) != DBL_MAX && ubnd[ 0 ] != AST__BAD ){ time_val = ubnd[ 0 ]; } } } /* Create Regions for all the SpectralIntervals found in the supplied element. */ spec_val = AST__BAD; nspec = scan->count[ 2 ]; spec_list = astMalloc( sizeof(AstRegion *)*(size_t)nspec ); if( spec_list ) { for( ispec = 0; ispec < nspec; ispec++ ) { spec_list[ ispec ] = SpectralIntervalReader( this, scan->el[ 2 ][ ispec ], spec_frame, status ); /* Store any uncertainty region.*/ if( uncs[ 2 ] ) astSetUnc( spec_list[ ispec ], uncs[ 2 ] ); } /* If the spectral region is a single point we will use the point as the rest frequency for all RedShift Frames which are created. If there is just one spectral interval, and if it is bounded. and if the bounds are equal, note the mean spectral value. */ if( nspec == 1 ){ if( astGetBounded( spec_list[ 0 ] ) ) { astGetRegionBounds( spec_list[ 0 ], lbnd, ubnd ); if( astEQUAL( lbnd[ 0 ], ubnd[ 0 ] ) ) { spec_val = 0.5*( lbnd[ 0 ] + ubnd[ 0 ] ); } } } } /* Create Regions for all the RedshiftIntervals found in the supplied element. */ nred = scan->count[ 3 ]; red_list = astMalloc( sizeof(AstRegion *)*(size_t)nred ); if( red_list ) { for( ired = 0; ired < nred; ired++ ) { red_list[ ired ] = RedshiftIntervalReader( this, scan->el[ 3 ][ ired ], red_frame, status ); /* Store any uncertainty region.*/ if( uncs[ 3 ] ) astSetUnc( red_list[ ired ], uncs[ 3 ] ); } } /* Free the can result structure.*/ scan = FreeIVOAScan( scan, status ); /* If the spatial regions cover only a single point, convert it to FK5 J2000 and use it as the reference position for any SpecFrames (spectral or redshift) unless values were inherited from the supplied Frame. If the supplied Frame did not contain set values for these attributes, set them now. Use astRegSetAttrib which applies the attribute setting to both base and current Frame of the Region's FrameSet, and avoids re-mapping the current Frame. */ if( astOK ) { if( space_val[ 0 ] != AST__BAD && space_val[ 1 ] != AST__BAD ) { /* First need to convert to FK5 J2000 and format into a string for use with astRegSetAttrib. Need to ensure that the Format and Digits attributes are set to values which will result in no loss of precision in the formatting and unformatting steps. */ fr = astCopy( space_frame ); astClear( fr, "Format(1),Format(2),Digits(1),Digits(2)" ); astSet( fr, "digits=%d,system=FK5,equinox=J2000", status, AST__DBL_DIG); fs = astConvert( space_frame, fr, "" ); fr = astAnnul( fr ); if( fs ) { astTran2( fs, 1, space_val, space_val + 1, 1, &raref, &decref ); text = astFormat( fs, raref, 0 ); l = text ? strlen( text ) : 0; raset = astMalloc( l + 10 ); if( raset ) sprintf( raset, "refra=%s", text ); text = astFormat( fs, decref, 1 ); l = text ? strlen( text ) : 0; decset = astMalloc( l + 10 ); if( decset ) sprintf( decset, "refdec=%s", text ); fs = astAnnul( fs ); /* Now set the FK5 J2000 values in the required Frames and Regions. */ if( !spec_frame || !astTestRefRA( spec_frame ) || !astTestRefDec( spec_frame ) ) { for( ispec = 0; ispec < nspec; ispec++ ) { astRegSetAttrib( spec_list[ ispec ], raset, NULL ); astRegSetAttrib( spec_list[ ispec ], decset, NULL ); } if( spec_frame ) { astSetRefRA( (AstSpecFrame *) spec_frame, raref ); astSetRefDec( (AstSpecFrame *) spec_frame, decref ); } } if( !red_frame || !astTestRefRA( red_frame ) || !astTestRefDec( red_frame ) ) { for( ired = 0; ired < nred; ired++ ) { astRegSetAttrib( red_list[ ired ], raset, NULL ); astRegSetAttrib( red_list[ ired ], decset, NULL ); } if( red_frame ) { astSetRefRA( (AstSpecFrame *) red_frame, raref ); astSetRefDec( (AstSpecFrame *) red_frame, decref ); } } for( ianc = 0; ianc < nanc; ianc++ ) { for( k = 0; k < 5; k++ ) { if( astMapGet0A( ancs[ ianc ], key[ k ], &o ) ) { r = (AstRegion *) o; astRegSetAttrib( r, raset, NULL ); astRegSetAttrib( r, decset, NULL ); r = astAnnul( r ); } } } /* Free resources. */ if( raset ) raset = astFree( raset ); if( decset ) decset = astFree( decset ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan):" " Cannot convert spatial position to FK5 J2000" , status); } } /* If a time region was specified, use a typical value as the epoch for all Frames. Call MakeMJD to convert "time_val" from the system of the TimeFrame to an MJD (as required by the Frame Epoch attribute). Set the value in both the returned Region and the supplied Frame. */ if( time_val != AST__BAD ) { fr = astRegFrame( time_list[ 0 ] ); if( astIsATimeFrame( fr ) ) { time_val = MakeMJD( (AstTimeFrame *) fr, time_val, status ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan): %s " "supplied where TimeFrame expected (internal " "AST programming error).", status, astGetClass( fr ) ); } fr = astAnnul( fr ); sprintf( buff, "epoch= MJD %.*g", AST__DBL_DIG, time_val ); if( !space_frame || !astTestEpoch( space_frame ) ) { for( ispace = 0; ispace < nspace; ispace++ ) { astRegSetAttrib( space_list[ ispace ], buff, NULL ); } if( space_frame ) astSetEpoch( space_frame, time_val ); } if( !spec_frame || !astTestEpoch( spec_frame ) ) { for( ispec = 0; ispec < nspec; ispec++ ) { astRegSetAttrib( spec_list[ ispec ], buff, NULL ); } if( spec_frame ) astSetEpoch( spec_frame, time_val ); } if( !red_frame || !astTestEpoch( red_frame ) ) { for( ired = 0; ired < nred; ired++ ) { astRegSetAttrib( red_list[ ired ], buff, NULL ); } if( red_frame ) astSetEpoch( red_frame, time_val ); } for( ianc = 0; ianc < nanc; ianc++ ) { for( k = 0; k < 5; k++ ) { if( astMapGet0A( ancs[ ianc ], key[ k ], &o ) ) { r = (AstRegion *) o; astRegSetAttrib( r, buff, NULL ); r = astAnnul( r ); } } } } /* If the spectral regions cover only a single point, format it with its units so that the astSetAttrib function can convert it to Hz and use it as the rest frequency for any redshift Frames. */ if( spec_val != AST__BAD && nred > 0 ) { text = astGetUnit( spec_frame, 0 ); if( text ) sprintf( buff, "restfreq= %.*g %s", AST__DBL_DIG, spec_val, text ); if( !red_frame || !astTestRestFreq( red_frame ) ) { for( ired = 0; ired < nred; ired++ ) { astRegSetAttrib( red_list[ ired ], buff, NULL ); } if( red_frame ) astSetAttrib( red_frame, buff ); } for( ianc = 0; ianc < nanc; ianc++ ) { for( k = 0; k < 5; k++ ) { if( astMapGet0A( ancs[ ianc ], key[ k ], &o ) ) { r = (AstRegion *) o; astRegSetAttrib( r, buff, NULL ); r = astAnnul( r ); } } } } /* Create Regions corresponding to every possible combination of interval on each axis type, and assemble the union of these into a CmpRegion (if there is more than one). */ sum = NULL; /* Initialise indices of the sub-Frame intervals to use. */ ispace = 0; itime = 0; ispec = 0; ired = 0; /* Loop over all possible combinations of time+space+spec+red intervals. */ while( 1 ) { rspace = ( ispace < nspace ) ? space_list[ ispace ] : NULL; rtime = ( itime < ntime ) ? time_list[ itime ] : NULL; rspec = ( ispec < nspec ) ? spec_list[ ispec ] : NULL; rred = ( ired < nred ) ? red_list[ ired ] : NULL; /* Prism Regions extrude a Region into higher dimensions, and the extrusion is defined by an Interval. Spatial Regions are not restricted to Intervals and so any spatial Region must be the first Region to be included in the Prism (all the other axis types *are* restricted to Intervals and so can be used to extrude the spatial region). */ reg = rspace ? astClone( rspace ) : NULL; /* Now extrude this region (if any) into the time axis. */ if( rtime ) { if( reg ) { tmp = (AstRegion *) astPrism( reg, rtime, "", status ); (void) astAnnul( reg ); reg = tmp; } else { reg = astClone( rtime ); } } /* Now extrude this region (if any) into the spectral axis. */ if( rspec ) { if( reg ) { tmp = (AstRegion *) astPrism( reg, rspec, "", status ); (void) astAnnul( reg ); reg = tmp; } else { reg = astClone( rspec ); } } /* Now extrude this region (if any) into the redshift axis. */ if( rred ) { if( reg ) { tmp = (AstRegion *) astPrism( reg, rred, "", status ); (void) astAnnul( reg ); reg = tmp; } else { reg = astClone( rred ); } } /* If a Prism was created, add it into the CmpRegion which holds the running sum of the union of all Prisms created so far. */ if( reg ) { if( !sum ) { sum = astClone( reg ); } else { tmp = (AstRegion *) astCmpRegion( sum, reg, AST__OR, "", status ); (void) astAnnul( sum ); sum = tmp; } reg = astAnnul( reg ); } /* Increment the indices of the next set of sub-Frame Intervals to use. Leave the while loop when all combinations have been done. */ if( ++ired >= nred ) { ired = 0; if( ++ispec >= nspec ) { ispec = 0; if( ++itime >= ntime ) { itime = 0; if( ++ispace >= nspace ) break; } } } } /* Simplify the total sum Region. */ tmp = astSimplify( sum ); (void) astAnnul( sum ); sum = tmp; /* The axes in this sum Region may not be in the correct order or units (i.e in the order and units specified in the supplied Frame). So use astConvert to get a Mapping from the Frame represented by the sum Region to the supplied Frame. */ fs = astConvert( sum, frm, "" ); if( fs ) { /* Unless the Mapping is a UnitMap, remap the sum Region into the supplied Frame using this Mapping. */ map = astGetMapping( fs, AST__BASE, AST__CURRENT ); if( !astIsAUnitMap( map ) ) { new = astMapRegion( sum, map, frm ); } else { new = astClone( sum ); } map = astAnnul( map ); fs = astAnnul( fs ); } else if( astOK ) { astError( AST__INTER, "AstroCoordAreaReader(%s): Cannot " "convert from supplied Frame to internal Frame (AST " "internal programming error).", status, astGetClass( this ) ); } /* Transfer selected properties from the supplied Frame to the current Frame of the returned Region. */ cfrm = astRegFrame( new ); if( astTestIdent( frm ) ) astSetIdent( cfrm, astGetIdent( frm ) ); if( astTestTitle( frm ) ) astSetTitle( cfrm, astGetTitle( frm ) ); /* Ensure the Epoch is set correctly in the Region */ if( time_val != AST__BAD ) { sprintf( buff, "epoch= MJD %.*g", AST__DBL_DIG, time_val ); astRegSetAttrib( new, buff, NULL ); } /* Free resources. */ cfrm = astAnnul( cfrm ); sum = astAnnul( sum ); } if( space_list ) { for( i = 0; i < nspace; i++ ) space_list[ i ] = astAnnul( space_list[ i ] ); space_list = astFree( space_list ); } if( time_list ) { for( i = 0; i < ntime; i++ ) time_list[ i ] = astAnnul( time_list[ i ] ); time_list = astFree( time_list ); } if( spec_list ) { for( i = 0; i < nspec; i++ ) spec_list[ i ] = astAnnul( spec_list[ i ] ); spec_list = astFree( spec_list ); } if( red_list ) { for( i = 0; i < nred; i++ ) red_list[ i ] = astAnnul( red_list[ i ] ); red_list = astFree( red_list ); } } if( space_frame ) space_frame = astAnnul( space_frame ); if( time_frame ) time_frame = astAnnul( time_frame ); if( spec_frame ) spec_frame = astAnnul( spec_frame ); if( red_frame ) red_frame = astAnnul( red_frame ); /* Get the ID attribute from the AstroCoordArea element and store in the returned Region. */ id = astXmlGetAttributeValue( elem, "ID" ); if( id ) astSetIdent( new, id ); } /* If an error has occurred,annul the returned pointer. */ if( !astOK ) new = astAnnul( new ); /* Return the pointer to the new Region. */ return new; } static int AstroCoordsReader( AstXmlChan *this, AstXmlElement *elem, AstFrame *frm, AstRegion *uncs[4], AstKeyMap **anc, int *status ) { /* * Name: * AstroCoordsReader * Purpose: * Modify a Frame to take account of an IVOA AstroCoords element, and * return an coordinate uncertainties. * Type: * Private function. * Synopsis: * #include "xmlchan.h" * int AstroCoordsReader( AstXmlChan *this, AstXmlElement *elem, * AstFrame *frm, AstRegion *uncs[4], * AstKeyMap **anc, int *status ) * Class Membership: * XmlChan member function. * Description: * This function modifies the supplied Frame object to incorporate the * effects of the supplied AstroCoords element. It may also return * Regions representing the bounds of the uncertainties in the four * component coordinate Frames, depending on the contents of the * AstroCoords element. * Parameters: * this * Pointer to the XmlChan. * elem * Pointer to the IVOA AstroCoords element. * frm * The Frame object to modify. * uncs * Array in which to return pointers to the uncertainty Regions to * be associated with each of the four STC domains (space, time, * spectral, redshift). NULL is returned in any element for which * no uncertainty is specified within the supplied AstroCoords element. * anc * Address of a location at which to store the pointer to a newly * created KeyMap holding ancillary information describing the * AstroCoords element in the form required by constructors of AST * Stc objects. A NULL pointer is returned if no usable ancillary * information is found in the AstroCoords. * status * Pointer to the inherited status variable. * Returned Value: * Non-zero if any non-NULL values have been returned in the "uncs" * array. Zero otherwise. */ /* Local Variables: */ AstFrame *afrm; /* Pointer to axis Frame */ AstFrame *gfrm; /* Pointer to generic Frame */ AstFrame *pfrm; /* Pointer to position Frame */ AstFrame *rfrm; /* Pointer to redshift Frame */ AstFrame *sfrm; /* Pointer to spectral Frame */ AstTimeFrame *tfrm; /* Pointer to time Frame */ AstKeyMap *panc; /* KeyMap holding spatial ancillary data */ AstKeyMap *ranc; /* KeyMap holding redshift ancillary data */ AstKeyMap *sanc; /* KeyMap holding spectral ancillary data */ AstKeyMap *tanc; /* KeyMap holding temporal ancillary data */ AstObject *o; /* Pointer to object retrieved from KeyMap */ AstRegion *r; /* Individual ancillary Region */ AstRegion *t; /* Total extruded ancillary Region */ AstRegion *tt; /* Temporary Region pointer */ AstXmlElement *el; /* Pointer to Position2D element */ IVOAScan *scan; /* Structure holding scan results */ char **anames; /* Pointer to list of ancillary name pointers */ const char *dom; /* Pointer to Domain attribute value */ const char *nam; /* Pointer to ancillary Name string */ const char *names[4]; /* Names of the subelements to be searched for */ char buff[100]; /* Message buffer */ double epoch; /* Epoch */ double hi; /* High limit for zero-width interval */ double lo; /* Low limit for zero-width interval */ double pos[2]; /* Reference spatial position */ double rf; /* Rest frequency */ int axes[2]; /* Indices of position axes */ int axis; /* Index of next axis to use */ int empty; /* Is returned KeyMap empty? */ int i; /* Loop count */ int isearth; /* Does the SkyFrame represent terrestrial lon/lat? */ int junk; /* Unused integer value */ int max[4]; /* Max allowed occurrences of each name */ int min[4]; /* Min allowed occurrences of each name */ int nax; /* Number of axes in supplied Frame */ int unc; /* Any uncertainty Regions found? */ int use; /* Use ancillary information? */ static const char *key[ 5 ] = { AST__STCERROR, AST__STCRES, AST__STCSIZE, AST__STCPIXSZ, AST__STCVALUE }; /* Initialise */ unc = 0; uncs[ 0 ] = NULL; uncs[ 1 ] = NULL; uncs[ 2 ] = NULL; uncs[ 3 ] = NULL; *anc = NULL; /* Check the global error status. */ if ( !astOK ) return unc; /* Search the supplied element for the required sub-elements. */ names[ 0 ] = "Position2D|Position3D"; names[ 1 ] = "Time"; names[ 2 ] = "Spectral"; names[ 3 ] = "Redshift"; min[ 0 ] = 0; min[ 1 ] = 0; min[ 2 ] = 0; min[ 3 ] = 0; max[ 0 ] = 1; max[ 1 ] = 1; max[ 2 ] = 1; max[ 3 ] = 1; scan = ScanIVOAElement( this, elem, 4, names, min, max, status ); /* If succesfull.. */ if( scan ) { /* Initialise pointers to component Frames */ pfrm = NULL; tfrm = NULL; sfrm = NULL; rfrm = NULL; /* Initialise pointers to KeyMaps holding ancillary data. */ panc = NULL; tanc = NULL; sanc = NULL; ranc = NULL; /* Allocate storage for an array of pointers to strings holding the Name value for each axis. Initialise them to a null string. */ nax = astGetNaxes( frm ); anames = astMalloc( sizeof( char * )*(size_t)nax ); for( i = 0; i < nax; i++ ) anames[ i ] = NULL; /* Initialise the index of the next Frame axis to use. */ axis = 0; /* Check to see if the next 2 axes describe positions on the sky or earth (see SpaceFrameReader). */ axes[ 0 ] = 0; axes[ 1 ] = 1; afrm = astPickAxes( frm, 2, axes, NULL ); dom = astGetDomain( afrm ); isearth = dom && ( !strcmp( dom, "GEO_D" ) || !strcmp( dom, "GEO_C" ) ); if( isearth || ( dom && !strcmp( dom, "SKY" ) ) ){ astPrimaryFrame( frm, axis, &pfrm, &junk ); if( scan->count[ 0 ] ) { /* We currently also use SkyFrames to represent geographical long/lat used to describe observatory positions. These may have 3D positions, in which case we convert the 3D position to a 2D position by ignoring the 3rd axis value (height). See SpaceFrameReader. */ el = MakePos2D( this, scan->el[ 0 ][ 0 ], status ); /* Use the Position2D to create a Region describing the uncertainty in the space axes of the Frame. Also create a KeyMap holding Regions describing any ancillary information stored in the Position2D. */ uncs[ 0 ] = Position2DReader( this, el, pfrm, pos, &panc, status ); if( uncs[ 0 ] ) unc = 1; el = astXmlDelete( el ); /* If ancillary information was returned, extract the Name element, and store it twice (once for each axis) in the "names" array. */ if( panc && astMapGet0C( panc, AST__STCNAME, &nam ) ) { anames[ axis ] = astStore( NULL, nam, strlen( nam ) + 1 ); anames[ axis + 1 ] = astStore( NULL, nam, strlen( nam ) + 1 ); } } /* Increment the axis index. */ axis += 2; /* If the supplied Frame has no sky frame, but we found a Position2D, then report a warning and ignore the Position2D. */ } else if( scan->count[ 0 ] ) { sprintf( buff, "contains a <%s> which is not being used.", astXmlGetName( scan->el[ 0 ][ 0 ] ) ); Report( this, elem, WARNING, buff, status ); } afrm = astAnnul( afrm ); /* Indicate we do not yet have an epoch to use. */ epoch = AST__BAD; /* Check to see if the Frame contains a time frame. It will be the next axis if it does. */ afrm = astPickAxes( frm, 1, &axis, NULL ); dom = astGetDomain( afrm ); if( dom && !strcmp( dom, "TIME" ) ){ astPrimaryFrame( frm, axis, &gfrm, &junk ); /* Report an error if it is not an AST TimeFrame. */ if( !astIsATimeFrame( gfrm ) && astOK ) { astError( AST__INTER, "AstroCoordAreaReader(XmlChan): %s " "supplied where TimeFrame expected (internal " "AST programming error).", status, astGetClass( pfrm ) ); } else { tfrm = (AstTimeFrame *) gfrm; } /* Use any Time element to create a Region describing the uncertainty in the time axis of the Frame. Also create a KeyMap holding Regions describing any ancillary information stored in the Time element. */ if( scan->count[ 1 ] ) { uncs[ 1 ] = TimeReader( this, scan->el[ 1 ][ 0 ], tfrm, &epoch, &tanc, status ); if( uncs[ 1 ] ) unc = 1; /* If ancillary information was returned, extract the Name element, and store it in the "names" array. */ if( tanc && astMapGet0C( tanc, AST__STCNAME, &nam ) ) { anames[ axis ] = astStore( NULL, nam, strlen( nam ) + 1 ); } } /* Increment the index of the next axis to use. */ axis++; /* If the supplied Frame has no time frame, but we found a Time element, then report a warning and ignore the Time element. */ } else if( scan->count[ 1 ] ) { Report( this, elem, WARNING, "contains a