summaryrefslogtreecommitdiffstats
path: root/ast/fitschan.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-11-02 19:11:06 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-11-02 19:11:06 (GMT)
commit33c55bd916dff8c4932b01c7db58f0103ac31c31 (patch)
treea4cdca3287dd2df5247ce8079c424ffa438b4c2e /ast/fitschan.c
parent4121637f3d41d6dc23e6543a445b5a3aed9e6ddc (diff)
downloadblt-33c55bd916dff8c4932b01c7db58f0103ac31c31.zip
blt-33c55bd916dff8c4932b01c7db58f0103ac31c31.tar.gz
blt-33c55bd916dff8c4932b01c7db58f0103ac31c31.tar.bz2
update ast
Diffstat (limited to 'ast/fitschan.c')
-rw-r--r--ast/fitschan.c42623
1 files changed, 0 insertions, 42623 deletions
diff --git a/ast/fitschan.c b/ast/fitschan.c
deleted file mode 100644
index 3e85444..0000000
--- a/ast/fitschan.c
+++ /dev/null
@@ -1,42623 +0,0 @@
-/*
-*class++
-* Name:
-* FitsChan
-
-* Purpose:
-* I/O Channel using FITS header cards to represent Objects.
-
-* Constructor Function:
-c astFitsChan
-f AST_FITSCHAN
-
-* Description:
-* A FitsChan is a specialised form of Channel which supports I/O
-* operations involving the use of FITS (Flexible Image Transport
-* System) header cards. Writing an Object to a FitsChan (using
-c astWrite) will, if the Object is suitable, generate a
-f AST_WRITE) will, if the Object is suitable, generate a
-* description of that Object composed of FITS header cards, and
-* reading from a FitsChan will create a new Object from its FITS
-* header card description.
-*
-* While a FitsChan is active, it represents a buffer which may
-* contain zero or more 80-character "header cards" conforming to
-* FITS conventions. Any sequence of FITS-conforming header cards
-* may be stored, apart from the "END" card whose existence is
-* merely implied. The cards may be accessed in any order by using
-* the FitsChan's integer Card attribute, which identifies a "current"
-* card, to which subsequent operations apply. Searches
-c based on keyword may be performed (using astFindFits), new
-c cards may be inserted (astPutFits, astPutCards, astSetFits<X>) and
-c existing ones may be deleted (astDelFits), extracted (astGetFits<X>),
-c or changed (astSetFits<X>).
-f based on keyword may be performed (using AST_FINDFITS), new
-f cards may be inserted (AST_PUTFITS, AST_PUTCARDS, AST_SETFITS<X>) and
-f existing ones may be deleted (AST_DELFITS), extracted
-f (AST_GETFITS<X>) or changed (AST_SETFITS<X>).
-*
-* When you create a FitsChan, you have the option of specifying
-* "source" and "sink" functions which connect it to external data
-* stores by reading and writing FITS header cards. If you provide
-* a source function, it is used to fill the FitsChan with header cards
-* when it is accessed for the first time. If you do not provide a
-* source function, the FitsChan remains empty until you explicitly enter
-c data into it (e.g. using astPutFits, astPutCards, astWrite
-f data into it (e.g. using AST_PUTFITS, AST_PUTCARDS, AST_WRITE
-* or by using the SourceFile attribute to specifying a text file from
-* which headers should be read). When the FitsChan is deleted, any
-* remaining header cards in the FitsChan can be saved in either of
-* two ways: 1) by specifying a value for the SinkFile attribute (the
-* name of a text file to which header cards should be written), or 2)
-* by providing a sink function (used to to deliver header cards to an
-* external data store). If you do not provide a sink function or a
-* value for SinkFile, any header cards remaining when the FitsChan
-* is deleted will be lost, so you should arrange to extract them
-* first if necessary
-c (e.g. using astFindFits or astRead).
-f (e.g. using AST_FINDFITS or AST_READ).
-*
-* Coordinate system information may be described using FITS header
-* cards using several different conventions, termed
-* "encodings". When an AST Object is written to (or read from) a
-* FitsChan, the value of the FitsChan's Encoding attribute
-* determines how the Object is converted to (or from) a
-* description involving FITS header cards. In general, different
-* encodings will result in different sets of header cards to
-* describe the same Object. Examples of encodings include the DSS
-* encoding (based on conventions used by the STScI Digitised Sky
-* Survey data), the FITS-WCS encoding (based on a proposed FITS
-* standard) and the NATIVE encoding (a near loss-less way of
-* storing AST Objects in FITS headers).
-*
-* The available encodings differ in the range of Objects they can
-* represent, in the number of Object descriptions that can coexist
-* in the same FitsChan, and in their accessibility to other
-* (external) astronomy applications (see the Encoding attribute
-* for details). Encodings are not necessarily mutually exclusive
-* and it may sometimes be possible to describe the same Object in
-* several ways within a particular set of FITS header cards by
-* using several different encodings.
-*
-c The detailed behaviour of astRead and astWrite, when used with
-f The detailed behaviour of AST_READ and AST_WRITE, when used with
-* a FitsChan, depends on the encoding in use. In general, however,
-c all successful use of astRead is destructive, so that FITS header cards
-f all successful use of AST_READ is destructive, so that FITS header cards
-* are consumed in the process of reading an Object, and are
-* removed from the FitsChan (this deletion can be prevented for
-* specific cards by calling the
-c astRetainFits function).
-f AST_RETAINFITS routine).
-* An unsuccessful call of
-c astRead
-f AST_READ
-* (for instance, caused by the FitsChan not containing the necessary
-* FITS headers cards needed to create an Object) results in the
-* contents of the FitsChan being left unchanged.
-*
-* If the encoding in use allows only a single Object description
-* to be stored in a FitsChan (e.g. the DSS, FITS-WCS and FITS-IRAF
-c encodings), then write operations using astWrite will
-f encodings), then write operations using AST_WRITE will
-* over-write any existing Object description using that
-* encoding. Otherwise (e.g. the NATIVE encoding), multiple Object
-* descriptions are written sequentially and may later be read
-* back in the same sequence.
-
-* Inheritance:
-* The FitsChan class inherits from the Channel class.
-
-* Attributes:
-* In addition to those attributes common to all Channels, every
-
-* FitsChan also has the following attributes:
-*
-* - AllWarnings: A list of the available conditions
-* - Card: Index of current FITS card in a FitsChan
-* - CardComm: The comment of the current FITS card in a FitsChan
-* - CardName: The keyword name of the current FITS card in a FitsChan
-* - CardType: The data type of the current FITS card in a FitsChan
-* - CarLin: Ignore spherical rotations on CAR projections?
-* - CDMatrix: Use a CD matrix instead of a PC matrix?
-* - Clean: Remove cards used whilst reading even if an error occurs?
-* - DefB1950: Use FK4 B1950 as default equatorial coordinates?
-* - Encoding: System for encoding Objects as FITS headers
-* - FitsAxisOrder: Sets the order of WCS axes within new FITS-WCS headers
-* - FitsDigits: Digits of precision for floating-point FITS values
-* - Iwc: Add a Frame describing Intermediate World Coords?
-* - Ncard: Number of FITS header cards in a FitsChan
-* - Nkey: Number of unique keywords in a FitsChan
-* - TabOK: Should the FITS "-TAB" algorithm be recognised?
-* - PolyTan: Use PVi_m keywords to define distorted TAN projection?
-* - Warnings: Produces warnings about selected conditions
-
-* Functions:
-c In addition to those functions applicable to all Channels, the
-c following functions may also be applied to all FitsChans:
-f In addition to those routines applicable to all Channels, the
-f following routines may also be applied to all FitsChans:
-*
-c - astDelFits: Delete the current FITS card in a FitsChan
-c - astEmptyFits: Delete all cards in a FitsChan
-c - astFindFits: Find a FITS card in a FitsChan by keyword
-c - astGetFits<X>: Get a keyword value from a FitsChan
-c - astGetTables: Retrieve any FitsTables from a FitsChan
-c - astPurgeWCS: Delete all WCS-related cards in a FitsChan
-c - astPutCards: Stores a set of FITS header card in a FitsChan
-c - astPutFits: Store a FITS header card in a FitsChan
-c - astPutTable: Store a single FitsTable in a FitsChan
-c - astPutTables: Store multiple FitsTables in a FitsChan
-c - astReadFits: Read cards in through the source function
-c - astRemoveTables: Remove one or more FitsTables from a FitsChan
-c - astRetainFits: Ensure current card is retained in a FitsChan
-c - astSetFits<X>: Store a new keyword value in a FitsChan
-c - astShowFits: Display the contents of a FitsChan on standard output
-c - astTableSource: Register a source function for FITS table access
-c - astTestFits: Test if a keyword has a defined value in a FitsChan
-c - astWriteFits: Write all cards out to the sink function
-f - AST_DELFITS: Delete the current FITS card in a FitsChan
-f - AST_EMPTYFITS: Delete all cards in a FitsChan
-f - AST_FINDFITS: Find a FITS card in a FitsChan by keyword
-f - AST_GETFITS<X>: Get a keyword value from a FitsChan
-f - AST_GETTABLES: Retrieve any FitsTables from a FitsChan
-f - AST_PURGEWCS: Delete all WCS-related cards in a FitsChan
-f - AST_PUTCARDS: Stores a set of FITS header card in a FitsChan
-f - AST_PUTFITS: Store a FITS header card in a FitsChan
-f - AST_PUTTABLE: Store a single FitsTables in a FitsChan
-f - AST_PUTTABLES: Store multiple FitsTables in a FitsChan
-f - AST_READFITS: Read cards in through the source function
-f - AST_REMOVETABLES: Remove one or more FitsTables from a FitsChan
-f - AST_RETAINFITS: Ensure current card is retained in a FitsChan
-f - AST_SETFITS<X>: Store a new keyword value in a FitsChan
-c - AST_SHOWFITS: Display the contents of a FitsChan on standard output
-f - AST_TABLESOURCE: Register a source function for FITS table access
-f - AST_TESTFITS: Test if a keyword has a defined value in a FitsChan
-f - AST_WRITEFITS: Write all cards out to the sink function
-
-* Copyright:
-* Copyright (C) 1997-2006 Council for the Central Laboratory of the
-* Research Councils
-* Copyright (C) 2008-2011 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
-* <http://www.gnu.org/licenses/>.
-
-* Authors:
-* DSB: David Berry (Starlink)
-* RFWS: R.F. Warren-Smith (Starlink, RAL)
-* TIMJ: Tim Jenness (JAC, Hawaii)
-
-* History:
-* 11-DEC-1996 (DSB):
-* Original version.
-* 20-MAR-1997 (DSB):
-* Made keyword setting and getting functions protected instead of
-* public. Renamed public methods. Added Ncard attribute.
-* 20-MAY-1997 (RFWS):
-* Tidied public prologues.
-* 30-JUN-1997 (DSB):
-* Added support for reading post-2000 DATE-OBS strings. Reading DSS
-* or FITS-WCS objects now returns NULL unless the FitsChan is
-* positioned at the start-of-file prior to the read. Bug fixed
-* which caused Ncard to be returned too large by one. Removed
-* dependancy on hard-wired header and footer text in Native
-* FitsChans.
-* 18-AUG-1997 (DSB):
-* Bug fixed in WcsNative which caused incorrect CRVAL values
-* to be used if the axes needed permuting. Values assigned to the
-* Projection attribute fo the SkyFrames created by astRead.
-* 2-SEP-1997 (DSB):
-* Added the IRAF convention that EPOCH=0.0 really means EPOCH=1950.0
-* (the EPOCH keyword is deprecated in the new FITS-WCS conventions
-* and is taken always as a Besselian epoch).
-* 19-SEP-1997 (DSB):
-* Corrected interpretation of the FITS CD matrix.
-* 25-SEP-1997 (DSB):
-* o Fix bug in LinearMap which caused it always to detect a linear
-* mapping. For instance, this allowed DssMaps to be erroneously
-* written out using FITS-WCS encoding with a CAR projection.
-* o Assign a full textual description to SkyFrame's Projection
-* attribute instead of a 3 letter acronym.
-* o If DATE-OBS >= 1999.0 then DATE-OBS is now written in new
-* Y2000 format. For DATE-OBS < 1999.0, the old format is written.
-* o Add new attribute CDMatrix to determine whether PC or CD
-* matrices should be used when writing objects using FITS-WCS
-* encoding.
-* o Modified the way floating point values are formatted to omit
-* unnecessary leading zeros from the exponent (i.e. E-5 instead of
-* E-05).
-* o New-line characters at the end of supplied header cards are now
-* ignored.
-* o Cater for EQUINOX specified as a string prefixed by B or J
-* rather than as a floating point value (some HST data does this).
-* o Corrected SetValue so that it always inserts comment cards
-* rather than over-write existing comment cards. Previously,
-* writing a FrameSet to a DSS encoded FitsChan resulted in all
-* comments cards being stripped except for the last one.
-* o Reading a FrameSet from a DSS-encoded FrameSet now only
-* removes the keywords actually required to construct the FrameSet.
-* Previously, all keywords were removed.
-* o The EPOCH and EQUINOX keywords created when a FrameSet is
-* written to a DSS-encoded FitsChan are now determined from the
-* epoch and equinox of the current Frame, instead of from a copy
-* of the original FitsChan stored within the DssMap.
-* o The Encoding and CDMatrix attributes, and keyword types are
-* now stored as strings externally instead of integers.
-* 11-NOV-1997 (DSB):
-* o Assume default of j2000 for DSS EQUINOX value.
-* o Check for null object pointers in the interfaces for
-* virtual functions which execute even if an error has previously
-* occurred. Otherwise, a segmentation violation can occur when
-* trying to find the member function pointer.
-* o Trailing spaces ignored in Encoding attribute.
-* o Bugs fixed in FindWcs and SetValue which resulted in WCS cards
-* being written at the wrong place if the supplied FitsChan does not
-* contain any WCS keywords.
-* o Default for CDMatrix (if no axis rotation keywords can be found)
-* changed to 2 (i.e. use "CDi_j" form keywords).
-* o Write now leaves the current card unchanged if nothing is
-* written to the FitsChan.
-* 17-NOV-1997 (RFWS):
-* Disabled use of CDmatrix. Fixed initialisation problems in
-* astLoadFitsChan.
-* 24-NOV-1997 (DSB):
-* Replace references to error code AST__OPT with AST__RDERR.
-* 28-NOV-1997 (DSB):
-* o Function WcsValues modified to prevent it from changing the
-* current card. Previously, this could cause new cards to be
-* written to the wrong place in a FITS-WCS encoded FitsChan.
-* o Description of argument "value" corrected in prologue of
-* function SetFits.
-* o Argument "lastkey" removed from function SetValue since it
-* was never used (it was a relic from a previous method of
-* determining where to store new cards). Corresponding changes
-* have been made to all the functions which create "lastkey" values
-* or pass them on to SetValue (i.e DescWcs, WcsPrimary, WcsSecondary,
-* WriteWcs and WriteDss).
-* 10-DEC-1997 (DSB):
-* Bug fixed which caused the initial character designating the system
-* within CTYPE value (eg E in ELON, G in GLON, etc) to be omitted.
-* 1-JUN-1998 (DSB):
-* CDELT values of zero are now replaced by a small non-zero value
-* when creating the "pixel-to-relative physical" transformation
-* matrix. Previously, zero CDELT values could cause the matrix to
-* be non-invertable.
-* 4-SEP-1998 (DSB):
-* - Indicate that SphMaps created by this class when using FITS-WCS
-* encoding all operate on the unit sphere. This aids simplification.
-* - Fix a bug in StoreFits which caused CD matrices to be indexed
-* incorrectly (sometimes causing floating exceptions) if they do not
-* describe a celestial longitude/latitude system.
-* - Changed astFindFits to ignore trailing spaces in the keyword
-* template.
-* - astSplit changed so that an error is not reported if a textual
-* keyword value ends before column 20.
-* 7-OCT-1998 (DSB):
-* - Corrected test for linearity in LinearMap to include a factor
-* of the test vector length. Also LinearMap now uses a simplified
-* Mapping.
-* 5-NOV-1998 (DSB):
-* Added FITS-IRAF encoding.
-* 9-NOV-1998 (DSB):
-* - Corrected values of macros DSS_ENCODING and MAX_ENCODING.
-* - Corrected erroneous success indication in IrafStore.
-* - Included checks for bad values in function LinearMap.
-* 17-NOV-1998 (DSB):
-* The Domain name GRID is now given to the Base Frame in any FrameSets
-* created by astRead when using FitsChans with DSS, FITS-WCS or
-* FITS-IRAF encodings.
-* 18-DEC-1998 (DSB):
-* Check for "D" exponents in floating point keyword strings.
-* 12-FEB-1998 (DSB):
-* Modified EncodeFloat to avoid exceeding the 20 character FITS
-* limit wherever possible if FitsDigits is positive.
-* 10-MAY-1998 (DSB):
-* Bug fixed in astSplit which caused comments associated with string
-* keywords to be lost when storing the card in a FitsChan.
-* 15-JUN-1999 (DSB):
-* Report an error if an unrecognised projection name is supplied.
-* 9-DEC-1999 (DSB):
-* - Fixed bug in WcsNatPole which could result in longitude values
-* being out by 180 degrees for cylindrical projections such as CAR.
-* - Only report an "unrecognised projection" error for CTYPE values
-* which look like celestial longitude or latitude axes (i.e. if the
-* first 4 characters are "RA--", "DEC-", "xLON" or "xLAT", and the
-* fifth character is "-").
-* - Added function SpecTrans to translated keywords related to the
-* IRAF ZPX projection into keyword for the standard ZPN projection.
-* - Add ICRS as a valid value for the RADECSYS keyword. Since the
-* SkyFrame class does not yet support ICRS, an FK5 SkyFrame is
-* created if RADECSYS=ICRS.
-* 16-DEC-1999 (DSB):
-* - Modified SpecTrans so that all keywords used to created a
-* standard WCS representation from a non-standard one are consumed
-* by the astRead operation.
-* - Changed the text of ASTWARN cards added to the FitsChan if an
-* IRAF ZPX projection is found to require unsupported corrections.
-* - Simplified the documentation describing the handling of the IRAF
-* ZPX projection.
-* - Fixed code which assumed that the 10 FITS-WCS projection
-* parameters were PROJP1 -> PROJP10. In fact they are PROJP0 -
-* PROJP9. This could cause projection parameter values to be
-* incorrectly numbered when they are written out upon deletion of
-* the FitsChan.
-* 1-FEB-2000 (DSB):
-* Check that FITS_IRAF encoding is not being used before using a
-* PC matrix when reading WCS information from a header. This is
-* important if the header contains both PC and CD matrices.
-* 8-FEB-2000 (DSB):
-* - Header cards are now only consumed by an astRead operation if the
-* operation succeeds (i.e. returns a non-null Object).
-* - The original FITS-WCS encoding has been renamed as FITS-PC (to
-* indicate the use of a PCiiijjj matrix), and a new FITS-WCS
-* encoding has been added.
-* - The disabled CDMatrix attribute has been removed.
-* - Bug in LinearMap corrected which prevented genuinely linear
-* Mappings from being judged to be linear. This bug was previously
-* fudged (so it now appears) by the introduction of the test vector
-* length factor (see History entry for 7-OCT-1998). This test
-* vector length scale factor has consequently now been removed.
-* - Added FITS-AIPS encoding.
-* - The critical keywords used to select default encoding have been
-* changed.
-* - Support for common flavours of IRAF TNX projections added.
-* - The algorithm used to find a WcsMap in the supplied FrameSet
-* has been improved so that compound Mappings which contain complex
-* mixtures of parallel and serial Mappings can be translated into
-* FITS-WCS encoding.
-* - Trailing white space in string keyword values is now retained
-* when using foreign encodings to enable correct concatenation where
-* a string has been split over several keywords. E.g. if 2 string
-* keywords contain a list of formatted numerical values (e.g. IRAF
-* WAT... keywords), and the 1st one ends "0.123 " and the next one
-* begins "1234.5 ", the trailing space at the end of the first keyword
-* is needed to prevent the two numbers being merged into "0.1231234.5".
-* Trailing spaces in native encodings is still protected by enclosing
-* the whole string in double quotes.
-* - The Channel methods WriteString and GetNextData can now save
-* and restore strings of arbitary length. This is done by storing
-* as much of the string as possible in the usual way, and then
-* storing any remaining characters in subsequent CONTINUE cards,
-* using the FITSIO conventions. This storage and retrieval of long
-* strings is only available for native encodings.
-* 19-MAY-2000 (DSB):
-* Added attribute Warnings. Lowered DSS in the priority list
-* of encodings implemented by GetEncoding.
-* 6-OCT-2000 (DSB):
-* Increased size of buffers used to store CTYPE values to take
-* account of the possiblity of lots of trailing spaces.
-* 5-DEC-2000 (DSB):
-* Add support for the WCSNAME FITS keyword.
-* 12-DEC-2000 (DSB):
-* Add a title to each physical, non-celestial coord Frame based on
-* its Domain name (if any).
-* 3-APR-2001 (DSB):
-* - Use an "unknown" celestial coordinate system, instead of a
-* Cartesian coordinate system, if the CTYPE keywords specify an
-* unknown celestial coordinate system.
-* - Do not report an error if there are no CTYPE keywords in the
-* header (assume a unit mapping, like in La Palma FITS files).
-* - Add a NoCTYPE warning condition.
-* - Added AllWarnings attribute.
-* - Ensure multiple copies of identical warnings are not produced.
-* - Use the Object Ident attribute to store the identifier letter
-* associated with each Frame read from a secondary axis description,
-* so that they can be given the same letter when they are written
-* out to a new FITS file.
-* 10-AUG-2001 (DSB):
-* - Corrected function value returned by SkySys to be 1 unless an
-* error occurs. This error resulted in CAR headers being produced
-* by astWrite with CRVAL and CD values till in radians rather than
-* degrees.
-* - Introduced SplitMap2 in order to guard against producing
-* celestial FITS headers for a Mapping which includes more than
-* one WcsMap.
-* 13-AUG-2001 (DSB):
-* - Modified FixNew so that it retains the current card index if possible.
-* This fixed a bug which could cause headers written out using Native
-* encodings to be non-contiguous.
-* - Corrected ComBlock to correctly remove AST comment blocks in
-* native encoded fitschans.
-* 14-AUG-2001 (DSB):
-* - Modified FixUsed so that it it does not set the current card
-* back to the start of file if the last card in the FitsChan is
-* deleted.
-* 16-AUG-2001 (DSB):
-* Modified WcsNative to limit reference point latitude to range
-* +/-90 degs (previously values outside this range were wrapped
-* round onto the opposite meridian). Also added new warning
-* condition "badlat".
-* 23-AUG-2001 (DSB):
-* - Re-write LinearMap to use a least squares fit.
-* - Check that CDj_i is not AST__BAD within WcsWithWcs when
-* forming the increments along each physical axis.
-* 28-SEP-2001 (DSB):
-* GoodWarns changed so that no error is reported if a blank list
-* of conditions is supplied.
-* 12-OCT-2001 (DSB):
-* - Added DefB1950 attribute.
-* - Corrected equations which calculate CROTA when writing
-* FITS-AIPS encodings.
-* - Corrected equations which turn a CROTA value into a CD matrix.
-* 29-NOV-2001 (DSB):
-* Corrected use of "_" and "-" characters when referring to FK4-NO-E
-* system in function SkySys.
-* 20-FEB-2002 (DSB)
-* Added CarLin attribute.
-* 8-MAY-2002 (DSB):
-* Correct DSSToStore to ignore trailing blanks in the PLTDECSN
-* keyword value.
-* 9-MAY-2002 (DSB):
-* Correct GetCard to avoid infinite loop if the current card has
-* been marked as deleted.
-* 25-SEP-2002 (DSB):
-* AIPSFromStore: use larger of coscro and sincro when determining
-* CDELT values. Previously a non-zero coscro was always used, even
-* if it was a s small as 1.0E-17.
-* 3-OCT-2002 (DSB):
-* - SkySys: Corrected calculation of longitude axis index for unknown
-* celestial systems.
-* - SpecTrans: Corrected check for latcor terms for ZPX projections.
-* - WcsFrame: Only store an explicit equinox value in a skyframe if
-* it needs one (i.e. if the system is ecliptic or equatorial).
-* - WcsWithWcs: For Zenithal projections, always use the default
-* LONPOLE value, and absorb any excess rotation caused by this
-* into the CD matrix.
-* - WcsWithWcs: Improve the check that the native->celestial mapping
-* is a pure rotation, allowing for rotations which change the
-* handed-ness of the system (if possible).
-* - WcsWithWcs: Avoid using LONPOLE keywords when creating headers
-* for a zenithal projection. Instead, add the corresponding rotation
-* into the CD matrix.
-* 22-OCT-2002 (DSB):
-* - Retain leading and trailing white space within COMMENT cards.
-* - Only use CTYPE comments as axis labels if all non-celestial
-* axes have a unique non-blank comment (otherwise use CTYPE
-* values as labels).
-* - Updated to use latest FITS-WCS projections. This means that the
-* "TAN with projection terms" is no longer a standard FITS
-* projection. It is now represented using the AST-specific TPN
-* projection (until such time as FITS-WCS paper IV is finished).
-* - Remove trailing "Z" from DATE-OBS values created by astWrite.
-* 14-NOV-2002 (DSB):
-* - WcsWithWcs: Corrected to ignore longitude axis returned by
-* astPrimaryFrame since it does not take into account any axis
-* permutation.
-* 26-NOV-2002 (DSB):
-* - SpecTrans: Corrected no. of characters copied from CTYPE to PRJ,
-* (from 5 to 4), and terminate PRJ correctly.
-* 8-JAN-2003 (DSB):
-* Changed private InitVtab method to protected astInitFitsChanVtab
-* method.
-* 22-JAN-2003 (DSB):
-* Restructured the functions used for reading FITS_WCS headers to
-* make the distinction between the generic parts (pixel->intermediate
-* world coordinates) and the specialised parts (e.g. celestial,
-* spectral, etc) clearer.
-* 31-JAN-2003 (DSB)
-* - Added Clean attribute.
-* - Corrected initialisation and defaulting of CarLin and DefB1950
-* attributes.
-* - Extensive changes to allow foreign encodings to be produced in
-* cases where the Base Frame has fewer axes than the Current Frame.
-* 12-FEB-2003 (DSB)
-* - Modified SetFits so that the existing card comment is retained
-* if the new data value equals the existing data value.
-* 30-APR-2003 (DSB):
-* - Revert to standard "TAN" code for distorted tan projections,
-* rather than using the "TPN" code. Also recognise QVi_m (produced
-* by AUTOASTROM) as an alternative to PVi_m when reading distorted
-* TAN headers.
-* 22-MAY-2003 (DSB):
-* Modified GetEncoding so that the presence of RADECSYS and/or
-* PROJPm is only considered significant if the modern equivalent
-* keyword (REDESYS or PVi_m) is *NOT* present.
-* 2-JUN-2003 (DSB):
-* - Added support for PCi_j kewwords within FITS-WCS encoding
-* - Added CDMatrix attribute
-* - Changed internal FitsStore usage to use PC/CDELT instead of CD
-* (as preparation for FITS-WCS paper IV).
-* - Added warning "BadMat".
-* 11-JUN-2003 (DSB):
-* - Modified WcsNative to use the new SphMap PolarLong attribute
-* in order to ensure correct propagation of the longitude CRVAL
-* value in cases where the fiducial point is coincident with a pole.
-* - Use PVi_3 and PVi_4 for longitude axis "i" (if present) in
-* preference to LONPOLE and LATPOLE when reading a FITS-WCS header.
-* Note, these projection values are never written out (LONPOLE and
-* LATPOLE are written instead).
-* - Associate "RADESYS=ICRS" with SkyFrame( "System=ICRS" ), rather
-* than SkyFrame( "System=FK5" ).
-* - If DefB1950 is zero, use ICRS instead of FK5 as the default RADESYS
-* if no EQUINOX is present.
-* 1-SEP-2003 (DSB):
-* - Modify Dump so that it dumps all cards including those flagged as
-* having been read.
-* - Added "reset" parameter to FixUsed.
-* - WcsMapFrm: store an Ident of ' ' for the primary coordinate
-* description (previously Ident was left unset)
-* - Default value for DefB1950 attribute now depends on the value
-* of the Encoding attribute.
-* 15-SEP-2003 (DSB):
-* - Added Warnings "BadVal", "Distortion".
-* - Ignore FITS-WCS paper IV CTYPE distortion codes (except for
-* "-SIP" which is interpreted correctly on reading).
-* 22-OCT-2003 (DSB):
-* - GetEncoding: If the header contains CDi_j but does not contain
-* any of the old IRAF keywords (RADECSYS, etc) then assume FITS-WCS
-* encoding. This allows a FITS-WCS header to have both CDi_j *and*
-* CROTA keywords.
-* 5-JAN-2004 (DSB):
-* - SpecTrans: Use 1.0 (instead of the CDELT value) as the
-* diagonal PCi_j term for non-celestial axes with associated CROTA
-* values.
-* 12-JAN-2004 (DSB):
-* - CelestialAxes: Initialise "tmap1" pointer to NULL in case of error
-* (avoids a segvio happening in the case of an error).
-* - AddVersion: Do not attempt to add a Frame into the FITS header
-* if the mapping from grid to frame is not invertable.
-* - WorldAxes: Initialise the returned "perm" values to safe values,
-* and return these values if no basis vectors cen be created.
-* 19-JAN-2004 (DSB):
-* - When reading a FITS-WCS header, allow all keywords to be defaulted
-* as decribed in paper I.
-* 27-JAN-2004 (DSB):
-* - Modify FitLine to use correlation between actual and estimated
-* axis value as the test for linearity.
-* - Modify RoundFString to avoid writing beyond the end of the
-* supplied buffer if the supplied string contains a long list of 9's.
-* 11-MAR-2004 (DSB):
-* - Modified SpecTrans to check all axis descriptions for keywords
-* to be translated.
-* 19-MAR-2004 (DSB):
-* - Added astPutCards to support new fits_hdr2str function in
-* CFITSIO.
-* 25-MAR-2004 (DSB):
-* - Corrected bug in astSplit which causes legal cards to be
-* rejected because characters beyond the 80 char limit are being
-* considered significant.
-* - Corrected bug in SpecTrans which caused QV keywords to be
-* ignored.
-* 15-APR-2004 (DSB):
-* - SpecTrans modified to include translation of old "-WAV", "-FRQ"
-* and "-VEL" spectral algorithm codes to modern "-X2P" form.
-* - WcsFromStore modified to supress creation of WCSAXES keywords
-* for un-used axis versions.
-* - IsMapLinear modified to improve fit by doing a second least
-* squares fit to the residualleft by the first least squares fit.
-* 16-APR-2004 (DSB):
-* - NonLinSpecWcs: Issue a warning if an illegal non-linear
-* spectral code is encountered.
-* - Add a BadCTYPE warning condition.
-* - Corrected default value for Clean so that it is zero (as
-* documented).
-* 21-APR-2004 (DSB):
-* - FindWcs: Corrected to use correct OBSGEO template. This bug
-* caused OBSGEO keywords to be misplaced in written headers.
-* 23-APR-2004 (DSB):
-* - SplitMap: Modified so that a Mapping which has celestial axes
-* with constant values (such as produced by a PermMap) are treated
-* as a valid sky coordinate Mapping.
-* - AddFrame modified so that WCS Frames with a different number
-* of axes ot the pixel Frame can be added into the FrameSet.
-* - IRAFFromStore and AIPSFromStore modified so that they do not
-* create any output keywords if the number of WCS axes is different
-* to the number of pixel axes.
-* - Handling of OBSGEO-X/Y/Z corrected again.
-* - WCSFromStore modified to avouid writing partial axis descriptions.
-* 26-APR-2004 (DSB):
-* - Corrected text of output SPECSYS keyword values.
-* 17-MAY-2004 (DSB):
-* - Added IWC attribute.
-* 15-JUN-2004 (DSB):
-* - Ensure out-of-bounds longitude CRPIX values for CAR
-* projections are wrapped back into bounds.
-* 21-JUN-2004 (DSB):
-* - Ensure primary MJD-OBS value is used when reading foreign FITS
-* headers.
-* 7-JUL-2004 (DSB):
-* - Issue errors if an un-invertable PC/CD matrix is supplied in a
-* FITS-WCS Header.
-* 11-JUL-2004 (DSB):
-* - Re-factor code for checking spectral axis CTYPE values into
-* new function IsSpectral.
-* - Modify AIPSFromSTore to create spectral axis keywords if
-* possible.
-* - Modify SpecTrans to recognize AIPS spectral axis keywords, and
-* to convert "HZ" to "Hz".
-* - Added FITS-AIPS++ encoding.
-* 12-AUG-2004 (DSB):
-* - Convert GLS projection codes to equivalent SFL in SpecTrans.
-* - Added FITS-CLASS encoding.
-* 16-AUG-2004 (DSB):
-* - Removed support for paper III keyword VSOURCE, and added
-* support for SSYSSRC keyword.
-* - Added initial support for CLASS encoding.
-* - In FitOK: Changed tolerance for detecting constant values
-* from 1.0E-10 to 1.0E-8.
-* 17-AUG-2004 (DSB):
-* Correct GetFiducialNSC so that the stored values for longitude
-* parameters 1 and 2 are ignored unless the value of parameter 0 is
-* not zero.
-* 19-AUG-2004 (DSB):
-* Modify SpecTrans to ignore any CDELT values if the header
-* includes some CDi_j values.
-* 26-AUG-2004 (DSB):
-* Modify astSplit_ to allow floating point keyword values which
-* include an exponent to be specified with no decimal point
-* (e.g. "2E-4").
-* 27-AUG-2004 (DSB):
-* Completed initial attempt at a FITS-CLASS encoding.
-* 9-SEP-2004 (DSB):
-* Fixed usage of uninitialised values within ReadCrval.
-* 13-SEP-2004 (DSB):
-* Check the "text" pointer can be used safely before using it in
-* DSSToStore.
-* 27-SEP-2004 (DSB):
-* In SpecTrans, before creating new PCi_j values, check that no
-* PCi_j values have been created via an earlier translation.
-* 28-SEP-2004 (DSB):
-* In AIPSPPFromStore only get projection parameters values if there
-* are some celestialaxes. Also allow CROTA to describe rotation of
-* non-celestial axes (same for AIPSFromSTore).
-* 4-OCT-2004 (DSB):
-* Correct rounding of CRPIX in AddVersion to avoid integer overflow.
-* 11-NOV-2004 (DSB):
-* - WcsFcRead: Avoid issuing warnings about bad keywords which
-* have already been translated into equivalent good forms.
-* - SpecTrans: If both PROJP and PV keywords are present, use PV
-* in favour of PROJP only if the PV values look correct.
-* 17-NOV-2004 (DSB):
-* - Make astSetFits<X> public.
-* 16-MAR-2005 (DSB):
-* - Primary OBSGEO-X/Y/Z, MJD-AVG and MJDOBS keywords are associated
-* with all axis descriptions and should not have a trailing single
-* character indicating an alternate axis set.
-* 9-AUG-2005 (DSB):
-* In WcsMapFrm, check reffrm is used before annulling it.
-* 8-SEP-2005 (DSB):
-* - Change "if( a < b < c )" constructs to "if( a < b && b < c )"
-* - DSBSetup: correct test on FrameSet pointer state
-* - Ensure CLASS keywords written to a FitsChan do not come before
-* the final fixed position keyword.
-* 9-SEP-2005 (DSB):
-* - Added "AZ--" and "EL--" as allowed axis types in FITS-WCS
-* ctype values.
-* 12-SEP-2005 (DSB):
-* - Cast difference between two pointers to (int)
-* - CLASSFromStore:Check source velocity is defined before
-* storing it in the output header.
-* 13-SEP-2005 (DSB):
-* - Corrected B1940 to B1950 in AddEncodingFrame. This bug
-* prevented some FrameSets being written out using FITS-CLASS.
-* - Rationalise the use of the "mapping" pointer in AddVersion.
-* - WcsCelestial: Modified so that the FITS reference point is
-* stored as the SkyFrame SkyRef attribute value.
-* 7-OCT-2005 (DSB):
-* Make astGetFits<X> public.
-* 30-NOV-2005 (DSB):
-* Add support for undefined FITS keyword values.
-* 5-DEC-2005 (DSB):
-* - Include an IMAGFREQ keyword in the output when writing a
-* DSBSpecFrame out using FITS-WCS encoding.
-* - Correct test for constant values in FitOK.
-* 7-DEC-2005 (DSB):
-* Free memory allocated by calls to astReadString.
-* 30-JAN-2006 (DSB):
-* Modify astSplit so that it does no read the supplied card beyond
-* column 80.
-* 14-FEB-2006 (DSB):
-* Override astGetObjSize.
-* 28-FEB-2006 (DSB):
-* Correct documentation typo ("NCards" -> "Ncard").
-* 5-APR-2006 (DSB):
-* Modify SpecTrans to convert CTYPE="LAMBDA" to CTYPE="WAVE".
-* 26-MAY-2006 (DSB):
-* Guard against NULL comment pointer when converting RESTFREQ to
-* RESTFRQ in SpecTrans.
-* 29-JUN-2006 (DSB):
-* - Added astRetainFits.
-* - Consume VELOSYS FITS-WCS keywords when reading an object.
-* - Write out VELOSYS FITS-WCS keywords when writing an object.
-* 7-AUG-2006 (DSB):
-* Remove trailing spaces from the string returned by astGetFitsS
-* if the original string contains 8 or fewer characters.
-* 16-AUG-2006 (DSB):
-* Document non-destructive nature of unsuccessful astRead calls.
-* 17-AUG-2006 (DSB):
-* Fix bugs so that the value of the Clean attribute is honoured
-* even if an error has occurred.
-* 4-SEP-2006 (DSB):
-* Modify GetClean so that it ignores the inherited status.
-* 20-SEP-2006 (DSB):
-* Fix memory leak in WcsSpectral.
-* 6-OCT-2006 (DSB):
-* Modify IsSpectral and IsAIPSSpectral to allow for CTYPE values that
-* are shorter than eight characters.
-* 13-OCT-2006 (DSB):
-* - Ensure SpecFrames and SkyFrames created from a foreign FITS header
-* are consistent in their choice of Epoch.
-* - Convert MJD-OBS and MJD-AVG values from TIMESYS timescale to
-* TDB before using as the Epoch value in an AstFrame. Use UTC if
-* TIMESYS is absent.
-* - Convert Epoch values from TDB to UTC before storing as the
-* value of an MJD-OBS or MJD-AVG keyword (no TIMESYS keyword is
-* written).
-* 23-OCT-2006 (DSB):
-* Prefer MJD-AVG over MJD-OBS.
-* 30-OCT-2006 (DSB):
-* In FitOK: Changed lower limit on acceptbale correlation from
-* 0.999999 to 0.99999.
-* 1-NOV-2006 (DSB):
-* - When reading a foreign header that contains a DUT1 keyword,
-* use it to set the Dut1 attribute in the SkyFrame. Note, JACH
-* store DUT1 in units of days. This may clash with the FITS-WCS
-* standard (when its produced). Also note that DUT1 is not written
-* out as yet when writing a FrameSet to a foreign FITS header.
-* - Correct bug that prevented ZSOURCE keyword being added to the
-* output header if the source velocity was negative.
-* 9-NOV-2006 (DSB):
-* Add STATUS argument to docs for F77 AST_SETx.
-* 20-DEC-2006 (DSB):
-* Correct FK5 to ICRS in error message issued if no RADESYS or
-* EQUINOX is found.
-* 16-JAN-2007 (DSB):
-* Cast ignored function return values to (void) to avoid compiler
-* warnings.
-* 31-JAN-2007 (DSB):
-* Change SpecTrans to ignore blank unit strings (previously
-* converted them to "Hz").
-* 16-APR-2007 (DSB):
-* In SplitMat, increase the allowed level of rounding erros from
-* 1.0E-10 to 1.0E-7 (to avoid spurious low CDi_j values being
-* created that should be zero).
-* 30-APR-2007 (DSB):
-* - Change DSBSetup so that the central DSBSpecFrame frequency is
-* CRVAL and the IF is the difference between CRVAL and LO.
-* - Change tolerance in FitOK from 0.99999 to 0.995 to handle data from Nicolas
-* Peretto.
-* 1-MAY-2007 (DSB):
-* - In astSplit, if a keyword value looks like an int but is too long to
-* fit in an int, then treat it as a float instead.
-* 18-MAY-2007 (DSB):
-* In CnvType, use input type rather than output type when checking
-* for a COMMENT card. Also, return a null data value buffer for a
-* COMMENT card.
-* 4-JUN-2007 (DSB):
-* In CLASSFromStore, create a DELTAV header even if it is equal to
-* the spectral CDELT value. Also, convert spatial reference point
-* to (az,el) and write out as headers AZIMUTH and ELEVATIO.
-* 9-JUL-2007 (DSB):
-* Fixed bug in DSBSetUp - previously, this function assumed that
-* the supplied DSBSpecFrame represented frequency, and so gave
-* incorrect values for IF and DSBCentre if the header described
-* velocity.
-* 9-AUG-2007 (DSB):
-* Changed GetEncoding so that critcal keywords are ignored if
-* there are no CTYPE, CRPIX or CRVAL keywords in the header.
-* 10-AUG-2007 (DSB):
-* - Changed GetEncoding so that FITS_PC is not returned if there are
-* any CDi_j or PCi_j keywords in the header.
-* - Added astPurgeWCS method.
-* 13-AUG-2007 (DSB):
-* - Include the DSS keywords AMDX%d and AMDY%d in FindWCS.
-* 16-AUG-2007 (DSB):
-* - Force all FITS-CLASS headers to contain frequency axes
-* (velocity axes seem not to be recognised properly by CLASS).
-* - Change the CLASS "VELO-LSR" header to be the velocity at the
-* reference channel, not the source velocity.
-* 22-AUG-2007 (DSB):
-* - Remove debugging printf statements.
-* 20-SEP-2007 (DSB):
-* Changed FitOK to check that the RMS residual is not more than
-* a fixed small fraction of the pixel size.
-* 4-DEC-2007 (DSB):
-* Changed CreateKeyword so that it uses a KeyMap to search for
-* existing keywords. This is much faster than checking every
-* FitsCard in the FitsChan explicitly.
-* 18-DEC-2007 (DSB):
-* Add keyword VLSR to the CLASS encoding. It holds the same value
-* as VELO-LSR, but different versions of class use different names.
-* Also write out the DELTAV keyword in the LSR rest frame rather
-* than the source rest frame.
-* 31-JAN-2008 (DSB):
-* Correct calculation of redshift from radio velocity in ClassTrans.
-* 25-FEB-2008 (DSB):
-* Ensure a SkyFrame represents absolute (rather than offset)
-* coords before writing it out in any non-native encoding.
-* 28-FEB-2008 (DSB):
-* Test for existing of SkyRefIs attribute before accessing it.
-* 2-APR-2008 (DSB):
-* In CLASSFromStore, adjust the spatial CRVAL and CRPIX values to be
-* the centre of the first pixel if the spatial axes are degenerate.
-* 17-APR-2008 (DSB):
-* Ignore latitude axis PV terms supplied in a TAN header
-* (previously, such PV terms were used as polynomial correction
-* terms in a TPN projection).
-* 30-APR-2008 (DSB):
-* SetValue changed so that new keywords are inserted before the
-* current card.
-* 1-MAY-2008 (DSB):
-* Added UndefRead warning.
-* 7-MAY-2008 (DSB):
-* Correct conversion of CDi_j to PCi_j/CDELT in SpecTrans.
-* 8-MAY-2008 (DSB):
-* When writing out a FITS-WCS header, allow linear grid->WCS
-* mapping to be represented by a CAR projection.
-* 9-MAY-2008 (DSB):
-* Make class variables IgnoreUsed and MarkNew static.
-* 30-JUN-2008 (DSB):
-* Improve efficiency of FindWcs.
-* 2-JUL-2008 (DSB):
-* FitsSof now returns non-zero if the FitsChan is empty.
-* 16-JUL-2008 (DSB):
-* Plug memory leak caused by failure to free the Warnings
-* attribute string when a FitsChan is deleted.
-* 24-JUL-2008 (TIMJ):
-* Fix buffer overrun in astGetFits when writing the keyword
-* to the buffer (occurred if the input string was 80 characters).
-* 1-OCT-2008 (DSB):
-* When reading a FITS-WCS header, spurious PVi_j keywords no
-* longer generate an error. Instead they generate warnings via the
-* new "BadPV" warning type.
-* 21-NOV-2008 (DSB):
-* Do not remove keywords from read headers if they may be of
-* relevance to things other than WCS (e.g. MJD-OBS, OBSGEO, etc).
-* 2-DEC-2008 (DSB):
-* - astGetFits<X> now reports an error if the keyword value is undefined.
-* - Add new functions astTestFits and astSetFitsU.
-* - Remove use of AST__UNDEF<X> constants.
-* - Remove "undefread" warning.
-* 16-JAN-2009 (DSB):
-* Use astAddWarning to store each warning in the parent Channel
-* structure.
-* 4-MAR-2009 (DSB):
-* DATE-OBS and MJD-OBS cannot have an axis description character.
-* 13-MAR-2009 (DSB):
-* The VELOSYS value read from the header is never used, so do not
-* report an error if VELOSYS has an undefined value.
-* 11-JUN-2009 (DSB):
-* Delay reading cards from the source until they are actually
-* needed. Previously, the source function was called in the
-* FitsChan initialiser, but this means it is not possible for
-* application code to call astPutChannelData before the source
-* function is called. The ReadFromSource function is now called
-* at the start of each (nearly) public or protected function to
-* ensure the source function has been called (the source function
-* pointer in the FitsChan is then nullified to ensure it is not
-* called again).
-* 18-JUN-2009 (DSB):
-* Include the effect of observer height (in the ObsAlt attribute)
-* when creating OBSGEO-X/Y/Z headers, and store a value for
-* ObsAlt when reading a set of OBSGEO-X/Y/Z headers.
-* 2-JUL-2009 (DSB):
-* Check FitsChan is not empty at start of FindWcs.
-* 7-JUL-2009 (DSB):
-* Add new function astSetFitsCM.
-* 30-JUL-2009 (DSB):
-* Fix axis numbering in SkyPole.
-* 12-FEB-2010 (DSB):
-* Use "<bad>" to represent AST__BAD externally.
-* 25-JUN-2010 (DSB):
-* Fix problem rounding lots of 9's in RoundFString. The problem
-* only affected negative values, and could lead to an extra zero
-* being included in the integer part.
-* 28-JUN-2010 (DSB):
-* Another problem in RoundFString! If the value has a series of
-* 9's followed by a series of zeros, with no decimal point (e.g.
-* "260579999000"), then the trailing zeros were being lost.
-* 16-JUL-2010 (DSB):
-* In SpecTrans, avoid over-writing the spatial projection code
-* with the spectral projection code.
-* 20-JUL-2010 (DSB):
-* Correct interpretation of NCP projection code.
-* 14-OCT-2010 (DSB):
-* - Correct loading of FitsChans that contain UNDEF keywords.
-* - Correct translation of spectral units with non-standard
-* capitalisation in SpecTrans.
-* 10-JAN-2011 (DSB):
-* Fix memory leak in MakeIntWorld.
-* 13-JAN-2011 (DSB):
-* Rename astEmpty ast astEmptyFits and make public.
-* 20-JAN-2011 (DSB):
-* - Extensive changes to support -TAB algorithm
-* - Recovery from a major unrequested reformatting of whitespace by
-* my editor!
-* 7-FEB-2011 (DSB):
-* Put a space between keyword value and slash that starts a comment
-* when formatting a FITS header card.
-* 11-FEB-2011 (DSB):
-* Change meaning of TabOK attribute. It is no longer a simple
-* boolean indicating if the -TAB algorithm is supported. Instead
-* it gives the value to be used for the EXTVER header - i.e. the
-* version number to store with any binary table created as a
-* result of calling astWrite. If TabOK is zero or begative, then
-* the -TAB algorithm is not supported. This is so that there is
-* some way of having multiple binary table extensions with the same
-* name (but different EXTVER values).
-* 14-FEB-2011 (DSB):
-* - Spectral reference point CRVAL records the obs. centre. So for -TAB
-* (when CRVAL is set to zero) we need to record the obs centre some
-* other way (use the AST-specific AXREF keywords, as for spatial axes).
-* - Whether to scale spatial axes from degs to rads depends on
-* whether the spatial axes are descirbed by -TAB or not.
-* - Relax the linearity requirement in IsMapLinear by a factor of
-* 10 to prevent a change in rest frame resulting in a non-linear
-* mapping.
-* 17-FEB-2011 (DSB):
-* Fix bug in axis linearity check (IsMapLinear).
-* 22-FEB-2011 (DSB):
-* The translations of AIPS non-standard CTYPE values were always
-* stored as primary axis description keywords, even if the original
-* non-standard CTYPE values were read from an alternative axis
-* descriptions.
-* 5-APR-2011 (DSB):
-* In SpecTrans, correct the MSX CAR projection translation. The
-* first pixel starts at GRID=0.5, not GRID=0.0. So the CRPIX value
-* needs to be reduced by 0.5 prior to normalisation, and then
-* increased by 0.5 after normalisation.
-* 23-MAY-2011 (DSB):
-* Add support for TNX projections that use Chebyshev polynomials.
-* 24-MAY-2011 (DSB):
-* - Add support for ZPX projections that include IRAF polynomial
-* corrections.
-* - Add PolyTan attribute.
-* - Fix interpretation of -SIP headers that have no inverse.
-* 1-JUN-2011 (DSB):
-* In astInitFitsChanVtab, only create the two TimeFrames if they
-* have not already been created (fixes scuba2 trac ticket #666).
-* 9-JUN-2011 (DSB):
-* In WCSFcRead, ignore trailing spaces when reading string values
-* for WCS keywords.
-* 23-JUN-2011 (DSB):
-* - Override the parent astSetSourceFile method so that it reads
-* headers from the SourceFile and appends them to the end of the
-* FitsChan.
-* - On deletion, write out the FitsChan contents to the file
-* specified by the SinkFile attribute. If no file is specified,
-* use the sink function specified when the FitsChan was created.
-* 30-AUG-2011 (DSB):
-* - Added astWriteFits and astReadFits.
-* - Move the deletion of tables and warnings from Delete to
-* EmptyFits.
-* 21-SEP-2011 (DSB):
-* - In RoundFString, remember to update the pointer to the exponent.
-* This bug caused parts of the exponent to dissappear when
-* formatting a value that included some trailing zeros and a
-* series of adjacent 9's.
-* - Added Nkey attribute.
-* 22-SEP-2011 (DSB):
-* - Added CardType attribute
-* - Allow GetFits to be used to get/set the value of the current
-* card.
-* 4-OCT-2011 (DSB):
-* When reading a FITS-WCFS header, if the projection is TPV (as produced
-* by SCAMP), change to TPN (the internal AST code for a distorted
-* TAN projection).
-* 22-NOV-2011 (DSB):
-* Allow the "-SIP" code to be used with non-celestial axes.
-* 1-FEB-2012 (DSB):
-* Write out MJD-OBS in the timescale specified by any TIMESYS
-* keyword in the FitsChan, and ensure the TIMESYS value is included
-* in the output header.
-* 23-FEB-2012 (DSB):
-* Use iauGd2gc in place of palGeoc where is saves some calculations.
-* 24-FEB-2012 (DSB):
-* Move invocation of AddEncodingFrame from Write to end of
-* MakeFitsFrameSet. This is so that AddEncodingFrame can take
-* advantage of any standardisations (such as adding celestial axes)
-* performed by MakeFItsFrameSet. Without this, a FRameSet contain
-* a 1D SpecFrame (no celestial axes) would fail to be exported using
-* FITS-CLASS encoding.
-* 29-FEB-2012 (DSB):
-* Fix bug in CLASSFromStore that caused spatial axes added by
-* MakeFitsFrameSet to be ignored.
-* 2-MAR-2012 (DSB):
-* - In CLASSFromSTore, ensure NAXIS2/3 values are stored in teh FitsChan,
-* and cater for FrameSets that have only a apectral axis and no celestial
-* axes (this prevented the VELO_LSR keyword being created)..
-* 7-MAR-2012 (DSB):
-* Use iauGc2gd in place of Geod.
-* 22-JUN-2012 (DSB):
-* - Check for distorted TAN projections that have zero for all PVi_m
-* coefficients. Issue a warning and ignore the distortion in such
-* cases.
-* - Remove all set but unused variables.
-* - Convert SAO distorted TAN projections (which use COi_j keywords
-* for polynomial coeffs) to TPN.
-* 26-JUN-2012 (DSB):
-* Correct call to astKeyFields in SAOTrans (thanks to Bill Joye
-* for pointing out this error).
-* 8-AUG-2012 (DSB):
-* Correct assignment to lonpole within CLASSFromStore.
-* 10-AUG-2012 (DSB):
-* Default DSS keywords CNPIX1 and CNPIX2 to zero if they are
-* absent, rather than reporting an error.
-* 7-DEC-2012 (DSB):
-* - When writing out a FrameSet that uses an SkyFrame to describe a
-* generalised spherical coordinate system ("system=unknown"), ensure
-* that the generated FITS CTYPE values use FITS-compliant codes
-* for the axis type ( "xxLN/xxLT" or "xLON/xLAT" ).
-* - Add support for reading and writing offset SkyFrames to
-* FITS-WCS.
-* 30-JAN-2013 (DSB):
-* When reading a FITS-CLASS header, use "VLSR" keyword if
-* "VELO-..." is not available.
-* 15-APR-2013 (DSB):
-* Correct initialisation of missing coefficients When reading a
-* SAO plate solution header.
-* 16-APR-2013 (DSB):
-* When determining default Encoding value, use "VLSR" keyword if
-* "VELO-..." is not available.
-* 30-MAY-2013 (DSB):
-* Prevent seg fault caused by overrunning the coeffs array in
-* WATCoeffs in cases where the TNX/ZPX projection is found to be
-* of a form that cannot be implemented as a TPN projection.
-* 11-JUN-2013 (DSB):
-* Fix support for reading GLS projections, and add support for
-* rotated GLS projections.
-* 28-AUG-2013 (DSB):
-* In WcsCelestial, if celestial axes are found with no projection
-* code in CTYPE, assume an old-fashioned CAR projection (i.e. no
-* rotation from native to WCS coords). Before this change,
-* CTYPE = "RA" | "DEC" axes got treated as radians, not degrees.
-* 16-SEP-2013 (DSB):
-* When exporting alternate offset SkyFrames to FITS-WCS headers,
-* correctly test the alternate Frame in the supplied FrameSet, rather
-* than the current Frame.
-* 24-SEP-2013 (DSB):
-* Fix bug in choosing default value for PolyTan attribute.
-* 19-OCT-2013 (DSB):
-* - In SIPMapping, always ignore any inverse polynomial supplied in
-* a SIP header as they seem often to be inaccurate. A new inverse is
-* created to replace it.
-* - In SIPMapping, only use a fit to the inverted SIP transformation
-* if an accuracy of 0.01 pixel can be achieved over an area three
-* times the dimensions of the image. Otherwise use an iterative
-* inverse for each point. People were seeing bad round-trip errors
-* when transforming points outside the image because the fit was
-* being used when it was not very accurate.
-* 12-NOV-2013 (DSB):
-* Added CardName and CardComm attributes.
-* 13-NOV-2013 (DSB):
-* Use a zero-length string for the CardComm attribute if the card
-* has no comment.
-* 15-NOV-2013 (DSB):
-* - Added method astShowFits.
-* - Ensure PurgeWcs removes WCS cards even if an error occurs when
-* reading FrameSets from the FitsChan.
-* - Change IsMapTab1D to improve chances of a -TAB mapping being found.
-* 6-JAN-2014 (DSB):
-* - Allow default options for newly created FitsChans to be
-* specified by the FITSCHAN_OPTIONS environment variable.
-* - Ensure the used CarLin value is not changed by a trailing frequency axis.
-* 9-JUL-2014 (DSB):
-* Added attribute FitsAxisOrder, which allows an order to be
-* specified for WCS axis within FITS headers generated using astWrite.
-* 9-SEP-2014 (DSB):
-* Modify Split so that any non-printing characters such as
-* newlines at the end of the string are ignored.
-* 30-SEP-2014 (DSB):
-* Modify CnvType to indicate that comment cards cannot be
-* converted to any other data type. For instance, this causes
-* a warning to be issued if an equals sign is misplaced in a
-* WCS-related card (causing it to be treated as a comment card).
-* 24-MAR-2015 (DSB):
-* Modify SpecTrans to avoid modifying the CRPIC value for CAR
-* projections when they do not need to be modified. The princiuple
-* is that the bulk of the array should be witin the native longitude
-* range [-180,+180]. Prompted by bug report from Bill Joye "yet
-* another CAR issue" on 24-MAR-2015 (file CHIPASS_Equ.head in
-* ast_tester).
-* 27-APR-2015 (DSB):
-* Modify MakeFitsFrameSet so that isolated SkyAxes (e.g.
-* individual axes that have been oicked from a SkyFrame) are
-* re-mapped into degrees before being used.
-* 20-APR-2015 (DSB):
-* In MakeIntWorld, relax tolerance for checking that each FITS-WCS IWC
-* axis is linear, from 0.01 of a pixel to 0.1 of a pixel.
-* 6-JUL-2015 (DSB):
-* When checking a sub-string, ensure the whole string is at least as
-* long as the offset to the start of the sub-string. Without this, you
-* can get erroneous sub-string matches by chance, depending on what
-* characters happen to be present in memory after the end of the string.
-* 11-AUG-2015 (DSB):
-* - Fix bug in CheckFitsName that prevented an error from being reported
-* if the FITS keyword name contained any illegal printable characters.
-* - Add new Warning "badkeyname", and issue such a warning instead
-* of an error if illegal characters are found in a keyword name.
-* 31-AUG-2015 (DSB):
-* In FitLine, use the whole axis rather than 0.1 of the axis (if "dim"
-* is supplied). This is because non-linearity can become greater at
-* further distances along the axis. In practice, it meant that SIP
-* distortion were being treated as linear because the test did not
-* explore a large enough region of pixel space.
-* 12-OCT-2015 (DSB):
-* Only add sky axes to a SpecFrame if the WCS Frame contains no
-* other axes other than the SpecFrame (MakeFitsFrameSet).
-* 17-OCT-2015 (DSB):
-* - Add new Warning "badkeyvalue", and issue such a warning instead
-* of an error if the Split function cannot determine the keyword value.
-* - Move the check for PLTRAH (i.e. DSS encoding) higher up in GetEncoding.
-* This is because some DSS file slaos have CD and/or PC keywords.
-* 5-NOV-2015 (DSB):
-* Fix bug in MakeFitsFrameSet that could cause an inappropriate
-* RefRA and RefDec values to be used when writing out a SpecFrame
-* using FITS-WCS. This bug was caused by the assumption that
-* changing the current Frame of a FRameSet also changes the Frame
-* that was added into the FRameSet. This used to be the case as
-* astAddFrame took a clone of the supplied Frame pointer, but it
-* now takes a deep copy, so the original Frame and the FrameSet's
-* current Frame are now independent of each other.
-*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 FitsChan
-
-/* A macro which tests a character to see if it can be used within a FITS
- keyword. We include lower case letters here, but they are considered
- as equivalent to upper case letter. */
-#define isFits(a) ( islower(a) || isupper(a) || isdigit(a) || (a)=='-' || (a)=='_' )
-
-/* A amacro to test if a Frame is a SkyFrame, and is used to describe the
- sky (skyframes could be used for other purposes - eg a POLANAL Frame). */
-#define IsASkyFrame(frame) (astIsASkyFrame(frame)&&!strcmp("SKY",astGetDomain(frame)))
-
-/* Macro which takes a pointer to a FitsCard and returns non-zero if the
- card has been used and so should be ignored. */
-#define CARDUSED(card) ( \
- ( ignore_used == 2 && \
- ( (FitsCard *) (card) )->flags & PROVISIONALLY_USED ) || \
- ( ignore_used >= 1 && \
- ( (FitsCard *) (card) )->flags & USED ) )
-
-/* Set of characters used to encode a "sequence number" at the end of
- FITS keywords in an attempt to make them unique.. */
-#define SEQ_CHARS "_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-
-/* A general tolerance for equality between floating point values. */
-#define TOL1 10.0*DBL_EPSILON
-
-/* A tolerance for equality between angular values in radians. */
-#define TOL2 1.0E-10
-
-/* Macro to check for equality of floating point angular values. We cannot
- compare bad values directory because of the danger of floating point
- exceptions, so bad values are dealt with explicitly. The smallest
- significant angle is assumed to be 1E-9 radians (0.0002 arc-seconds).*/
-#define EQUALANG(aa,bb) (((aa)==AST__BAD)?(((bb)==AST__BAD)?1:0):(((bb)==AST__BAD)?0:(fabs((aa)-(bb))<=astMAX(1.0E5*(fabs(aa)+fabs(bb))*DBL_EPSILON,1.0E-9))))
-
-/* Macro to compare an angle in radians with zero, allowing some tolerance. */
-#define ZEROANG(aa) (fabs(aa)<1.0E-9)
-
-/* Constants: */
-#define UNKNOWN_ENCODING -1
-#define NATIVE_ENCODING 0
-#define FITSPC_ENCODING 1
-#define DSS_ENCODING 2
-#define FITSWCS_ENCODING 3
-#define FITSIRAF_ENCODING 4
-#define FITSAIPS_ENCODING 5
-#define FITSAIPSPP_ENCODING 6
-#define FITSCLASS_ENCODING 7
-#define MAX_ENCODING 7
-#define UNKNOWN_STRING "UNKNOWN"
-#define NATIVE_STRING "NATIVE"
-#define FITSPC_STRING "FITS-PC"
-#define FITSPC_STRING2 "FITS_PC"
-#define DSS_STRING "DSS"
-#define FITSWCS_STRING "FITS-WCS"
-#define FITSWCS_STRING2 "FITS_WCS"
-#define FITSIRAF_STRING "FITS-IRAF"
-#define FITSIRAF_STRING2 "FITS_IRAF"
-#define FITSAIPS_STRING "FITS-AIPS"
-#define FITSAIPS_STRING2 "FITS_AIPS"
-#define FITSAIPSPP_STRING "FITS-AIPS++"
-#define FITSAIPSPP_STRING2 "FITS_AIPS++"
-#define FITSCLASS_STRING "FITS-CLASS"
-#define FITSCLASS_STRING2 "FITS_CLASS"
-#define INDENT_INC 3
-#define PREVIOUS 0
-#define NEXT 1
-#define HEADER_TEXT "Beginning of AST data for "
-#define FOOTER_TEXT "End of AST data for "
-#define FITSNAMLEN 8
-#define FITSSTCOL 20
-#define FITSRLCOL 30
-#define FITSIMCOL 50
-#define FITSCOMCOL 32
-#define NORADEC 0
-#define FK4 1
-#define FK4NOE 2
-#define FK5 3
-#define GAPPT 4
-#define ICRS 5
-#define NOCEL 0
-#define RADEC 1
-#define ECLIP 2
-#define GALAC 3
-#define SUPER 4
-#define HECLIP 5
-#define AZEL 6
-#define LONAX -1
-#define NONAX 0
-#define LATAX 1
-#define NDESC 9
-#define MXCTYPELEN 81
-#define ALLWARNINGS " distortion noequinox noradesys nomjd-obs nolonpole nolatpole tnx zpx badcel noctype badlat badmat badval badctype badpv badkeyname badkeyvalue "
-#define NPFIT 10
-#define SPD 86400.0
-#define FL 1.0/298.257 /* Reference spheroid flattening factor */
-#define A0 6378140.0 /* Earth equatorial radius (metres) */
-
-/* String used to represent AST__BAD externally. */
-#define BAD_STRING "<bad>"
-
-/* Each card in the fitschan has a set of flags associated with it,
- stored in different bits of the "flags" item within each FitsCard
- structure (note, in AST V1.4 these flags were stored in the "del"
- item... Dump and LoadFitsChan will need to be changed to use a
- correspondingly changed name for the external representation of this
- item). The following flags are currently defined: */
-
-/* "USED" - This flag indicates that the the card has been used in the
- construction of an AST Object returned by astRead. Such cards should
- usually be treated as if they do not exist, i.e. they should not be
- used again by subsequent calls to astRead, they should not be recognised
- by public FitsChan methods which search the FitsChan for specified
- cards, and they should not be written out when the FitsChan is deleted.
- This flag was the only flag available in AST V1.4, and was called
- "Del" (for "deleted"). Used cards are retained in order to give an
- indication of where abouts within the header new cards should be placed
- when astWrite is called (i.e. new cards should usually be placed at
- the same point within the header as the cards which they replace). */
-#define USED 1
-
-/* "PROVISIONALLY_USED" - This flag indicates that the the card is being
- considered as a candidate for inclusion in the construction of an AST
- Object. If the Object is constructed succesfully, cards flagged as
- "provisionally used" will be changed to be flagged as "definitely used"
- (using the USED flag). If the Object fails to be constructed
- succesfully (if some required cards are missing from the FitsChan
- for instance), then "provisionally used" cards will be returned to the
- former state which they had prior to the attempt to construct the
- object. */
-#define PROVISIONALLY_USED 2
-
-/* "NEW" - This flag indicates that the the card has just been added to
- the FitsChan and may yet proove to be unrequired. For instance if the
- supplied Object is not of an appropriate flavour to be stored using
- the requested encoding, all "new" cards which were added before the
- inappropriateness was discovered will be removed from the FitsChan.
- Two different levels of "newness" are available. */
-#define NEW1 4
-#define NEW2 8
-
-/* "PROTECTED" - This flag indicates that the the card should not be
- removed form the FitsChan when an Object is read using astRead. If
- this flag is not set, then the card will dehave as if it has been
- deleted if it was used in the construction of the returned AST Object. */
-#define PROTECTED 16
-
-/* Include files. */
-/* ============== */
-
-/* Interface definitions. */
-/* ---------------------- */
-#include "channel.h"
-#include "cmpframe.h"
-#include "cmpmap.h"
-#include "dssmap.h"
-#include "error.h"
-#include "fitschan.h"
-#include "frame.h"
-#include "frameset.h"
-#include "grismmap.h"
-#include "lutmap.h"
-#include "mathmap.h"
-#include "matrixmap.h"
-#include "memory.h"
-#include "object.h"
-#include "permmap.h"
-#include "pointset.h"
-#include "shiftmap.h"
-#include "skyframe.h"
-#include "timeframe.h"
-#include "keymap.h"
-#include "pal.h"
-#include "erfa.h"
-#include "slamap.h"
-#include "specframe.h"
-#include "dsbspecframe.h"
-#include "specmap.h"
-#include "sphmap.h"
-#include "unit.h"
-#include "unitmap.h"
-#include "polymap.h"
-#include "wcsmap.h"
-#include "winmap.h"
-#include "zoommap.h"
-#include "globals.h"
-#include "fitstable.h"
-
-/* Error code definitions. */
-/* ----------------------- */
-#include "ast_err.h" /* AST error codes */
-
-/* C header files. */
-/* --------------- */
-#include <ctype.h>
-#include <float.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <errno.h>
-
-/* Type Definitions */
-/* ================ */
-
-/* This structure contains information describing a single FITS header card
- in a circular list of such structures. */
-typedef struct FitsCard {
- char name[ FITSNAMLEN + 1 ];/* Keyword name (plus terminating null). */
- int type; /* Data type. */
- void *data; /* Pointer to the keyword's data value. */
- char *comment; /* Pointer to a comment for the keyword. */
- int flags; /* Flags for each card */
- size_t size; /* Size of data value */
- struct FitsCard *next; /* Pointer to next structure in list. */
- struct FitsCard *prev; /* Pointer to previous structure in list. */
-} FitsCard;
-
-/* Structure used to store information derived from the FITS WCS keyword
- values in a form more convenient to further processing. Conventions
- for units, etc, for values in a FitsStore follow FITS-WCS (e.g. angular
- values are stored in degrees, equinox is B or J depending on RADECSYS,
- etc). */
-typedef struct FitsStore {
- char ****cname;
- char ****ctype;
- char ****ctype_com;
- char ****cunit;
- char ****radesys;
- char ****wcsname;
- char ****specsys;
- char ****ssyssrc;
- char ****ps;
- char ****timesys;
- double ***pc;
- double ***cdelt;
- double ***crpix;
- double ***crval;
- double ***equinox;
- double ***latpole;
- double ***lonpole;
- double ***mjdobs;
- double ***dut1;
- double ***mjdavg;
- double ***pv;
- double ***wcsaxes;
- double ***obsgeox;
- double ***obsgeoy;
- double ***obsgeoz;
- double ***restfrq;
- double ***restwav;
- double ***zsource;
- double ***velosys;
- double ***asip;
- double ***bsip;
- double ***apsip;
- double ***bpsip;
- double ***imagfreq;
- double ***axref;
- int naxis;
- AstKeyMap *tables;
- double ***skyref;
- double ***skyrefp;
- char ****skyrefis;
-} FitsStore;
-
-/* 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 void (* parent_setsourcefile)( AstChannel *, const char *, int * );
-static int (* parent_getobjsize)( AstObject *, int * );
-static const char *(* parent_getattrib)( AstObject *, const char *, int * );
-static int (* parent_getfull)( AstChannel *, int * );
-static int (* parent_getskip)( AstChannel *, 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_write)( AstChannel *, AstObject *, int * );
-static AstObject *(* parent_read)( AstChannel *, int * );
-#if defined(THREAD_SAFE)
-static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
-#endif
-
-/* Strings to describe each data type. These should be in the order implied
- by the corresponding macros (eg AST__FLOAT, etc). */
-static const char *type_names[9] = {"comment", "integer", "floating point",
- "string", "complex floating point",
- "complex integer", "logical",
- "continuation string", "undef" };
-
-/* Text values used to represent Encoding values externally. */
-
-static const char *xencod[8] = { NATIVE_STRING, FITSPC_STRING,
- DSS_STRING, FITSWCS_STRING,
- FITSIRAF_STRING, FITSAIPS_STRING,
- FITSAIPSPP_STRING, FITSCLASS_STRING };
-/* Define two variables to hold TimeFrames which will be used for converting
- MJD values between time scales. */
-static AstTimeFrame *tdbframe = NULL;
-static AstTimeFrame *timeframe = NULL;
-
-/* Max number of characters in a formatted int */
-static int int_dig;
-
-/* 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->Items_Written = 0; \
- globals->Write_Nest = -1; \
- globals->Current_Indent = 0; \
- globals->Ignore_Used = 1; \
- globals->Mark_New = 0; \
- globals->CnvType_Text[ 0 ] = 0; \
- globals->CnvType_Text0[ 0 ] = 0; \
- globals->CnvType_Text1[ 0 ] = 0; \
- globals->CreateKeyword_Seq_Nchars = -1; \
- globals->FormatKey_Buff[ 0 ] = 0; \
- globals->FitsGetCom_Sval[ 0 ] = 0; \
- globals->IsSpectral_Ret = NULL; \
- globals->Match_Fmt[ 0 ] = 0; \
- globals->Match_Template = NULL; \
- globals->Match_PA = 0; \
- globals->Match_PB = 0; \
- globals->Match_NA = 0; \
- globals->Match_NB = 0; \
- globals->Match_Nentry = 0; \
- globals->WcsCelestial_Type[ 0 ] = 0; \
- globals->Ignore_Used = 1; \
- globals->Mark_New = 0;
-
-/* Create the function that initialises global data for this module. */
-astMAKE_INITGLOBALS(FitsChan)
-
-/* Define macros for accessing each item of thread specific global data. */
-#define class_init astGLOBAL(FitsChan,Class_Init)
-#define class_vtab astGLOBAL(FitsChan,Class_Vtab)
-#define getattrib_buff astGLOBAL(FitsChan,GetAttrib_Buff)
-#define items_written astGLOBAL(FitsChan,Items_Written)
-#define write_nest astGLOBAL(FitsChan,Write_Nest)
-#define current_indent astGLOBAL(FitsChan,Current_Indent)
-#define ignore_used astGLOBAL(FitsChan,Ignore_Used)
-#define mark_new astGLOBAL(FitsChan,Mark_New)
-#define cnvtype_text astGLOBAL(FitsChan,CnvType_Text)
-#define cnvtype_text0 astGLOBAL(FitsChan,CnvType_Text0)
-#define cnvtype_text1 astGLOBAL(FitsChan,CnvType_Text1)
-#define createkeyword_seq_nchars astGLOBAL(FitsChan,CreateKeyword_Seq_Nchars)
-#define formatkey_buff astGLOBAL(FitsChan,FormatKey_Buff)
-#define fitsgetcom_sval astGLOBAL(FitsChan,FitsGetCom_Sval)
-#define isspectral_ret astGLOBAL(FitsChan,IsSpectral_Ret)
-#define match_fmt astGLOBAL(FitsChan,Match_Fmt)
-#define match_template astGLOBAL(FitsChan,Match_Template)
-#define match_pa astGLOBAL(FitsChan,Match_PA)
-#define match_pb astGLOBAL(FitsChan,Match_PB)
-#define match_na astGLOBAL(FitsChan,Match_NA)
-#define match_nb astGLOBAL(FitsChan,Match_NB)
-#define match_nentry astGLOBAL(FitsChan,Match_Nentry)
-#define wcscelestial_type astGLOBAL(FitsChan,WcsCelestial_Type)
-static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
-#define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 );
-#define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 );
-static pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
-#define LOCK_MUTEX3 pthread_mutex_lock( &mutex3 );
-#define UNLOCK_MUTEX3 pthread_mutex_unlock( &mutex3 );
-static pthread_mutex_t mutex4 = PTHREAD_MUTEX_INITIALIZER;
-#define LOCK_MUTEX4 pthread_mutex_lock( &mutex4 );
-#define UNLOCK_MUTEX4 pthread_mutex_unlock( &mutex4 );
-
-/* If thread safety is not needed, declare and initialise globals at static
- variables. */
-#else
-
-/* Buffer returned by GetAttrib. */
-static char getattrib_buff[ AST__FITSCHAN_GETATTRIB_BUFF_LEN + 1 ];
-
-/* Buffer for returned text string in CnvType */
-static char cnvtype_text[ AST__FITSCHAN_FITSCARDLEN + 1 ];
-
-/* Buffer for real value in CnvType */
-static char cnvtype_text0[ AST__FITSCHAN_FITSCARDLEN + 1 ];
-
-/* Buffer for imaginary value in CnvType */
-static char cnvtype_text1[ AST__FITSCHAN_FITSCARDLEN + 1 ];
-
-/* Number of output items written since the last "Begin" or "IsA"
- output item, and level of Object nesting during recursive
- invocation of the astWrite method. */
-static int items_written = 0;
-static int write_nest = -1;
-
-/* Indentation level for indented comments when writing Objects to a
- FitsChan. */
-static int current_indent = 0;
-
-/* Ignore_Used: If 2, then cards which have been marked as either "definitely
- used" or "provisionally used" (see the USED flag above) will be ignored
- when searching the FitsChan, etc (i.e. they will be treated as if they
- have been removed from the FitsChan). If 1, then cards which have been
- "definitely used" will be skipped over. If zero then no cards will be
- skipped over. */
-static int ignore_used = 1;
-
-/* Mark_New: If non-zero, then all cards added to the FitsChan will be
- marked with both the NEW1 and NEW2 flags (see above). If zero then
- new cards will not be marked with either NEW1 or NEW2. */
-static int mark_new = 0;
-
-/* Number of characters used for encoding */
-static int createkeyword_seq_nchars = -1;
-
-/* Buffer for value returned by FormatKey */
-static char formatkey_buff[ 10 ];
-
-/* Buffer for value returned by FitsGetCom */
-static char fitsgetcom_sval[ AST__FITSCHAN_FITSCARDLEN + 1 ];
-
-/* Pointer returned by IsSpectral */
-static const char *isspectral_ret = NULL;
-
-/* Format specifier for reading an integer field in Match */
-static char match_fmt[ 10 ];
-
-/* Pointer to start of template in Match */
-static const char *match_template = NULL;
-
-/* Pointer to first returned field value in Match */
-static int *match_pa = 0;
-
-/* Pointer to last returned field value in Match */
-static int *match_pb = 0;
-
-/* No. of characters read from the test string in Match */
-static int match_na = 0;
-
-/* No. of characters read from the template string in Match */
-static int match_nb = 0;
-
-/* Number of recursive entries into Match */
-static int match_nentry = 0;
-
-/* Buffer for celestial system in WcsCelestial */
-static char wcscelestial_type[ 4 ];
-
-/* Define the class virtual function table and its initialisation flag
- as static variables. */
-static AstFitsChanVtab class_vtab; /* Virtual function table */
-static int class_init = 0; /* Virtual function table initialised? */
-#define LOCK_MUTEX2
-#define UNLOCK_MUTEX2
-#define LOCK_MUTEX3
-#define UNLOCK_MUTEX3
-#define LOCK_MUTEX4
-#define UNLOCK_MUTEX4
-#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. */
-AstFitsChan *astFitsChanForId_( const char *(*)( void ),
- char *(*)( const char *(*)( void ), int * ),
- void (*)( const char * ),
- void (*)( void (*)( const char * ), const char *, int * ),
- const char *, ... );
-AstFitsChan *astFitsChanId_( const char *(* source)( void ),
- void (* sink)( const char * ),
- const char *options, ... );
-
-/* Prototypes for Private Member Functions. */
-/* ======================================== */
-static int GetObjSize( AstObject *, int * );
-static void ClearCard( AstFitsChan *, int * );
-static int GetCard( AstFitsChan *, int * );
-static int TestCard( AstFitsChan *, int * );
-static void SetCard( AstFitsChan *, int, int * );
-static void ClearEncoding( AstFitsChan *, int * );
-static int GetEncoding( AstFitsChan *, int * );
-static int TestEncoding( AstFitsChan *, int * );
-static void SetEncoding( AstFitsChan *, int, int * );
-static void ClearCDMatrix( AstFitsChan *, int * );
-static int GetCDMatrix( AstFitsChan *, int * );
-static int TestCDMatrix( AstFitsChan *, int * );
-static void SetCDMatrix( AstFitsChan *, int, int * );
-static void ClearFitsDigits( AstFitsChan *, int * );
-static int GetFitsDigits( AstFitsChan *, int * );
-static int TestFitsDigits( AstFitsChan *, int * );
-static void SetFitsDigits( AstFitsChan *, int, int * );
-static void ClearFitsAxisOrder( AstFitsChan *, int * );
-static const char *GetFitsAxisOrder( AstFitsChan *, int * );
-static int TestFitsAxisOrder( AstFitsChan *, int * );
-static void SetFitsAxisOrder( AstFitsChan *, const char *, int * );
-static void ClearDefB1950( AstFitsChan *, int * );
-static int GetDefB1950( AstFitsChan *, int * );
-static int TestDefB1950( AstFitsChan *, int * );
-static void SetDefB1950( AstFitsChan *, int, int * );
-static void ClearTabOK( AstFitsChan *, int * );
-static int GetTabOK( AstFitsChan *, int * );
-static int TestTabOK( AstFitsChan *, int * );
-static void SetTabOK( AstFitsChan *, int, int * );
-static void ClearCarLin( AstFitsChan *, int * );
-static int GetCarLin( AstFitsChan *, int * );
-static int TestCarLin( AstFitsChan *, int * );
-static void SetCarLin( AstFitsChan *, int, int * );
-static void ClearPolyTan( AstFitsChan *, int * );
-static int GetPolyTan( AstFitsChan *, int * );
-static int TestPolyTan( AstFitsChan *, int * );
-static void SetPolyTan( AstFitsChan *, int, int * );
-static void ClearIwc( AstFitsChan *, int * );
-static int GetIwc( AstFitsChan *, int * );
-static int TestIwc( AstFitsChan *, int * );
-static void SetIwc( AstFitsChan *, int, int * );
-static void ClearClean( AstFitsChan *, int * );
-static int GetClean( AstFitsChan *, int * );
-static int TestClean( AstFitsChan *, int * );
-static void SetClean( AstFitsChan *, int, int * );
-static void ClearWarnings( AstFitsChan *, int * );
-static const char *GetWarnings( AstFitsChan *, int * );
-static int TestWarnings( AstFitsChan *, int * );
-static void SetWarnings( AstFitsChan *, const char *, int * );
-
-static AstFitsChan *SpecTrans( AstFitsChan *, int, const char *, const char *, int * );
-static AstFitsTable *GetNamedTable( AstFitsChan *, const char *, int, int, int, const char *, int * );
-static AstFrameSet *MakeFitsFrameSet( AstFitsChan *, AstFrameSet *, int, int, int, const char *, const char *, int * );
-static AstGrismMap *ExtractGrismMap( AstMapping *, int, AstMapping **, int * );
-static AstKeyMap *GetTables( AstFitsChan *, int * );
-static AstMapping *AddUnitMaps( AstMapping *, int, int, int * );
-static AstMapping *CelestialAxes( AstFitsChan *this, AstFrameSet *, double *, int *, char, FitsStore *, int *, int, const char *, const char *, int * );
-static AstMapping *GrismSpecWcs( char *, FitsStore *, int, char, AstSpecFrame *, const char *, const char *, int * );
-static AstMapping *IsMapTab1D( AstMapping *, double, const char *, AstFrame *, double *, int, int, AstFitsTable **, int *, int *, int *, int * );
-static AstMapping *IsMapTab2D( AstMapping *, double, const char *, AstFrame *, double *, int, int, int, int, AstFitsTable **, int *, int *, int *, int *, int *, int *, int *, int *, int * );
-static AstMapping *LinearWcs( FitsStore *, int, char, const char *, const char *, int * );
-static AstMapping *LogAxis( AstMapping *, int, int, double *, double *, double, int * );
-static AstMapping *LogWcs( FitsStore *, int, char, const char *, const char *, int * );
-static AstMapping *MakeColumnMap( AstFitsTable *, const char *, int, int, const char *, const char *, int * );
-static AstMapping *NonLinSpecWcs( AstFitsChan *, char *, FitsStore *, int, char, AstSpecFrame *, const char *, const char *, int * );
-static AstMapping *OtherAxes( AstFitsChan *, AstFrameSet *, double *, int *, char, FitsStore *, double *, int *, const char *, const char *, int * );
-static AstMapping *SIPMapping( double *, FitsStore *, char, int, const char *, const char *, int * );
-static AstMapping *SpectralAxes( AstFitsChan *, AstFrameSet *, double *, int *, char, FitsStore *, double *, int *, const char *, const char *, int * );
-static AstMapping *TabMapping( AstFitsChan *, FitsStore *, char, int **, const char *, const char *, int *);
-static AstMapping *WcsCelestial( AstFitsChan *, FitsStore *, char, AstFrame **, AstFrame *, double *, double *, AstSkyFrame **, AstMapping **, int *, const char *, const char *, int * );
-static AstMapping *WcsIntWorld( AstFitsChan *, FitsStore *, char, int, const char *, const char *, int * );
-static AstMapping *WcsMapFrm( AstFitsChan *, FitsStore *, char, AstFrame **, const char *, const char *, int * );
-static AstMapping *WcsNative( AstFitsChan *, FitsStore *, char, AstWcsMap *, int, int, const char *, const char *, int * );
-static AstMapping *WcsOthers( AstFitsChan *, FitsStore *, char, AstFrame **, AstFrame *, const char *, const char *, int * );
-static AstMapping *WcsSpectral( AstFitsChan *, FitsStore *, char, AstFrame **, AstFrame *, double, double, AstSkyFrame *, const char *, const char *, int * );
-static AstMapping *ZPXMapping( AstFitsChan *, FitsStore *, char, int, int[2], const char *, const char *, int * );
-static AstMatrixMap *WcsCDeltMatrix( FitsStore *, char, int, const char *, const char *, int * );
-static AstMatrixMap *WcsPCMatrix( FitsStore *, char, int, const char *, const char *, int * );
-static AstObject *FsetFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static AstObject *Read( AstChannel *, int * );
-static AstSkyFrame *WcsSkyFrame( AstFitsChan *, FitsStore *, char, int, char *, int, int, const char *, const char *, int * );
-static AstTimeScaleType TimeSysToAst( AstFitsChan *, const char *, const char *, const char *, int * );
-static AstWinMap *WcsShift( FitsStore *, char, int, const char *, const char *, int * );
-static FitsCard *GetLink( FitsCard *, int, const char *, const char *, int * );
-static FitsStore *FitsToStore( AstFitsChan *, int, const char *, const char *, int * );
-static FitsStore *FreeStore( FitsStore *, int * );
-static FitsStore *FsetToStore( AstFitsChan *, AstFrameSet *, int, double *, int, const char *, const char *, int * );
-static char *CardComm( AstFitsChan *, int * );
-static char *CardName( AstFitsChan *, int * );
-static char *ConcatWAT( AstFitsChan *, int, const char *, const char *, int * );
-static char *FormatKey( const char *, int, int, char, int * );
-static char *GetItemC( char *****, int, int, char, char *, const char *method, const char *class, int * );
-static char *SourceWrap( const char *(*)( void ), int * );
-static char *UnPreQuote( const char *, int * );
-static char GetMaxS( double ****item, int * );
-static const char *GetAllWarnings( AstFitsChan *, int * );
-static const char *GetAttrib( AstObject *, const char *, int * );
-static const char *GetCardComm( AstFitsChan *, int * );
-static const char *GetCardName( AstFitsChan *, int * );
-static const char *GetFitsSor( const char *, int * );
-static const char *IsSpectral( const char *, char[5], char[5], int * );
-static double **OrthVectorSet( int, int, double **, int * );
-static double *Cheb2Poly( double *, int, int, double, double, double, double, int * );
-static double *FitLine( AstMapping *, double *, double *, double *, double, double *, int * );
-static double *OrthVector( int, int, double **, int * );
-static double *ReadCrval( AstFitsChan *, AstFrame *, char, const char *, const char *, int * );
-static double ChooseEpoch( AstFitsChan *, FitsStore *, char, const char *, const char *, int * );
-static double DateObs( const char *, int * );
-static double GetItem( double ****, int, int, char, char *, const char *method, const char *class, int * );
-static double NearestPix( AstMapping *, double, int, int * );
-static double TDBConv( double, int, int, const char *, const char *, int * );
-static int *CardFlags( AstFitsChan *, int * );
-static int AIPSFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static int AIPSPPFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static int AddEncodingFrame( AstFitsChan *, AstFrameSet *, int, const char *, const char *, int * );
-static int AddVersion( AstFitsChan *, AstFrameSet *, int, int, FitsStore *, double *, char, int, int, const char *, const char *, int * );
-static int CLASSFromStore( AstFitsChan *, FitsStore *, AstFrameSet *, double *, const char *, const char *, int * );
-static int CardType( AstFitsChan *, int * );
-static int CheckFitsName( AstFitsChan *, const char *, const char *, const char *, int * );
-static int ChrLen( const char *, int * );
-static int CnvType( int, void *, size_t, int, int, void *, const char *, const char *, const char *, int * );
-static int CnvValue( AstFitsChan *, int , int, void *, const char *, int * );
-static int ComBlock( AstFitsChan *, int, const char *, const char *, int * );
-static int CountFields( const char *, char, const char *, const char *, int * );
-static int DSSFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static int EncodeFloat( char *, int, int, int, double, int * );
-static int EncodeValue( AstFitsChan *, char *, int, int, const char *, int * );
-static int FindBasisVectors( AstMapping *, int, int, double *, AstPointSet *, AstPointSet *, int * );
-static int FindFits( AstFitsChan *, const char *, char[ AST__FITSCHAN_FITSCARDLEN + 1 ], int, int * );
-static int FindKeyCard( AstFitsChan *, const char *, const char *, const char *, int * );
-static int FindLonLatSpecAxes( FitsStore *, char, int *, int *, int *, const char *, const char *, int * );
-static int FindString( int, const char *[], const char *, const char *, const char *, const char *, int * );
-static int FitOK( int, double *, double *, double, int * );
-static int FitsAxisOrder( AstFitsChan *this, int nwcs, AstFrame *wcsfrm, int *perm, int *status );
-static int FitsEof( AstFitsChan *, int * );
-static int FitsFromStore( AstFitsChan *, FitsStore *, int, double *, AstFrameSet *, const char *, const char *, int * );
-static int FitsGetCom( AstFitsChan *, const char *, char **, int * );
-static int FitsSof( AstFitsChan *, int * );
-static int FullForm( const char *, const char *, int, int * );
-static int GetCardType( AstFitsChan *, int * );
-static int GetFiducialWCS( AstWcsMap *, AstMapping *, int, int, double *, double *, int * );
-static int GetFitsCF( AstFitsChan *, const char *, double *, int * );
-static int GetFitsCI( AstFitsChan *, const char *, int *, int * );
-static int GetFitsCN( AstFitsChan *, const char *, char **, int * );
-static int GetFitsF( AstFitsChan *, const char *, double *, int * );
-static int GetFitsI( AstFitsChan *, const char *, int *, int * );
-static int GetFitsL( AstFitsChan *, const char *, int *, int * );
-static int GetFitsS( AstFitsChan *, const char *, char **, int * );
-static int GetFull( AstChannel *, int * );
-static int GetMaxI( double ****item, char, int * );
-static int GetMaxJM( double ****item, char, int * );
-static int GetMaxJMC( char *****item, char, int * );
-static int GetNcard( AstFitsChan *, int * );
-static int GetNkey( AstFitsChan *, int * );
-static int GetSkip( AstChannel *, int * );
-static int GetUsedPolyTan( AstFitsChan *, AstFitsChan *, int, int, char, const char *, const char *, int * );
-static int GetValue( AstFitsChan *, const char *, int, void *, int, int, const char *, const char *, int * );
-static int GetValue2( AstFitsChan *, AstFitsChan *, const char *, int, void *, int, const char *, const char *, int * );
-static int GoodWarns( const char *, int * );
-static int HasAIPSSpecAxis( AstFitsChan *, const char *, const char *, int * );
-static int HasCard( AstFitsChan *, const char *, const char *, const char *, int * );
-static int IRAFFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static int IsAIPSSpectral( const char *, char **, char **, int * );
-static int IsMapLinear( AstMapping *, const double [], const double [], int, int * );
-static int IsSkyOff( AstFrameSet *, int, int * );
-static int KeyFields( AstFitsChan *, const char *, int, int *, int *, int * );
-static int LooksLikeClass( AstFitsChan *, const char *, const char *, int * );
-static int MakeBasisVectors( AstMapping *, int, int, double *, AstPointSet *, AstPointSet *, int * );
-static int MakeIntWorld( AstMapping *, AstFrame *, int *, char, FitsStore *, double *, const char *, const char *, int * );
-static int Match( const char *, const char *, int, int *, int *, const char *, const char *, int * );
-static int MatchChar( char, char, const char *, const char *, const char *, int * );
-static int MatchFront( const char *, const char *, char *, int *, int *, int *, const char *, const char *, const char *, int * );
-static int MoveCard( AstFitsChan *, int, const char *, const char *, int * );
-static int PCFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static int SAOTrans( AstFitsChan *, AstFitsChan *, const char *, const char *, int * );
-static int SearchCard( AstFitsChan *, const char *, const char *, const char *, int * );
-static int SetFits( AstFitsChan *, const char *, void *, int, const char *, int, int * );
-static int Similar( const char *, const char *, int * );
-static int SkySys( AstFitsChan *, AstSkyFrame *, int, int, FitsStore *, int, int, char c, int, const char *, const char *, int * );
-static int Split( AstFitsChan *, const char *, char **, char **, char **, const char *, const char *, int * );
-static int SplitMap( AstMapping *, int, int, int, AstMapping **, AstWcsMap **, AstMapping **, int * );
-static int SplitMap2( AstMapping *, int, AstMapping **, AstWcsMap **, AstMapping **, int * );
-static int SplitMat( int , double *, double *, int * );
-static int TestAttrib( AstObject *, const char *, int * );
-static int TestFits( AstFitsChan *, const char *, int *, int * );
-static int Use( AstFitsChan *, int, int, int * );
-static int Ustrcmp( const char *, const char *, int * );
-static int Ustrncmp( const char *, const char *, size_t, int * );
-static int WATCoeffs( const char *, int, double **, int **, int *, int * );
-static int WcsFromStore( AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static int WcsNatPole( AstFitsChan *, AstWcsMap *, double, double, double, double *, double *, double *, int * );
-static int WorldAxes( AstFitsChan *this, AstMapping *, double *, int *, int * );
-static int Write( AstChannel *, AstObject *, int * );
-static void *CardData( AstFitsChan *, size_t *, int * );
-static void AdaptLut( AstMapping *, int, double, double, double, double, double, double **, double **, int *, int * );
-static void AddFrame( AstFitsChan *, AstFrameSet *, int, int, FitsStore *, char, const char *, const char *, int * );
-static void ChangePermSplit( AstMapping *, int * );
-static void CheckZero( char *, double, int, int * );
-static void Chpc1( double *, double *, int, int *, int *, int * );
-static void ClassTrans( AstFitsChan *, AstFitsChan *, int, int, const char *, const char *, int * );
-static void ClearAttrib( AstObject *, const char *, int * );
-static void Copy( const AstObject *, AstObject *, int * );
-static void CreateKeyword( AstFitsChan *, const char *, char [ FITSNAMLEN + 1 ], int * );
-static void DSBSetUp( AstFitsChan *, FitsStore *, AstDSBSpecFrame *, char, double, const char *, const char *, int * );
-static void DSSToStore( AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static void DelFits( AstFitsChan *, int * );
-static void Delete( AstObject *, int * );
-static void DeleteCard( AstFitsChan *, const char *, const char *, int * );
-static void DistortMaps( AstFitsChan *, FitsStore *, char, int , AstMapping **, AstMapping **, AstMapping **, AstMapping **, const char *, const char *, int * );
-static void Dump( AstObject *, AstChannel *, int * );
-static void EmptyFits( AstFitsChan *, int * );
-static void FindWcs( AstFitsChan *, int, int, int, const char *, const char *, int * );
-static void FixNew( AstFitsChan *, int, int, const char *, const char *, int * );
-static void FixUsed( AstFitsChan *, int, int, int, const char *, const char *, int * );
-static void FormatCard( AstFitsChan *, char *, const char *, int * );
-static void FreeItem( double ****, int * );
-static void FreeItemC( char *****, int * );
-static void GetFiducialNSC( AstWcsMap *, double *, double *, int * );
-static void GetFiducialPPC( AstWcsMap *, double *, double *, int * );
-static void GetNextData( AstChannel *, int, char **, char **, int * );
-static void InsCard( AstFitsChan *, int, const char *, int, void *, const char *, const char *, const char *, int * );
-static void MakeBanner( const char *, const char *, const char *, char [ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ], int * );
-static void MakeIndentedComment( int, char, const char *, const char *, char [ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1], int * );
-static void MakeIntoComment( AstFitsChan *, const char *, const char *, int * );
-static void MakeInvertable( double **, int, double *, int * );
-static void MarkCard( AstFitsChan *, int * );
-static void NewCard( AstFitsChan *, const char *, int, const void *, const char *, int, int * );
-static void PreQuote( const char *, char [ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ], int * );
-static void PurgeWCS( AstFitsChan *, int * );
-static void PutCards( AstFitsChan *, const char *, int * );
-static void PutFits( AstFitsChan *, const char [ AST__FITSCHAN_FITSCARDLEN + 1 ], int, int * );
-static void PutTable( AstFitsChan *, AstFitsTable *, const char *, int * );
-static void PutTables( AstFitsChan *, AstKeyMap *, int * );
-static void ReadFits( AstFitsChan *, int * );
-static void ReadFromSource( AstFitsChan *, int * );
-static void RemoveTables( AstFitsChan *, const char *, int * );
-static void RetainFits( AstFitsChan *, int * );
-static void RoundFString( char *, int, int * );
-static void SetAlgCode( char *, const char *, int * );
-static void SetAttrib( AstObject *, const char *, int * );
-static void SetFitsCF( AstFitsChan *, const char *, double *, const char *, int, int * );
-static void SetFitsCI( AstFitsChan *, const char *, int *, const char *, int, int * );
-static void SetFitsCM( AstFitsChan *, const char *, int, int * );
-static void SetFitsCN( AstFitsChan *, const char *, const char *, const char *, int, int * );
-static void SetFitsCom( AstFitsChan *, const char *, const char *, int, int * );
-static void SetFitsF( AstFitsChan *, const char *, double, const char *, int, int * );
-static void SetFitsI( AstFitsChan *, const char *, int, const char *, int, int * );
-static void SetFitsL( AstFitsChan *, const char *, int, const char *, int, int * );
-static void SetFitsS( AstFitsChan *, const char *, const char *, const char *, int, int * );
-static void SetFitsU( AstFitsChan *, const char *, const char *, int, int * );
-static void SetItem( double ****, int, int, char, double, int * );
-static void SetItemC( char *****, int, int, char, const char *, int * );
-static void SetSourceFile( AstChannel *, const char *, int * );
-static void SetValue( AstFitsChan *, const char *, void *, int, const char *, int * );
-static void ShowFits( AstFitsChan *, int * );
-static void Shpc1( double, double, int, double *, double *, int * );
-static void SinkWrap( void (*)( const char * ), const char *, int * );
-static void SkyPole( AstWcsMap *, AstMapping *, int, int, int *, char, FitsStore *, const char *, const char *, int * );
-static void TableSource( AstFitsChan *, void (*)( AstFitsChan *, const char *, int, int, int * ), int * );
-static void TidyOffsets( AstFrameSet *, int * );
-static void Warn( AstFitsChan *, const char *, const char *, const char *, const char *, int * );
-static void WcsFcRead( AstFitsChan *, AstFitsChan *, FitsStore *, const char *, const char *, int * );
-static void WcsToStore( AstFitsChan *, AstFitsChan *, FitsStore *, 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 WriteFits( AstFitsChan *, 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 void WriteToSink( AstFitsChan *, int * );
-static void SetTableSource( AstFitsChan *,
- void (*)( void ),
- void (*)( void (*)( void ),
- AstFitsChan *, const char *, int, int, int * ), int * );
-static void TabSourceWrap( void (*)( void ),
- AstFitsChan *, const char *, int, int, int * );
-#if defined(THREAD_SAFE)
-static int ManageLock( AstObject *, int, int, AstObject **, int * );
-#endif
-
-/* Member functions. */
-/* ================= */
-
-static void AdaptLut( AstMapping *map, int npos, double eps, double x0,
- double x1, double v0, double v1, double **xtab,
- double **vtab, int *nsamp, int *status ){
-/*
-* Name:
-* AdaptLut
-
-* Purpose:
-* Create a table of optimally sampled values for a Mapping.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void AdaptLut( AstMapping *map, int npos, double eps, double x0,
-* double x1, double v0, double v1, double **xtab,
-* double **vtab, int *nsamp, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function returns a look-up table holding samples of the supplied
-* 1D mapping. The input values at which the samples are taken are
-* returned in the "xtab" array, and the Mapping output values at
-* these input values are returned in the "vtab" array. The sample
-* spacing is smaller at positions where the output gradient is
-* changing more rapidly (i.e. where the output is more non-linear).
-
-* Parameters:
-* map
-* Pointer to the Mapping. Should have 1 input and 1 output.
-* npos
-* The minimum number of samples to place within the interval to be
-* sampled, excluding the two end points (which are always sampeld
-* anyway). These samples are placed evenly through the [x0,x1]
- interval. The interval between adjacent samples will be further
-* subdivided if necessary by calling this function recursively.
-* eps
-* The maximum error in X (i.e. the Mapping input) allowed before
-* the supplied interval is subdivided further by a recursive call
-* to this function.
-* x0
-* The Mapping input value at the start of the interval to be sampled.
-* It is assumed that this value is already stored in (*xtab)[0] on
-* entry.
-* x1
-* The Mapping input value at the end of the interval to be sampled.
-* v0
-* The Mapping output value at the start of the interval to be sampled.
-* It is assumed that this value is already stored in (*vtab)[0] on
-* entry.
-* v1
-* The Mapping output value at the end of the interval to be sampled.
-* xtab
-* Address of a pointer to the array in which to store the Mapping
-* input values at which samples were taken. The supplied pointer
-* may be changed on exit to point to a larger array. New values
-* are added to the end of this array. The initial size of the array
-* is given by the supplied value for "*nsamp"
-* vtab
-* Address of a pointer to the array in which to store the Mapping
-* output value at each sample. The supplied pointer may be changed
-* on exit to point to a larger array. New values are added to the
-* end of this array. The initial size of the array is given by the
-* supplied value for "*nsamp".
-* nsamp
-* Address of an int holding the number of values in the "*xtab"
-* and "*ytab" arrays. Updated on exit to include the new values
-* added to the arrays by this function.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The size of the returned xtab and vtab arrays.
-*/
-
-/* Local Variables: */
- double *vv; /* Pointer to Mapping output values */
- double *xx; /* Pointer to Mapping input values */
- double dx; /* Step between sample positions */
- double rg; /* Reciprocal of gradient of (x0,v0)->(x1,v1) line */
- double xx0; /* X at first new sample position */
- int ipos; /* Interior sample index */
- int isamp; /* Index into extended xtab and vtab arrays. */
- int subdivide; /* Subdivide each subinterval? */
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* Allocate work space. */
- xx = astMalloc( sizeof( double )*npos );
- vv = astMalloc( sizeof( double )*npos );
- if( astOK ) {
-
-/* Set up the evenly spaced interior sample positions. */
- dx = ( x1 - x0 )/( npos + 1 );
- xx0 = x0 + dx;
- for( ipos = 0; ipos < npos; ipos++ ) {
- xx[ ipos ] = xx0 + ipos*dx;
- }
-
-/* Find the Mapping output values at these input values. */
- astTran1( map, npos, xx, 1, vv );
-
-/* See if any of these samples deviate significantly from the straight line
- defined by (x0,v0) and (x1,v1). If any such sample is found, we call
- this function recursively to sample the subdivided intervals. First
- handle cases where the straight line has zero gradient. */
- subdivide = 0;
- if( v0 == v1 ) {
-
-/* Subdivide if any of the interior sample values are different to the
- end values. */
- for( ipos = 0; ipos < npos; ipos++ ) {
- if( vv[ ipos ] != v0 ) {
- subdivide = 1;
- break;
- }
- }
-
-/* Now handle cases where the line has non-zero gradient. Subdivide if any
- of the interior sample input positions are further than "eps" from the
- input position that would give the same output value if the mapping was
- linear. */
- } else {
- rg = ( x1 - x0 )/( v1 - v0 );
- for( ipos = 0; ipos < npos; ipos++ ) {
- if( vv[ ipos ] == AST__BAD ||
- fabs( rg*( vv[ ipos ] - v0 ) - ( xx[ ipos ] - x0 ) ) > eps ) {
- subdivide = 1;
- break;
- }
- }
- }
-
-/* If required, call this function recursively to subdivide each section
- of the supplied input interval, and append samples to the returned
- arrays. */
- if( subdivide ) {
-
-/* Do each sub-interval, except the last one. The number of subintervals
- is one more than the number of interior samples. */
- for( ipos = 0; ipos < npos; ipos++ ) {
-
-/* Append samples covering the current subinterval to the ends of the
- arrays. */
- AdaptLut( map, npos, eps, x0, xx[ ipos ], v0, vv[ ipos ],
- xtab, vtab, nsamp, status );
-
-/* Store the starting position for the next sub-interval. */
- x0 = xx[ ipos ];
- v0 = vv[ ipos ];
- }
-
-/* Now do the final sub-interval. */
- AdaptLut( map, npos, eps, x0, x1, v0, v1, xtab, vtab, nsamp, status );
-
-/* If we do not need to subdivide, store the samples in the returned
- array, together with the supplied final point. */
- } else {
-
-/* Extend the arrays. */
- isamp = *nsamp;
- *nsamp += npos + 1;
- *xtab = astGrow( *xtab, *nsamp, sizeof( double ) );
- *vtab = astGrow( *vtab, *nsamp, sizeof( double ) );
- if( astOK ) {
-
-/* Store the sample positions and values at the end of the extended
- arrays. */
- for( ipos = 0; ipos < npos; ipos++, isamp++ ) {
- (*xtab)[ isamp ] = xx[ ipos ];
- (*vtab)[ isamp ] = vv[ ipos ];
- }
- (*xtab)[ isamp ] = x1;
- (*vtab)[ isamp ] = v1;
- }
- }
- }
-
-/* Free resources. */
- xx = astFree( xx );
- vv= astFree( vv );
-}
-
-static int AddEncodingFrame( AstFitsChan *this, AstFrameSet *fs, int encoding,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* AddEncodingFrame
-
-* Purpose:
-* Add a Frame which conforms to the requirements of the specified encoding.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int AddEncodingFrame( AstFitsChan *this, AstFrameSet *fs, int encoding,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function attempts to create a Frame based on the current Frame
-* of the supplied FrameSet, which conforms to the requirements of the
-* specified Encoding. If created, this Frame is added into the
-* FrameSet as the new current Frame, and the index of the original current
-* Frame is returned.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* fs
-* Pointer to the FrameSet.
-* encoding
-* The encoding in use.
-* 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:
-* The index of the original current Frame in the FrameSet. A value of
-* AST__NOFRAME is returned if no new Frame is added to the FrameSet,
-* or if an error occurs.
-*/
-
-/* Local Variables: */
- AstCmpFrame *cmpfrm; /* Pointer to spectral cube frame */
- AstFrame *cfrm; /* Pointer to original current Frame */
- AstFrame *newfrm; /* Frame describing coord system to be used */
- AstFrame *pfrm; /* Pointer to primary Frame containing axis */
- AstFrameSet *fsconv; /* FrameSet converting what we have to what we want */
- AstMapping *map; /* Mapping from what we have to what we want */
- AstSkyFrame *skyfrm; /* Pointer to SkyFrame */
- AstSpecFrame *specfrm; /* Pointer to SpecFrame */
- AstSystemType sys; /* Frame coordinate system */
- int i; /* Axis index */
- int naxc; /* No. of axes in original current Frame */
- int paxis; /* Axis index in primary frame */
- int result; /* Returned value */
-
-/* Initialise */
- result = AST__NOFRAME;
-
-/* Check the inherited status. */
- if( !astOK ) return result;
-
-/* Get a pointer to the current Frame and note how many axes it has. */
- cfrm = astGetFrame( fs, AST__CURRENT );
- naxc = astGetNaxes( cfrm );
-
-/* FITS-CLASS */
-/* ========== */
- if( encoding == FITSCLASS_ENCODING ) {
-
-/* Try to locate a SpecFrame and a SkyFrame in the current Frame. */
- specfrm = NULL;
- skyfrm = NULL;
- for( i = 0; i < naxc; i++ ) {
- astPrimaryFrame( cfrm, i, &pfrm, &paxis );
- if( astIsASpecFrame( pfrm ) ) {
- if( !specfrm ) specfrm = astCopy( pfrm );
- } else if( IsASkyFrame( pfrm ) ) {
- if( !skyfrm ) skyfrm = astCopy( pfrm );
- }
- pfrm = astAnnul( pfrm );
- }
-
-/* Cannot do anything if either is missing. */
- if( specfrm && skyfrm ) {
-
-/* If the spectral axis is not frequency, set it to frequency. Also set
- spectral units of "Hz". */
- sys = astGetSystem( specfrm );
- if( sys != AST__FREQ ) {
- astSetSystem( specfrm, AST__FREQ );
- sys = AST__FREQ;
- }
-
-/* Ensure the standard of rest is Source and units are "Hz". */
- astSetUnit( specfrm, 0, "Hz" );
- astSetStdOfRest( specfrm, AST__SCSOR );
-
-/* The celestial axes must be either FK4, FK5 or galactic. */
- sys = astGetSystem( skyfrm );
- if( sys != AST__FK4 && sys != AST__FK5 && sys != AST__GALACTIC ) {
- astSetSystem( skyfrm, AST__FK5 );
- sys = AST__FK5;
- }
-
-/* FK5 systems must be J2000, and FK4 must be B1950. */
- if( sys == AST__FK5 ) {
- astSetC( skyfrm, "Equinox", "J2000.0" );
- } else if( sys == AST__FK4 ) {
- astSetC( skyfrm, "Equinox", "B1950.0" );
- }
-
-/* Combine the spectral and celestial Frames into a single CmpFrame with
- the spectral axis being the first axis. */
- cmpfrm = astCmpFrame( specfrm, skyfrm, "", status );
-
-/* Attempt to obtain the current Frame of the supplied FrameSet to this
- new Frame. */
- fsconv = astConvert( cfrm, cmpfrm, "" );
- if( fsconv ) {
-
-/* Get the Mapping and current Frame from the rconversion FrameSet. */
- newfrm = astGetFrame( fsconv, AST__CURRENT );
- map = astGetMapping( fsconv, AST__BASE, AST__CURRENT );
-
-/* Save the original current Frame index. */
- result = astGetCurrent( fs );
-
-/* Add the new Frame into the supplied FrameSet using the above Mapping
- to connect it to the original current Frame. The new Frame becomes the
- current Frame. */
- astAddFrame( fs, AST__CURRENT, map, newfrm );
-
-/* Free resources */
- map = astAnnul( map );
- newfrm = astAnnul( newfrm );
- fsconv = astAnnul( fsconv );
- }
-
-/* Free resources */
- cmpfrm = astAnnul( cmpfrm );
- }
-
-/* Release resources. */
- if( specfrm ) specfrm = astAnnul( specfrm );
- if( skyfrm ) skyfrm = astAnnul( skyfrm );
- }
-
-/* Free reources. */
- cfrm = astAnnul( cfrm );
-
-/* Return the result */
- return result;
-}
-
-static void AddFrame( AstFitsChan *this, AstFrameSet *fset, int pixel,
- int npix, FitsStore *store, char s, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* AddFrame
-
-* Purpose:
-* Create a Frame describing a set of axes with a given co-ordinate
-* version, and add it to the supplied FrameSet.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void AddFrame( AstFitsChan *this, AstFrameSet *fset, int pixel,
-* int npix, FitsStore *store, char s, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A Frame is created describing axis with a specific co-ordinate
-* version character, reading information from the supplied FitsStore.
-* A suitable Mapping is created to connect the new Frame to the pixel
-* (GRID) Frame in the supplied FrameSet, and the Frame is added into
-* the FrameSet using this Mapping.
-
-* Parameters:
-* this
-* The FitsChan from which the keywords were read. Warning messages
-* are added to this FitsChan if the celestial co-ordinate system is
-* not recognized.
-* fset
-* Pointer to the FrameSet to be extended.
-* pixel
-* The index of the pixel (GRID) Frame within fset.
-* npix
-* The number of pixel axes.
-* store
-* The FitsStore containing the required information extracted from
-* the FitsChan.
-* s
-* The co-ordinate version character. A space means the primary
-* axis descriptions. Otherwise the supplied character should be
-* an upper case alphabetical character ('A' to 'Z').
-* 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.
-*/
-
-/* Local Variables: */
- AstFrame *frame; /* Requested Frame */
- AstMapping *mapping; /* Mapping from pixel to requested Frame */
- AstMapping *tmap; /* Temporary Mapping pointer */
- AstPermMap *pmap; /* PermMap pointer to add or remove axes */
- double con; /* Value to be assigned to missing axes */
- int *inperm; /* Pointer to input axis permutation array */
- int *outperm; /* Pointer to output axis permutation array */
- int i; /* Axis index */
- int nwcs; /* Number of wcs axes */
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* Get a Mapping between pixel coordinates and physical coordinates, using
- the requested axis descriptions. Also returns a Frame describing the
- physical coordinate system. */
- mapping = WcsMapFrm( this, store, s, &frame, method, class, status );
-
-/* Add the Frame into the FrameSet, and annul the mapping and frame. If
- the new Frame has more axes than the pixel Frame, use a PermMap which
- assigns constant value 1.0 to the extra axes. If the new Frame has less
- axes than the pixel Frame, use a PermMap which throws away the extra
- axes. */
- if( mapping != NULL ) {
- nwcs = astGetNin( mapping );
- if( nwcs != npix ) {
- inperm = astMalloc( sizeof(int)*(size_t)npix );
- outperm = astMalloc( sizeof(int)*(size_t)nwcs );
- if( astOK ) {
- for( i = 0; i < npix; i++ ) {
- inperm[ i ] = ( i < nwcs ) ? i : -1;
- }
- for( i = 0; i < nwcs; i++ ) {
- outperm[ i ] = ( i < npix ) ? i : -1;
- }
- con = 1.0;
- pmap = astPermMap( npix, inperm, nwcs, outperm, &con, "", status );
- tmap = (AstMapping *) astCmpMap( pmap, mapping, 1, "", status );
- pmap = astAnnul( pmap );
- (void) astAnnul( mapping );
- mapping = tmap;
- }
- inperm = astFree( inperm );
- outperm = astFree( outperm );
- }
- astAddFrame( fset, pixel, mapping, frame );
-
-/* Annul temporary resources. */
- mapping = astAnnul( mapping );
- }
- frame = astAnnul( frame );
-}
-
-static int AddVersion( AstFitsChan *this, AstFrameSet *fs, int ipix, int iwcs,
- FitsStore *store, double *dim, char s, int encoding,
- int isoff, const char *method, const char *class,
- int *status ){
-
-/*
-* Name:
-* AddVersion
-
-* Purpose:
-* Add values to a FitsStore describing a specified Frame in a FrameSet.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int AddVersion( AstFitsChan *this, AstFrameSet *fs, int ipix, int iwcs,
-* FitsStore *store, double *dim, char s, int encoding,
-* int isoff, const char *method, const char *class,
-* int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Values are added to the supplied FitsStore describing the specified
-* WCS Frame, and its relationship to the specified pixel Frame. These
-* values are based on the standard FITS-WCS conventions.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* fs
-* Pointer to the FrameSet.
-* ipix
-* The index of the pixel (GRID) Frame within fset.
-* iwcs
-* The index of the Frame within fset to use as the WCS co-ordinate
-* Frame.
-* store
-* The FitsStore in which to store the information extracted from
-* the FrameSet.
-* dim
-* Pointer to an array of pixel axis dimensions. Individual elements
-* will be AST__BAD if dimensions are not known. The number of
-* elements should equal the number of axes in the base Frame of the
-* supplied FrameSet.
-* s
-* The co-ordinate version character. A space means the primary
-* axis descriptions. Otherwise the supplied character should be
-* an upper case alphabetical character ('A' to 'Z').
-* encoding
-* The encoding being used.
-* isoff
-* If greater than zero, the Frame is an offset SkyFrame and the
-* description added to the FitsStore should describe offset coordinates.
-* If less than than zero, the Frame is an offset SkyFrame and the
-* description added to the FitsStore should describe absolute coordinates.
-* If zero, the Frame is an absolute SkyFrame and the description added
-* to the FitsSTore should (by necessity) describe absolute coordinates.
-* 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.
-
-* Retuned Value:
-* A value of 1 is returned if the WCS Frame was succesfully added to
-* the FitsStore. A value of zero is returned otherwise.
-*/
-
-/* Local Variables: */
- AstFrame *wcsfrm; /* WCS Frame */
- AstFrameSet *fset; /* Temporary FrameSet */
- AstMapping *iwcmap; /* Mapping from WCS to IWC Frame */
- AstMapping *mapping; /* Mapping from pixel to WCS Frame */
- AstMapping *pixiwcmap; /* Mapping from pixel to IWC Frame */
- AstMapping *tmap2; /* Temporary Mapping */
- AstMapping *tmap; /* Temporary Mapping */
- const char *old_skyrefis;/* Old value of SkyRefIs attribute */
- double *crvals; /* Pointer to array holding default CRVAL values */
- double cdelt2; /* Sum of squared PC values */
- double cdelt; /* CDELT value for axis */
- double crpix; /* CRPIX value for axis */
- double crval; /* CRVAL value for axis */
- double pc; /* Element of the PC array */
- int *axis_done; /* Flags indicating which axes have been done */
- int *wperm; /* FITS axis for each Mapping output (Frame axis) */
- int fits_i; /* FITS WCS axis index */
- int fits_j; /* FITS pixel axis index */
- int iax; /* Frame axis index */
- int icurr; /* Index of current Frame */
- int nwcs; /* No. of axes in WCS frame */
- int ret; /* Returned value */
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* If the frame is a SkyFrame describing offset coordinates, but the
- description added to the FitsStore should be for absolute coordinates,
- temporarily clear the SkyFrame SkyRefIs attribute. We need to make it
- the current Frame first so that we can use the FrameSet to clear the
- attribte, so that the SkyFrame will be re-mapped within the FrameSet
- to take account of the clearing. For negative isoff values, set the
- specific negative value to indicate the original SkyRefIs value. */
- if( isoff < 0 ) {
- icurr = astGetCurrent( fs );
- astSetCurrent( fs, iwcs );
- old_skyrefis = astGetC( fs, "SkyRefIs" );
- if( astOK ) {
- if( !Ustrcmp( old_skyrefis, "POLE", status ) ) {
- isoff = -1;
- } else if( !Ustrcmp( old_skyrefis, "ORIGIN", status ) ) {
- isoff = -2;
- } else {
- isoff = -3;
- }
- }
- astClear( fs, "SkyRefIs" );
- astSetCurrent( fs, icurr );
- } else {
- old_skyrefis = AST__BAD_REF;
- }
-
-/* Construct a new FrameSet holding the pixel and WCS Frames from the
- supplied FrameSet, but in which the current Frame is a copy of the
- supplied WCS Frame, but optionally extended to include any extra axes
- needed to conform to the FITS model. For instance, if the WCS Frame
- consists of a single 1D SpecFrame with a defined celestial reference
- position (SpecFrame attributes RefRA and RefDec), then FITS-WCS paper
- III requires there to be a pair of celestial axes in the WCS Frame in
- which the celestial reference point for the spectral axis is defined. */
- fset = MakeFitsFrameSet( this, fs, ipix, iwcs, encoding, method, class, status );
-
-/* If required, re-instate the original value of the SkyRefIs attribute
- in the supplied FrameSet. */
- if( old_skyrefis != AST__BAD_REF ) {
- astSetCurrent( fs, iwcs );
- astSetC( fs, "SkyRefIs", old_skyrefis );
- astSetCurrent( fs, icurr );
- }
-
-/* Abort if the FrameSet could not be produced. */
- if( !fset ) return ret;
-
-/* Get the Mapping from base to current Frame and check its inverse is
- defined. Return if not. Note, we can handle non-invertable Mappings if
- we are allowed to use the -TAB algorithm. */
- mapping = astGetMapping( fset, AST__BASE, AST__CURRENT );
- wcsfrm = astGetFrame( fset, AST__CURRENT );
- if( !astGetTranInverse( mapping ) && astGetTabOK( this ) <= 0 ) {
- mapping = astAnnul( mapping );
- wcsfrm = astAnnul( wcsfrm );
- fset = astAnnul( fset );
- return ret;
- }
-
-/* We now need to choose the "FITS WCS axis" (i.e. the number that is included
- in FITS keywords such as CRVAL2) for each axis of the output Frame.
- Allocate memory to store these indices. */
- nwcs= astGetNout( mapping );
- wperm = astMalloc( sizeof(int)*(size_t) nwcs );
-
-/* Attempt to use the FitsAxisOrder attribute to determine the order. If
- this is set to "<auto>", then for each WCS axis, we use the index of
- the pixel axis which is most closely aligned with it. */
- if( !FitsAxisOrder( this, nwcs, wcsfrm, wperm, status ) &&
- !WorldAxes( this, mapping, dim, wperm, status ) ) {
- wperm = astFree( wperm );
- mapping = astAnnul( mapping );
- wcsfrm = astAnnul( wcsfrm );
- fset = astAnnul( fset );
- return ret;
- }
-
-/* Allocate an array of flags, one for each axis, which indicate if a
- description of the corresponding axis has yet been stored in the
- FitsStore. Initialise them to indicate that no axes have yet been
- described. */
- axis_done = astMalloc( sizeof(int)*(size_t) nwcs );
- if( astOK ) for( iax = 0; iax < nwcs; iax++ ) axis_done[ iax ] = 0;
-
-/* Get the original reference point from the FitsChan and convert it into
- the require WCS Frame. This is used as the default reference point (some
- algorithms may choose to ignore this default reference point ). */
- crvals = ReadCrval( this, wcsfrm, s, method, class, status );
-
-/* For each class of FITS conventions (celestial, spectral, others),
- identify any corresponding axes within the WCS Frame and add
- descriptions of them to the FitsStore. These descriptions are in terms
- of the FITS keywords defined in the corresponding FITS-WCS paper. Note,
- the keywords which descirbed the pixel->IWC mapping (CRPIX, CD, PC,
- CDELT) are not stored by these functions, instead each function
- returns a Mapping from WCS to IWC coords (these Mappings
- pass on axes of the wrong class without change). These Mappings are
- combined in series to get the final WCS->IWC Mapping. First do
- celestial axes. */
- iwcmap = CelestialAxes( this, fset, dim, wperm, s, store, axis_done,
- isoff, method, class, status );
-
-/* Now look for spectral axes, and update the iwcmap. */
- tmap = SpectralAxes( this, fset, dim, wperm, s, store, crvals, axis_done,
- method, class, status );
- tmap2 = (AstMapping *) astCmpMap( iwcmap, tmap, 1, "", status );
- tmap = astAnnul( tmap );
- (void) astAnnul( iwcmap );
- iwcmap = tmap2;
-
-/* Finally add descriptions of any axes not yet described (they are
- assumed to be linear), and update the iwcmap. */
- tmap = OtherAxes( this, fset, dim, wperm, s, store, crvals, axis_done,
- method, class, status );
- tmap2 = (AstMapping *) astCmpMap( iwcmap, tmap, 1, "", status );
- tmap = astAnnul( tmap );
- (void) astAnnul( iwcmap );
- iwcmap = tmap2;
-
-/* The "iwcmap" Mapping found above converts from the WCS Frame to the IWC
- Frame. Combine the pixel->WCS Mapping with this WCS->IWC Mapping to
- get the pixel->IWC Mapping. */
- pixiwcmap = (AstMapping *) astCmpMap( mapping, iwcmap, 1, "", status );
- mapping = astAnnul( mapping );
- iwcmap = astAnnul( iwcmap );
-
-/* Now attempt to store values for the keywords describing the pixel->IWC
- Mapping (CRPIX, CD, PC, CDELT). This tests that the iwcmap is linear.
- Zero is returned if the test fails. */
- ret = MakeIntWorld( pixiwcmap, wcsfrm, wperm, s, store, dim, method, class,
- status );
-
-/* If succesfull... */
- if( ret ) {
-
-/* Store the Domain name as the WCSNAME keyword (if set). */
- if( astTestDomain( wcsfrm ) ) {
- SetItemC( &(store->wcsname), 0, 0, s, (char *) astGetDomain( wcsfrm ),
- status );
- }
-
-/* Store the UT1-UTC correction, if set, converting from seconds to days
- (as used by JACH). */
- if( astTestDut1( wcsfrm ) && s == ' ' ) {
- SetItem( &(store->dut1), 0, 0, ' ', astGetDut1( wcsfrm )/SPD, status );
- }
-
-/* Set CRVAL values which are very small compared to the pixel size to
- zero. */
- for( iax = 0; iax < nwcs; iax++ ) {
- fits_i = wperm[ iax ];
- crval = GetItem( &(store->crval), fits_i, 0, s, NULL, method, class,
- status );
- if( crval != AST__BAD ) {
- cdelt2 = 0.0;
- for( fits_j = 0; fits_j < nwcs; fits_j++ ){
- pc = GetItem( &(store->pc), fits_i, fits_j, s, NULL, method, class, status );
- if( pc == AST__BAD ) pc = ( fits_i == fits_j ) ? 1.0 : 0.0;
- cdelt2 += pc*pc;
- }
- cdelt = GetItem( &(store->cdelt), fits_i, 0, s, NULL, method, class, status );
- if( cdelt == AST__BAD ) cdelt = 1.0;
- cdelt2 *= ( cdelt*cdelt );
- if( fabs( crval ) < sqrt( DBL_EPSILON*cdelt2 ) ) {
- SetItem( &(store->crval), fits_i, 0, s, 0.0, status );
- }
- }
- }
-
-/* Round CRPIX values to the nearest millionth of a pixel. */
- for( iax = 0; iax < nwcs; iax++ ) {
- crpix = GetItem( &(store->crpix), 0, iax, s, NULL, method, class, status );
- if( crpix != AST__BAD ) {
- SetItem( &(store->crpix), 0, iax, s,
- floor( crpix*1.0E6 + 0.5 )*1.0E-6, status );
- }
- }
- }
-
-/* Free remaining resources. */
- if( crvals ) crvals = astFree( crvals );
- wcsfrm = astAnnul( wcsfrm );
- pixiwcmap = astAnnul( pixiwcmap );
- axis_done = astFree( axis_done );
- wperm = astFree( wperm );
- fset = astAnnul( fset );
-
-/* If an error has occurred, return zero */
- return astOK ? ret : 0;
-}
-
-static AstMapping *AddUnitMaps( AstMapping *map, int iax, int nax, int *status ) {
-/*
-* Name:
-* AddUnitMaps
-
-* Purpose:
-* Embed a Mapping within a pair of parallel UnitMaps.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *AddUnitMaps( AstMapping *map, int iax, int nax, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns a Mapping which consists of the supplied Mapping
-* in parallel with a pair of UnitMaps so that the first axis of the
-* supplied Mapping is at a specified axis number in the returned Mapping.
-
-* Parameters:
-* map
-* Pointer to the Mapping. The Mapping must have equal numbers of
-* input and output coordinates.
-* iax
-* The index for the first input of "map" within the returned
-* Mapping.
-* nax
-* The number of axes for the returned Mapping.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A Mapping which has "nax" axes, and in which the "iax" axis
-* corresponds to the first axis of "map". Axes lower than "iax" are
-* transformed using a UnitMap, and axes higher than the last axis of
-* "map" are transformed using a UnitMap.
-*/
-
-/* Local Variables: */
- AstMapping *ret; /* Returned Mapping */
- AstMapping *tmap0; /* Temporary Mapping */
- AstMapping *tmap1; /* Temporary Mapping */
- AstMapping *tmap2; /* Temporary Mapping */
- int nmap; /* Number of supplied Mapping inputs */
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Initialise the returned Mapping to be a clone of the supplied Mapping. */
- ret = astClone( map );
-
-/* Note the number of inputs of the supplied Mapping (assumed to be equal
- to the number of outputs). */
- nmap = astGetNin( map );
-
-/* If necessary produce a parallel CmpMap which combines the Mapping with a
- UnitMap representing the axes lower than "iax". */
- if( iax > 0 ) {
- tmap0 = (AstMapping *) astUnitMap( iax, "", status );
- tmap1 = (AstMapping *) astCmpMap( tmap0, ret, 0, "", status );
- ret = astAnnul( ret );
- tmap0 = astAnnul( tmap0 );
- ret = tmap1;
- }
-
-/* If necessary produce a parallel CmpMap which combines the Mapping with a
- UnitMap representing the axes higher than "iax+nmap". */
- if( iax + nmap < nax ) {
- tmap1 = (AstMapping *) astUnitMap( nax - iax - nmap, "", status );
- tmap2 = (AstMapping *) astCmpMap( ret, tmap1, 0, "", status );
- ret = astAnnul( ret );
- tmap1 = astAnnul( tmap1 );
- ret = tmap2;
- }
-
-/* Return the result. */
- return ret;
-}
-
-static int AIPSFromStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* AIPSFromStore
-
-* Purpose:
-* Store WCS keywords in a FitsChan using FITS-AIPS encoding.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* int AIPSFromStore( AstFitsChan *this, FitsStore *store,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function copies the WCS information stored in the supplied
-* FitsStore into the supplied FitsChan, using FITS-AIPS encoding.
-*
-* AIPS encoding is like FITS-WCS encoding but with the following
-* restrictions:
-*
-* 1) The celestial projection must not have any projection parameters
-* which are not set to their default values. The one exception to this
-* is that SIN projections are acceptable if the associated projection
-* parameter PV<axlat>_1 is zero and PV<axlat>_2 = cot( reference point
-* latitude). This is encoded using the string "-NCP". The SFL projection
-* is encoded using the string "-GLS". Note, the original AIPS WCS
-* system only recognised a small subset of the currently available
-* projections, but some more recent AIPS-like software recognizes some
-* of the new projections included in the FITS-WCS encoding. The AIT,
-* GLS and MER can only be written if the CRVAL keywords are zero for
-* both longitude and latitude axes.
-*
-* 2) The celestial axes must be RA/DEC, galactic or ecliptic.
-*
-* 3) LONPOLE and LATPOLE must take their default values.
-*
-* 4) Only primary axis descriptions are written out.
-*
-* 5) EPOCH is written instead of EQUINOX & RADECSYS, and uses the
-* IAU 1984 rule ( EPOCH < 1984.0 is treated as a Besselian epoch
-* and implies RADECSYS=FK4, EPOCH >= 1984.0 is treated as a
-* Julian epoch and implies RADECSYS=FK5). The RADECSYS & EQUINOX
-* values in the FitsStore must be consistent with this rule.
-*
-* 6) Any rotation produced by the PC matrix must be restricted to
-* the celestial plane, and must involve no shear. A CROTA keyword
-* with associated CDELT values are produced instead of the PC
-* matrix.
-*
-* 7) ICRS is not supported.
-*
-* 8) Spectral axes can be created only for FITS-WCS CTYPE values of "FREQ"
-* "VRAD" and "VOPT-F2W" and with standards of rest of LSRK, LSRD,
-* BARYCENT and GEOCENTR.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore.
-* 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 value of 1 is returned if succesfull, and zero is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- char *comm; /* Pointer to comment string */
- const char *cval; /* Pointer to string keyword value */
- const char *specunit;/* Pointer to corrected spectral units string */
- char combuf[80]; /* Buffer for FITS card comment */
- char lattype[MXCTYPELEN];/* Latitude axis CTYPE */
- char lontype[MXCTYPELEN];/* Longitude axis CTYPE */
- char s; /* Co-ordinate version character */
- char sign[2]; /* Fraction's sign character */
- char spectype[MXCTYPELEN];/* Spectral axis CTYPE */
- double *cdelt; /* Pointer to CDELT array */
- double cdl; /* CDELT term */
- double cdlat_lon; /* Off-diagonal CD element */
- double cdlon_lat; /* Off-diagonal CD element */
- double coscro; /* Cos( CROTA ) */
- double crota; /* CROTA value to use */
- double epoch; /* Epoch of reference equinox */
- double fd; /* Fraction of a day */
- double latval; /* CRVAL for latitude axis */
- double lonval; /* CRVAL for longitude axis */
- double mjd99; /* MJD at start of 1999 */
- double p1, p2; /* Projection parameters */
- double rho_a; /* First estimate of CROTA */
- double rho_b; /* Second estimate of CROTA */
- double sincro; /* Sin( CROTA ) */
- double specfactor; /* Factor for converting internal spectral units */
- double val; /* General purpose value */
- int axlat; /* Index of latitude FITS WCS axis */
- int axlon; /* Index of longitude FITS WCS axis */
- int axrot1; /* Index of first CROTA rotation axis */
- int axrot2; /* Index of second CROTA rotation axis */
- int axspec; /* Index of spectral FITS WCS axis */
- int i; /* Axis index */
- int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */
- int iymdf[ 4 ]; /* Year, month, date, fractional day */
- int j; /* Axis index */
- int jj; /* SlaLib status */
- int naxis; /* No. of axes */
- int ok; /* Is FitsSTore OK for IRAF encoding? */
- int prj; /* Projection type */
-
-/* Check the inherited status. */
- if( !astOK ) return 0;
-
-/* Initialise */
- specunit = "";
- specfactor = 1.0;
-
-/* First check that the values in the FitsStore conform to the
- requirements of the AIPS encoding. Assume they do to begin with. */
- ok = 1;
-
-/* Just do primary axes. */
- s = ' ';
-
-/* Look for the primary celestial axes. */
- FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status );
-
-/* If both longitude and latitude axes are present ...*/
- if( axlon >= 0 && axlat >= 0 ) {
-
-/* Get the CRVAL values for both axes. */
- latval = GetItem( &( store->crval ), axlat, 0, s, NULL, method, class, status );
- if( latval == AST__BAD ) ok = 0;
- lonval = GetItem( &( store->crval ), axlon, 0, s, NULL, method, class, status );
- if( lonval == AST__BAD ) ok = 0;
-
-/* Get the CTYPE values for both axes. Extract the projection type as
- specified by the last 4 characters in the latitude CTYPE keyword value. */
- cval = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else {
- strcpy( lontype, cval );
- }
- cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- prj = AST__WCSBAD;
- } else {
- strcpy( lattype, cval );
- prj = astWcsPrjType( cval + 4 );
- }
-
-/* Check the projection type is OK. */
- if( prj == AST__WCSBAD ){
- ok = 0;
- } else if( prj != AST__SIN ){
-
-/* There must be no projection parameters. */
- if( GetMaxJM( &(store->pv), ' ', status ) >= 0 ) {
- ok = 0;
-
-/* FITS-AIPS cannot handle the AST-specific TPN projection. */
- } else if( prj == AST__TPN ) {
- ok = 0;
-
-/* For AIT, MER and GLS, check that the reference point is the origin of
- the celestial co-ordinate system. */
- } else if( prj == AST__MER ||
- prj == AST__AIT ||
- prj == AST__SFL ) {
- if( latval != 0.0 || lonval != 0.0 ){
- ok = 0;
-
-/* Change the new SFL projection code to to the older equivalent GLS */
- } else if( prj == AST__SFL ){
- (void) strcpy( lontype + 4, "-GLS" );
- (void) strcpy( lattype + 4, "-GLS" );
- }
- }
-
-/* SIN projections are only acceptable if the associated projection
- parameters are both zero, or if the first is zero and the second
- = cot( reference point latitude ) (the latter case is equivalent to
- the old NCP projection). */
- } else {
- p1 = GetItem( &( store->pv ), axlat, 1, s, NULL, method, class, status );
- p2 = GetItem( &( store->pv ), axlat, 2, s, NULL, method, class, status );
- if( p1 == AST__BAD ) p1 = 0.0;
- if( p2 == AST__BAD ) p2 = 0.0;
- ok = 0;
- if( p1 == 0.0 ) {
- if( p2 == 0.0 ) {
- ok = 1;
- } else if( fabs( p2 ) >= 1.0E14 && latval == 0.0 ){
- ok = 1;
- (void) strcpy( lontype + 4, "-NCP" );
- (void) strcpy( lattype + 4, "-NCP" );
- } else if( fabs( p2*tan( AST__DD2R*latval ) - 1.0 )
- < 0.01 ){
- ok = 1;
- (void) strcpy( lontype + 4, "-NCP" );
- (void) strcpy( lattype + 4, "-NCP" );
- }
- }
- }
-
-/* Identify the celestial coordinate system from the first 4 characters of the
- longitude CTYPE value. Only RA, galactic longitude, and ecliptic
- longitude can be stored using FITS-AIPS. */
- if( ok && strncmp( lontype, "RA--", 4 ) &&
- strncmp( lontype, "GLON", 4 ) &&
- strncmp( lontype, "ELON", 4 ) ) ok = 0;
-
-/* If the physical Frame requires a LONPOLE or LATPOLE keyword, it cannot
- be encoded using FITS-IRAF. */
- if( GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status )
- != AST__BAD ||
- GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status )
- != AST__BAD ) ok = 0;
- }
-
-/* If a spectral axis is present ...*/
- if( ok && axspec >= 0 ) {
-
-/* Get the CTYPE values for the axis, and find the AIPS equivalent, if
- possible. */
- cval = GetItemC( &(store->ctype), axspec, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else {
- if( !strncmp( cval, "FREQ", astChrLen( cval ) ) ) {
- strcpy( spectype, "FREQ" );
- } else if( !strncmp( cval, "VRAD", astChrLen( cval ) ) ) {
- strcpy( spectype, "VELO" );
- } else if( !strncmp( cval, "VOPT-F2W", astChrLen( cval ) ) ) {
- strcpy( spectype, "FELO" );
- } else {
- ok = 0;
- }
- }
-
-/* If OK, check the SPECSYS value and add the AIPS equivalent onto the
- end of the CTYPE value.*/
- cval = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else if( ok ) {
- if( !strncmp( cval, "LSRK", astChrLen( cval ) ) ) {
- strcpy( spectype+4, "-LSR" );
- } else if( !strncmp( cval, "LSRD", astChrLen( cval ) ) ) {
- strcpy( spectype+4, "-LSD" );
- } else if( !strncmp( cval, "BARYCENT", astChrLen( cval ) ) ) {
- strcpy( spectype+4, "-HEL" );
- } else if( !strncmp( cval, "GEOCENTR", astChrLen( cval ) ) ) {
- strcpy( spectype+4, "-GEO" );
- } else {
- ok = 0;
- }
- }
-
-/* If still OK, ensure the spectral axis units are Hz or m/s. */
- cval = GetItemC( &(store->cunit), axspec, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else if( ok ) {
- if( !strcmp( cval, "Hz" ) ) {
- specunit = "HZ";
- specfactor = 1.0;
- } else if( !strcmp( cval, "kHz" ) ) {
- specunit = "HZ";
- specfactor = 1.0E3;
- } else if( !strcmp( cval, "MHz" ) ) {
- specunit = "HZ";
- specfactor = 1.0E6;
- } else if( !strcmp( cval, "GHz" ) ) {
- specunit = "HZ";
- specfactor = 1.0E9;
- } else if( !strcmp( cval, "m/s" ) ) {
- specunit = "m/s";
- specfactor = 1.0;
- } else if( !strcmp( cval, "km/s" ) ) {
- specunit = "m/s";
- specfactor = 1.0E3;
- } else {
- ok = 0;
- }
- }
- }
-
-/* Save the number of axes */
- naxis = GetMaxJM( &(store->crpix), ' ', status ) + 1;
-
-/* If this is different to the value of NAXIS abort since this encoding
- does not support WCSAXES keyword. */
- if( naxis != store->naxis ) ok = 0;
-
-/* Allocate memory to store the CDELT values */
- if( ok ) {
- cdelt = (double *) astMalloc( sizeof(double)*naxis );
- if( !cdelt ) ok = 0;
- } else {
- cdelt = NULL;
- }
-
-/* Check that rotation is restricted to the celestial plane, and extract
- the CDELT (diagonal) terms, etc. If there are no celestial
- axes, restrict rotation to the first two non-spectral axes. */
- if( axlat < 0 && axlon < 0 ) {
- if( axspec >= 0 && naxis > 2 ) {
- axrot2 = ( axspec == 0 ) ? 1 : 0;
- axrot1 = axrot2 + 1;
- if( axrot1 == axspec ) axrot1++;
- } else if( naxis > 1 ){
- axrot2 = 0;
- axrot1 = 1;
- } else {
- axrot2 = -1;
- axrot1 = -1;
- }
- } else {
- axrot1 = axlon;
- axrot2 = axlat;
- }
- cdlat_lon = 0.0;
- cdlon_lat = 0.0;
- for( i = 0; i < naxis && ok; i++ ){
- cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
- if( cdl == AST__BAD ) cdl = 1.0;
- for( j = 0; j < naxis && ok; j++ ){
- val = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
- if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0;
- val *= cdl;
- if( i == j ){
- cdelt[ i ] = val;
- } else if( i == axrot2 && j == axrot1 ){
- cdlat_lon = val;
- } else if( i == axrot1 && j == axrot2 ){
- cdlon_lat = val;
- } else if( val != 0.0 ){
- ok = 0;
- }
- }
- }
-
-/* Find the CROTA and CDELT values for the celestial axes. */
- if( ok && axrot1 >= 0 && axrot2 >= 0 ) {
- if( cdlat_lon > 0.0 ) {
- rho_a = atan2( cdlat_lon, cdelt[ axrot1 ] );
- } else if( cdlat_lon == 0.0 ) {
- rho_a = 0.0;
- } else {
- rho_a = atan2( -cdlat_lon, -cdelt[ axrot1 ] );
- }
- if( cdlon_lat > 0.0 ) {
- rho_b = atan2( cdlon_lat, -cdelt[ axrot2 ] );
- } else if( cdlon_lat == 0.0 ) {
- rho_b = 0.0;
- } else {
- rho_b = atan2( -cdlon_lat, cdelt[ axrot2 ] );
- }
- if( fabs( palDrange( rho_a - rho_b ) ) < 1.0E-2 ){
- crota = 0.5*( palDranrm( rho_a ) + palDranrm( rho_b ) );
- coscro = cos( crota );
- sincro = sin( crota );
- if( fabs( coscro ) > fabs( sincro ) ){
- cdelt[ axrot2 ] /= coscro;
- cdelt[ axrot1 ] /= coscro;
- } else {
- cdelt[ axrot2 ] = -cdlon_lat/sincro;
- cdelt[ axrot1 ] = cdlat_lon/sincro;
- }
- crota *= AST__DR2D;
- } else {
- ok = 0;
- }
- } else {
- crota = 0.0;
- }
-
-/* Get RADECSYS and the reference equinox (called EPOCH in FITS-AIPS). */
- cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status );
- epoch = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status );
-
-/* If RADECSYS was available... */
- if( cval ){
-
-/* ICRS is not supported in this encoding. */
- if( !strcmp( "ICRS", cval ) ) ok = 0;
-
-/* If epoch was not available, set a default epoch. */
- if( epoch == AST__BAD ){
- if( !strcmp( "FK4", cval ) ){
- epoch = 1950.0;
- } else if( !strcmp( "FK5", cval ) ){
- epoch = 2000.0;
- } else {
- ok = 0;
- }
-
-/* If an epoch was supplied, check it is consistent with the IAU 1984
- rule. */
- } else {
- if( !strcmp( "FK4", cval ) ){
- if( epoch >= 1984.0 ) ok = 0;
- } else if( !strcmp( "FK5", cval ) ){
- if( epoch < 1984.0 ) ok = 0;
- } else {
- ok = 0;
- }
- }
- }
-
-/* Only create the keywords if the FitsStore conforms to the requirements
- of the FITS-AIPS encoding. */
- if( ok ) {
-
-/* Get and save CRPIX for all pixel axes. These are required, so break
- if they are not available. */
- for( j = 0; j < naxis && ok; j++ ){
- val = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- } else {
- sprintf( combuf, "Reference pixel on axis %d", j + 1 );
- SetValue( this, FormatKey( "CRPIX", j + 1, -1, s, status ), &val,
- AST__FLOAT, combuf, status );
- }
- }
-
-/* Get and save CRVAL for all intermediate axes. These are required, so
- break if they are not available. */
- for( i = 0; i < naxis && ok; i++ ){
- val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- } else {
- if( i == axspec ) val *= specfactor;
- sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 );
- SetValue( this, FormatKey( "CRVAL", i + 1, -1, s, status ), &val,
- AST__FLOAT, combuf, status );
- }
- }
-
-/* Get and save CTYPE for all intermediate axes. These are required, so
- break if they are not available. Use the potentially modified versions
- saved above for the celestial axes. */
- for( i = 0; i < naxis && ok; i++ ){
- if( i == axlat ) {
- cval = lattype;
- } else if( i == axlon ) {
- cval = lontype;
- } else if( i == axspec ) {
- cval = spectype;
- } else {
- cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- }
- if( cval && ( strlen(cval) < 5 || strcmp( cval + 4, "-TAB" ) ) ) {
- comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status );
- if( !comm ) {
- sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 );
- comm = combuf;
- }
- SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval,
- AST__STRING, comm, status );
- } else {
- ok = 0;
- }
- }
-
-/* CDELT values */
- if( axspec != -1 ) cdelt[ axspec ] *= specfactor;
- for( i = 0; i < naxis; i++ ){
- SetValue( this, FormatKey( "CDELT", i + 1, -1, s, status ), cdelt + i,
- AST__FLOAT, "Pixel size", status );
- }
-
-/* CUNIT values. */
- for( i = 0; i < naxis; i++ ) {
- cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status );
- if( cval ) {
- if( i == axspec ) cval = specunit;
- sprintf( combuf, "Units for axis %d", i + 1 );
- SetValue( this, FormatKey( "CUNIT", i + 1, -1, s, status ), &cval, AST__STRING,
- combuf, status );
- }
- }
-
-/* CROTA */
- if( axrot2 != -1 ){
- SetValue( this, FormatKey( "CROTA", axrot2 + 1, -1, s, status ), &crota,
- AST__FLOAT, "Axis rotation", status );
- } else if( ( axspec == -1 && naxis > 1 ) ||
- ( axspec != -1 && naxis > 2 ) ) {
- SetValue( this, "CROTA1", &crota, AST__FLOAT, "Axis rotation", status );
- }
-
-/* Reference equinox */
- if( epoch != AST__BAD ) SetValue( this, "EPOCH", &epoch, AST__FLOAT,
- "Epoch of reference equinox", status );
-
-/* Date of observation. */
- val = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status );
- if( val != AST__BAD ) {
-
-/* The format used for the DATE-OBS keyword depends on the value of the
- keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format.
- Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */
- palCaldj( 99, 1, 1, &mjd99, &jj );
- if( val < mjd99 ) {
- palDjcal( 0, val, iymdf, &jj );
- sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ],
- iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) );
- } else {
- palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj );
- palDd2tf( 3, fd, sign, ihmsf );
- sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d",
- iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1],
- ihmsf[2], ihmsf[3] );
- }
-
-/* Now store the formatted string in the FitsChan. */
- cval = combuf;
- SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING,
- "Date of observation", status );
- }
-
-/* Spectral stuff.. */
- if( axspec >= 0 ) {
-
-/* Rest frequency */
- val = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "RESTFREQ", -1, -1, s, status ),
- &val, AST__FLOAT, "[Hz] Rest frequency", status );
- }
- }
-
-/* Release CDELT workspace */
- if( cdelt ) cdelt = (double *) astFree( (void *) cdelt );
-
-/* Return zero or ret depending on whether an error has occurred. */
- return astOK ? ok : 0;
-}
-
-static int AIPSPPFromStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* AIPSPPFromStore
-
-* Purpose:
-* Store WCS keywords in a FitsChan using FITS-AIPS++ encoding.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* int AIPSPPFromStore( AstFitsChan *this, FitsStore *store,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function copies the WCS information stored in the supplied
-* FitsStore into the supplied FitsChan, using FITS-AIPS++ encoding.
-*
-* AIPS++ encoding is like FITS-WCS encoding but with the following
-* restrictions:
-*
-* 1) The celestial axes must be RA/DEC, galactic or ecliptic.
-*
-* 2) Only primary axis descriptions are written out.
-*
-* 3) RADESYS is not written and so the RADECSYS & EQUINOX values in the
-* FitsStore must be consistent with the "1984" rule.
-*
-* 4) Any rotation produced by the PC matrix must be restricted to
-* the celestial plane, and must involve no shear. A CROTA keyword
-* with associated CDELT values are produced instead of the PC
-* matrix.
-*
-* 5) ICRS is not supported.
-*
-* 6) Spectral axes can be created only for FITS-WCS CTYPE values of "FREQ"
-* "VRAD" and "VOPT-F2W" and with standards of rest of LSRK, LSRD,
-* BARYCENT and GEOCENTR.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore.
-* 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 value of 1 is returned if succesfull, and zero is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- char *comm; /* Pointer to comment string */
- const char *cval; /* Pointer to string keyword value */
- const char *specunit;/* Pointer to corrected spectral units string */
- char combuf[80]; /* Buffer for FITS card comment */
- char lattype[MXCTYPELEN];/* Latitude axis CTYPE */
- char lontype[MXCTYPELEN];/* Longitude axis CTYPE */
- char s; /* Co-ordinate version character */
- char sign[2]; /* Fraction's sign character */
- char spectype[MXCTYPELEN];/* Spectral axis CTYPE */
- double *cdelt; /* Pointer to CDELT array */
- double cdl; /* CDELT term */
- double cdlat_lon; /* Off-diagonal CD element */
- double cdlon_lat; /* Off-diagonal CD element */
- double coscro; /* Cos( CROTA ) */
- double crota; /* CROTA value to use */
- double epoch; /* Epoch of reference equinox */
- double fd; /* Fraction of a day */
- double mjd99; /* MJD at start of 1999 */
- double rho_a; /* First estimate of CROTA */
- double rho_b; /* Second estimate of CROTA */
- double sincro; /* Sin( CROTA ) */
- double specfactor; /* Factor for converting internal spectral units */
- double val; /* General purpose value */
- int axlat; /* Index of latitude FITS WCS axis */
- int axlon; /* Index of longitude FITS WCS axis */
- int axrot1; /* Index of first CROTA rotation axis */
- int axrot2; /* Index of second CROTA rotation axis */
- int axspec; /* Index of spectral FITS WCS axis */
- int i; /* Axis index */
- int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */
- int iymdf[ 4 ]; /* Year, month, date, fractional day */
- int j; /* Axis index */
- int jj; /* SlaLib status */
- int m; /* Projection parameter index */
- int maxm; /* Max projection parameter index */
- int naxis; /* No. of axes */
- int ok; /* Is FitsSTore OK for IRAF encoding? */
- int prj; /* Projection type */
-
-/* Check the inherited status. */
- if( !astOK ) return 0;
-
-/* Initialise */
- specunit = "";
- specfactor = 1.0;
- maxm = 0;
-
-/* First check that the values in the FitsStore conform to the
- requirements of the AIPS++ encoding. Assume they do to begin with. */
- ok = 1;
-
-/* Just do primary axes. */
- s = ' ';
-
-/* Save the number of axes */
- naxis = GetMaxJM( &(store->crpix), ' ', status ) + 1;
-
-/* Look for the primary celestial and spectral axes. */
- FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status );
-
-/* If both longitude and latitude axes are present ...*/
- if( axlon >= 0 && axlat >= 0 ) {
-
-/* Get the CTYPE values for both axes. Extract the projection type as
- specified by the last 4 characters in the latitude CTYPE keyword value. */
- cval = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else {
- strcpy( lontype, cval );
- }
- cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- prj = AST__WCSBAD;
- } else {
- strcpy( lattype, cval );
- prj = astWcsPrjType( cval + 4 );
- }
-
-/* FITS-AIPS++ cannot handle the AST-specific TPN projection. */
- if( prj == AST__TPN || prj == AST__WCSBAD ) ok = 0;
-
-/* Projection parameters. FITS-AIPS++ encoding ignores projection parameters
- associated with the longitude axis. The number of parameters is limited to
- 10. */
- maxm = GetMaxJM( &(store->pv), ' ', status );
- for( i = 0; i < naxis && ok; i++ ){
- if( i != axlon ) {
- for( m = 0; m <= maxm; m++ ){
- val = GetItem( &(store->pv), i, m, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- if( i != axlat || m >= 10 ){
- ok = 0;
- break;
- }
- }
- }
- }
- }
-
-/* Identify the celestial coordinate system from the first 4 characters of the
- longitude CTYPE value. Only RA, galactic longitude, and ecliptic
- longitude can be stored using FITS-AIPS++. */
- if( ok && strncmp( lontype, "RA--", 4 ) &&
- strncmp( lontype, "GLON", 4 ) &&
- strncmp( lontype, "ELON", 4 ) ) ok = 0;
- }
-
-/* If a spectral axis is present ...*/
- if( axspec >= 0 ) {
-
-/* Get the CTYPE values for the axis, and find the AIPS equivalent, if
- possible. */
- cval = GetItemC( &(store->ctype), axspec, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else {
- if( !strncmp( cval, "FREQ", astChrLen( cval ) ) ) {
- strcpy( spectype, "FREQ" );
- } else if( !strncmp( cval, "VRAD", astChrLen( cval ) ) ) {
- strcpy( spectype, "VELO" );
- } else if( !strncmp( cval, "VOPT-F2W", astChrLen( cval ) ) ) {
- strcpy( spectype, "FELO" );
- } else {
- ok = 0;
- }
- }
-
-/* If OK, check the SPECSYS value and add the AIPS equivalent onto the
- end of the CTYPE value.*/
- cval = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else {
- if( !strncmp( cval, "LSRK", astChrLen( cval ) ) ) {
- strcpy( spectype+4, "-LSR" );
- } else if( !strncmp( cval, "LSRD", astChrLen( cval ) ) ) {
- strcpy( spectype+4, "-LSD" );
- } else if( !strncmp( cval, "BARYCENT", astChrLen( cval ) ) ) {
- strcpy( spectype+4, "-HEL" );
- } else if( !strncmp( cval, "GEOCENTR", astChrLen( cval ) ) ) {
- strcpy( spectype+4, "-GEO" );
- } else {
- ok = 0;
- }
- }
-
-/* If still OK, ensure the spectral axis units are Hz or m/s. */
- cval = GetItemC( &(store->cunit), axspec, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else if( ok ) {
- if( !strcmp( cval, "Hz" ) ) {
- specunit = "HZ";
- specfactor = 1.0;
- } else if( !strcmp( cval, "kHz" ) ) {
- specunit = "HZ";
- specfactor = 1.0E3;
- } else if( !strcmp( cval, "MHz" ) ) {
- specunit = "HZ";
- specfactor = 1.0E6;
- } else if( !strcmp( cval, "GHz" ) ) {
- specunit = "HZ";
- specfactor = 1.0E9;
- } else if( !strcmp( cval, "m/s" ) ) {
- specunit = "m/s";
- specfactor = 1.0;
- } else if( !strcmp( cval, "km/s" ) ) {
- specunit = "m/s";
- specfactor = 1.0E3;
- } else {
- ok = 0;
- }
- }
- }
-
-/* If this is different to the value of NAXIS abort since this encoding
- does not support WCSAXES keyword. */
- if( naxis != store->naxis ) ok = 0;
-
-/* Allocate memory to store the CDELT values */
- if( ok ) {
- cdelt = (double *) astMalloc( sizeof(double)*naxis );
- if( !cdelt ) ok = 0;
- } else {
- cdelt = NULL;
- }
-
-/* Check that rotation is restricted to the celestial plane, and extract
- the CDELT (diagonal) terms, etc. If there are no celestial
- axes, restrict rotation to the first two non-spectral axes. */
- if( axlat < 0 && axlon < 0 ) {
- if( axspec >= 0 && naxis > 2 ) {
- axrot2 = ( axspec == 0 ) ? 1 : 0;
- axrot1 = axrot2 + 1;
- if( axrot1 == axspec ) axrot1++;
- } else if( naxis > 1 ){
- axrot2 = 0;
- axrot1 = 1;
- } else {
- axrot2 = -1;
- axrot1 = -1;
- }
- } else {
- axrot1 = axlon;
- axrot2 = axlat;
- }
- cdlat_lon = 0.0;
- cdlon_lat = 0.0;
- for( i = 0; i < naxis && ok; i++ ){
- cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
- if( cdl == AST__BAD ) cdl = 1.0;
- for( j = 0; j < naxis && ok; j++ ){
- val = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
- if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0;
- val *= cdl;
- if( i == j ){
- cdelt[ i ] = val;
- } else if( i == axrot2 && j == axrot1 ){
- cdlat_lon = val;
- } else if( i == axrot1 && j == axrot2 ){
- cdlon_lat = val;
- } else if( val != 0.0 ){
- ok = 0;
- }
- }
- }
-
-/* Find the CROTA and CDELT values for the celestial axes. */
- if( ok && axrot1 >= 0 && axrot2 >= 0 ) {
- if( cdlat_lon > 0.0 ) {
- rho_a = atan2( cdlat_lon, cdelt[ axrot1 ] );
- } else if( cdlat_lon == 0.0 ) {
- rho_a = 0.0;
- } else {
- rho_a = atan2( -cdlat_lon, -cdelt[ axrot1 ] );
- }
- if( cdlon_lat > 0.0 ) {
- rho_b = atan2( cdlon_lat, -cdelt[ axrot2 ] );
- } else if( cdlon_lat == 0.0 ) {
- rho_b = 0.0;
- } else {
- rho_b = atan2( -cdlon_lat, cdelt[ axrot2 ] );
- }
- if( fabs( palDrange( rho_a - rho_b ) ) < 1.0E-2 ){
- crota = 0.5*( palDranrm( rho_a ) + palDranrm( rho_b ) );
- coscro = cos( crota );
- sincro = sin( crota );
- if( fabs( coscro ) > fabs( sincro ) ){
- cdelt[ axrot2 ] /= coscro;
- cdelt[ axrot1 ] /= coscro;
- } else {
- cdelt[ axrot2 ] = -cdlon_lat/sincro;
- cdelt[ axrot1 ] = cdlat_lon/sincro;
- }
- crota *= AST__DR2D;
-
-/* Use AST__BAD to indicate that CDi_j values should be produced
- instead of CROTA/CDELT. (I am told AIPS++ can understand CD matrices) */
- } else {
- crota = AST__BAD;
- }
- } else {
- crota = 0.0;
- }
-
-/* Get RADECSYS and the reference equinox. */
- cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status );
- epoch = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status );
-
-/* If RADECSYS was available... */
- if( cval ){
-
-/* ICRS is not supported in this encoding. */
- if( !strcmp( "ICRS", cval ) ) ok = 0;
-
-/* If epoch was not available, set a default epoch. */
- if( epoch == AST__BAD ){
- if( !strcmp( "FK4", cval ) ){
- epoch = 1950.0;
- } else if( !strcmp( "FK5", cval ) ){
- epoch = 2000.0;
- } else {
- ok = 0;
- }
-
-/* If an equinox was supplied, check it is consistent with the IAU 1984
- rule. */
- } else {
- if( !strcmp( "FK4", cval ) ){
- if( epoch >= 1984.0 ) ok = 0;
- } else if( !strcmp( "FK5", cval ) ){
- if( epoch < 1984.0 ) ok = 0;
- } else {
- ok = 0;
- }
- }
- }
-
-/* Only create the keywords if the FitsStore conforms to the requirements
- of the FITS-AIPS++ encoding. */
- if( ok ) {
-
-/* Get and save CRPIX for all pixel axes. These are required, so break
- if they are not available. */
- for( j = 0; j < naxis && ok; j++ ){
- val = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- } else {
- sprintf( combuf, "Reference pixel on axis %d", j + 1 );
- SetValue( this, FormatKey( "CRPIX", j + 1, -1, s, status ), &val,
- AST__FLOAT, combuf, status );
- }
- }
-
-/* Get and save CRVAL for all intermediate axes. These are required, so
- break if they are not available. */
- for( i = 0; i < naxis && ok; i++ ){
- val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- } else {
- if( i == axspec ) val *= specfactor;
- sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 );
- SetValue( this, FormatKey( "CRVAL", i + 1, -1, s, status ), &val,
- AST__FLOAT, combuf, status );
- }
- }
-
-/* Get and save CTYPE for all intermediate axes. These are required, so
- break if they are not available. Use the potentially modified versions
- saved above for the celestial axes. */
- for( i = 0; i < naxis && ok; i++ ){
- if( i == axlat ) {
- cval = lattype;
- } else if( i == axlon ) {
- cval = lontype;
- } else if( i == axspec ) {
- cval = spectype;
- } else {
- cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- }
- if( cval && ( strlen(cval) < 5 || strcmp( cval + 4, "-TAB" ) ) ) {
- comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status );
- if( !comm ) {
- sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 );
- comm = combuf;
- }
- SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval,
- AST__STRING, comm, status );
- } else {
- ok = 0;
- }
- }
-
-/* CDELT values */
- if( axspec != -1 ) cdelt[ axspec ] *= specfactor;
- for( i = 0; i < naxis; i++ ){
- SetValue( this, FormatKey( "CDELT", i + 1, -1, s, status ), cdelt + i,
- AST__FLOAT, "Pixel size", status );
- }
-
-/* CUNIT values. [Spectral axis units should be upper-case] */
- for( i = 0; i < naxis; i++ ) {
- cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status );
- if( cval ) {
- if( i == axspec ) cval = specunit;
- sprintf( combuf, "Units for axis %d", i + 1 );
- SetValue( this, FormatKey( "CUNIT", i + 1, -1, s, status ), &cval, AST__STRING,
- combuf, status );
- }
- }
-
-/* CD matrix. Multiply the row of the PC matrix by the CDELT value. */
- if( crota == AST__BAD ) {
- for( i = 0; i < naxis; i++ ) {
- cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
- if( cdl == AST__BAD ) cdl = 1.0;
- for( j = 0; j < naxis; j++ ){
- val = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
- if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0;
- val *= cdl;
- if( val != 0.0 ) {
- SetValue( this, FormatKey( "CD", i + 1, j + 1, s, status ), &val,
- AST__FLOAT, "Transformation matrix element", status );
- }
- }
- }
-
-/* CROTA */
- } else if( crota != 0.0 ) {
- if( axrot2 != -1 ){
- SetValue( this, FormatKey( "CROTA", axrot2 + 1, -1, s, status ), &crota,
- AST__FLOAT, "Axis rotation", status );
- } else if( ( axspec == -1 && naxis > 1 ) ||
- ( axspec != -1 && naxis > 2 ) ) {
- SetValue( this, "CROTA1", &crota, AST__FLOAT, "Axis rotation", status );
- }
- }
-
-/* Reference equinox */
- if( epoch != AST__BAD ) SetValue( this, "EPOCH", &epoch, AST__FLOAT,
- "Epoch of reference equinox", status );
-
-/* Latitude of native north pole. */
- val = GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, "LATPOLE", &val, AST__FLOAT,
- "Latitude of native north pole", status );
-
-/* Longitude of native north pole. */
- val = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, "LONPOLE", &val, AST__FLOAT,
- "Longitude of native north pole", status );
-
-/* Date of observation. */
- val = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status );
- if( val != AST__BAD ) {
-
-/* The format used for the DATE-OBS keyword depends on the value of the
- keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format.
- Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */
- palCaldj( 99, 1, 1, &mjd99, &jj );
- if( val < mjd99 ) {
- palDjcal( 0, val, iymdf, &jj );
- sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ],
- iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) );
- } else {
- palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj );
- palDd2tf( 3, fd, sign, ihmsf );
- sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d",
- iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1],
- ihmsf[2], ihmsf[3] );
- }
-
-/* Now store the formatted string in the FitsChan. */
- cval = combuf;
- SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING,
- "Date of observation", status );
- }
-
-/* Projection parameters. */
- if( axlat >= 0 && axlon >= 0 ) {
- for( m = 0; m <= maxm; m++ ){
- val = GetItem( &(store->pv), axlat, m, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "PROJP", m, -1, ' ', status ),
- &val, AST__FLOAT, "Projection parameter", status );
- }
- }
-
-/* Spectral stuff.. */
- if( axspec >= 0 ) {
-
-/* Rest frequency */
- val = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "RESTFREQ", -1, -1, s, status ),
- &val, AST__FLOAT, "[Hz] Rest frequency", status );
- }
- }
-
-/* Release CDELT workspace */
- if( cdelt ) cdelt = (double *) astFree( (void *) cdelt );
-
-/* Return zero or ret depending on whether an error has occurred. */
- return astOK ? ok : 0;
-}
-
-static char *CardComm( AstFitsChan *this, int *status ){
-
-/*
-* Name:
-* CardComm
-
-* Purpose:
-* Return the keyword comment from the current card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* char *CardComm( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns a pointer to a string holding the keyword comment from the
-* current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the keyword comment, or NULL if the FitsChan is at
-* end-of-file, or does not have a comment.
-
-* Notes:
-* - The current card is not changed by this function.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- char *ret;
-
-/* Check the supplied object. */
- if( !this ) return NULL;
-
-/* If the current card is defined, store a pointer to its keyword comment. */
- if( this->card ){
- ret = ( (FitsCard *) this->card )->comment;
-
-/* Otherwise store a NULL pointer. */
- } else {
- ret = NULL;
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static void *CardData( AstFitsChan *this, size_t *size, int *status ){
-
-/*
-* Name:
-* CardData
-
-* Purpose:
-* Return a pointer to the keyword data value for the current card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void *CardData( AstFitsChan *this, size_t *size, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns a pointer to keyword data value from the current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* size
-* A pointer to a location at which to return the number of bytes
-* occupied by the data value. NULL can be supplied if this
-* information is not required.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the keyword data, or NULL if the FitsChan is at
-* end-of-file, or if the keyword does not have any data.
-
-* Notes:
-* - For text data, the returned value for "size" includes the
-* terminating null character.
-* - The current card is not changed by this function.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- void *ret;
-
-/* Check the supplied object. */
- if( !this ) return NULL;
-
-/* If the current card is defined, store a pointer to its keyword data. */
- if( this->card ){
- ret = ( (FitsCard *) this->card )->data;
- if( size ) *size = ( (FitsCard *) this->card )->size;
-
-/* Otherwise store a NULL pointer. */
- } else {
- ret = NULL;
- if( size ) *size = 0;
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static int *CardFlags( AstFitsChan *this, int *status ){
-
-/*
-* Name:
-* CardFlags
-
-* Purpose:
-* Return a pointer to the flags mask for the current card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int *CardFlags( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns a pointer to the flags mask for the current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The pointer to the flags mask.
-
-* Notes:
-* - The current card is not changed by this function.
-* - NULL is returned if the current card is not defined.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- int *ret;
-
-/* Check the supplied object. */
- if( !this ) return NULL;
-
-/* If the current card is defined, store its deletion flag. */
- if( this->card ){
- ret = &( ( (FitsCard *) this->card )->flags );
-
-/* Otherwise store zero. */
- } else {
- ret = NULL;
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static char *CardName( AstFitsChan *this, int *status ){
-/*
-* Name:
-* CardName
-
-* Purpose:
-* Return the keyword name from the current card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* char *CardName( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns a pointer to a string holding the keyword name from the
-* current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the keyword name, or NULL if the FitsChan is at
-* end-of-file.
-
-* Notes:
-* - The current card is not changed by this function.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- char *ret;
-
-/* Check the supplied object. */
- if( !this ) return NULL;
-
-/* If the current card is defined, store a pointer to its keyword name. */
- if( this->card ){
- ret = ( (FitsCard *) this->card )->name;
-
-/* Otherwise store a NULL pointer. */
- } else {
- ret = NULL;
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static int CardType( AstFitsChan *this, int *status ){
-/*
-* Name:
-* CardType
-
-* Purpose:
-* Return the keyword type from the current card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int CardType( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns the keyword type from the current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The keyword type.
-
-* Notes:
-* - The current card is not changed by this function.
-* - AST__NOTYPE is returned if the current card is not defined.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- int ret;
-
-/* Check the supplied object. */
- if( !this ) return AST__NOTYPE;
-
-/* If the current card is defined, store the keyword type. */
- if( this->card ){
- ret = ( (FitsCard *) this->card )->type;
-
-/* Otherwise store AST__NOTYPE. */
- } else {
- ret = AST__NOTYPE;
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static AstMapping *CelestialAxes( AstFitsChan *this, AstFrameSet *fs, double *dim,
- int *wperm, char s, FitsStore *store, int *axis_done,
- int isoff, const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* CelestialAxes
-
-* Purpose:
-* Add values to a FitsStore describing celestial axes in a Frame.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *CelestialAxes( AstFitsChan *this, AstFrameSet *fs, double *dim,
-* int *wperm, char s, FitsStore *store, int *axis_done,
-* int isoff, const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The current Frame of the supplied FrameSet is searched for celestial
-* axes. If any are found, FITS WCS keyword values describing the axis
-* are added to the supplied FitsStore, if possible (the conventions
-* of FITS-WCS paper II are used). Note, this function does not store
-* values for keywords which define the transformation from pixel
-* coords to Intermediate World Coords (CRPIX, PC and CDELT), but a
-* Mapping is returned which embodies these values. This Mapping is
-* from the current Frame in the FrameSet (WCS coords) to a Frame
-* representing IWC. The IWC Frame has the same number of axes as the
-* WCS Frame which may be greater than the number of base Frame (i.e.
-* pixel) axes.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* fs
-* Pointer to the FrameSet. The base Frame should represent FITS pixel
-* coordinates, and the current Frame should represent FITS WCS
-* coordinates. The number of base Frame axes should not exceed the
-* number of current Frame axes.
-* dim
-* An array holding the image dimensions in pixels. AST__BAD can be
-* supplied for any unknown dimensions.
-* wperm
-* Pointer to an array of integers with one element for each axis of
-* the current Frame. Each element holds the zero-based
-* index of the FITS-WCS axis (i.e. the value of "i" in the keyword
-* names "CTYPEi", "CRVALi", etc) which describes the Frame axis.
-* s
-* The co-ordinate version character. A space means the primary
-* axis descriptions. Otherwise the supplied character should be
-* an upper case alphabetical character ('A' to 'Z').
-* store
-* The FitsStore in which to store the FITS WCS keyword values.
-* axis_done
-* An array of flags, one for each Frame axis, which indicate if a
-* description of the corresponding axis has yet been stored in the
-* FitsStore.
-* isoff
-* If greater than zero, the description to add to the FitsStore
-* should describe offset coordinates. If less than zero, the
-* description to add to the FitsStore should describe absolute
-* coordinates but should include the SkyRefIs, SkyRef and SkyRefP
-* attributes. If zero, ignore all offset coordinate info. The
-* absolute value indicates the nature of the reference point:
-* 1 == "pole", 2 == "origin", otherwise "ignored".
-* 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:
-* If celestial axes were found which can be described using the
-* conventions of FITS-WCS paper II, then a Mapping from the current Frame
-* of the supplied FrameSet, to the IWC Frame is returned. Otherwise,
-* a UnitMap is returned. Note, the Mapping only defines the IWC
-* transformation for celestial axes. Any non-celestial axes are passed
-* unchanged by the returned Mapping.
-*/
-
-/* Local Variables: */
- AstFitsTable *table; /* Pointer to structure holding -TAB table info */
- AstFrame *pframe; /* Primary Frame containing current WCS axis*/
- AstFrame *wcsfrm; /* WCS Frame within FrameSet */
- AstMapping *map1; /* Pointer to pre-WcsMap Mapping */
- AstMapping *map3; /* Pointer to post-WcsMap Mapping */
- AstMapping *map; /* Pixel -> WCS mapping */
- AstMapping *ret; /* Returned Mapping */
- AstMapping *tmap0; /* A temporary Mapping */
- AstMapping *tmap1; /* A temporary Mapping */
- AstMapping *tmap2; /* A temporary Mapping */
- AstMapping *tmap3; /* A temporary Mapping */
- AstMapping *tmap4; /* A temporary Mapping */
- AstSkyFrame *skyfrm; /* The SkyFrame defining current WCS axis */
- AstWcsMap *map2; /* Pointer to WcsMap */
- AstWcsMap *map2b; /* Pointer to WcsMap with cleared lat/lonpole */
- char *cval; /* Pointer to keyword value */
- char *temp; /* Pointer to temporary string */
- double *mat; /* Pointer to matrix diagonal elements */
- double *ppcfid; /* Pointer to array holding PPC at fiducial point */
- double con; /* Constant value for unassigned axes */
- double crval[ 2 ]; /* Psi coords of reference point */
- double pv; /* Projection parameter value */
- double skyfid[ 2 ]; /* Sky coords of fiducial point */
- double val; /* Keyword value */
- int *inperm; /* Input axis permutation array */
- int *outperm; /* Output axis permutation array */
- int *tperm; /* Pointer to new FITS axis numbering array */
- int axlat; /* Index of latitude output from WcsMap */
- int axlon; /* Index of longitude output from WcsMap */
- int extver; /* Table version number for -TAB headers */
- int fits_ilat; /* FITS WCS axis index for latitude axis */
- int fits_ilon; /* FITS WCS axis index for longitude axis */
- int i; /* Loop index */
- int iax; /* Axis index */
- int icolindexlat; /* Index of table column holding lat index vector */
- int icolindexlon; /* Index of table column holding lon index vector */
- int icolmainlat; /* Index of table column holding main lat coord array */
- int icolmainlon; /* Index of table column holding main lon coord array */
- int interplat; /* INterpolation method for latitude look-up tables */
- int interplon; /* INterpolation method for longitude look-up tables */
- int ilat; /* Index of latitude axis within total WCS Frame */
- int ilon; /* Index of longitude axis within total WCS Frame */
- int j; /* Loop index */
- int m; /* Projection parameter index */
- int maxm; /* Largest used "m" value */
- int mlat; /* Index of latitude axis in main lat coord array */
- int mlon; /* Index of longitude axis in main lon coord array */
- int nwcs; /* Number of WCS axes */
- int nwcsmap; /* Number of inputs/outputs for the WcsMap */
- int paxis; /* Axis index within primary Frame */
- int skylataxis; /* Index of latitude axis within SkyFrame */
- int skylonaxis; /* Index of longitude axis within SkyFrame */
- int tpn; /* Is the WCS projectiona TPN projection? */
-
-/* Initialise */
- ret = NULL;
-
-/* Other initialisation to avoid compiler warnings. */
- mlon = 0;
- mlat = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Get a pointer to the WCS Frame. */
- wcsfrm = astGetFrame( fs, AST__CURRENT );
-
-/* Store the number of WCS axes. */
- nwcs = astGetNout( fs );
-
-/* Check each axis in the WCS Frame to see if it is a celestial axis. */
- skyfrm = NULL;
- map = NULL;
- ilon = -1;
- ilat = -1;
- for( iax = 0; iax < nwcs; iax++ ) {
-
-/* Obtain a pointer to the primary Frame containing the current WCS axis. */
- astPrimaryFrame( wcsfrm, iax, &pframe, &paxis );
-
-/* If the current axis belongs to a SkyFrame, we have found a celestial
- axis. Keep a pointer to it, and note the indices of the celestial axes
- within the complete WCS Frame. The MakeFitsFrameSet function will have
- ensured that the WCS Frame only contains at most a single SkyFrame. */
- if( IsASkyFrame( pframe ) ) {
- if( !skyfrm ) skyfrm = astClone( pframe );
- if( paxis == 0 ) {
- ilon = iax;
- } else {
- ilat = iax;
- }
-
-/* Indicate that this axis has been classified. */
- axis_done[ iax ] = 1;
- }
-
-/* Release resources. */
- pframe = astAnnul( pframe );
- }
-
-/* Only proceed if we found celestial axes. */
- if( ilon != -1 && ilat != -1 ) {
-
-/* Note the FITS WCS axis indices for the longitude and latitude axes */
- fits_ilon = wperm[ ilon ];
- fits_ilat = wperm[ ilat ];
-
-/* Create an array to hold the Projection Plane Coords corresponding to the
- CRVALi keywords. */
- ppcfid = (double *) astMalloc( sizeof( double )*nwcs );
-
-/* Get the pixel->wcs Mapping. */
- map = astGetMapping( fs, AST__BASE, AST__CURRENT );
-
-/* Get the table version number to use if we end up using the -TAB
- algorithm. This is the set value of the TabOK attribute (if positive). */
- extver = astGetTabOK( this );
-
-/* Some of the required FITS Keyword values are defined by the WcsMap
- contained within the Mapping. Split the mapping up into a list of serial
- component mappings, and locate the first WcsMap in this list. The first
- Mapping returned by this call is the result of compounding all the
- Mappings up to (but not including) the WcsMap, the second returned Mapping
- is the (inverted) WcsMap, and the third returned Mapping is anything
- following the WcsMap. Only proceed if one and only one WcsMap is found. */
- if( SplitMap( map, astGetInvert( map ), ilon, ilat, &map1, &map2, &map3,
- status ) ){
-
-/* Get the indices of the latitude and longitude axes within the SkyFrame
- (not necessarily (1,0) because they may have been permuted). */
- skylataxis = astGetLatAxis( skyfrm );
- skylonaxis = astGetLonAxis( skyfrm );
-
-/* The reference point in the celestial coordinate system is found by
- transforming the fiducial point in native spherical co-ordinates
- into WCS coordinates using map3. */
- if( GetFiducialWCS( map2, map3, ilon, ilat, skyfid + skylonaxis,
- skyfid + skylataxis, status ) ){
-
-/* We also need to find the indices of the longitude and latitude outputs
- from the WcsMap. These may not be the same as ilat and ilon because of
- axis permutations in "map3". */
- axlon = astGetWcsAxis( map2, 0 );
- axlat = astGetWcsAxis( map2, 1 );
-
-/* Normalise the latitude and longitude values at the fiducial point. The
- longitude and latitude values found above will be in radians, but after
- normalization we convert them to degrees, as expected by other functions
- which handle FitsStores. */
- if( skyfid[ skylonaxis ] == AST__BAD ) skyfid[ skylonaxis ] = 0.0;
- if( skyfid[ skylataxis ] == AST__BAD ) skyfid[ skylataxis ] = 0.0;
- if( ZEROANG( skyfid[ 0 ] ) ) skyfid[ 0 ] = 0.0;
- if( ZEROANG( skyfid[ 1 ] ) ) skyfid[ 1 ] = 0.0;
- astNorm( skyfrm, skyfid );
- SetItem( &(store->crval), fits_ilon, 0, s, AST__DR2D*skyfid[ skylonaxis ], status );
- SetItem( &(store->crval), fits_ilat, 0, s, AST__DR2D*skyfid[ skylataxis ], status );
-
-/* Set a flag if we have a TPN projection. This is an AST-specific
- projection which mimicks the old "TAN with correction terms" projection
- which was removed from the final version of the FITS-WCS paper II. */
- tpn = ( astGetWcsType( map2 ) == AST__TPN );
-
-/* Store the WCS projection parameters. Except for TPN projections, always
- exclude parameters 3 and 4 on the longitude axis since these are
- reserved to hold copies of LONPOLE and LATPOLE. */
- for( m = 0; m < WCSLIB_MXPAR; m++ ){
- if( astTestPV( map2, axlon, m ) ) {
- if( m < 3 || m > 4 || tpn ) {
- pv = astGetPV( map2, axlon, m );
- if( pv != AST__BAD ) SetItem( &(store->pv), fits_ilon, m,
- s, pv, status );
- }
- }
- if( astTestPV( map2, axlat, m ) ) {
- pv = astGetPV( map2, axlat, m );
- if( pv != AST__BAD ) SetItem( &(store->pv), fits_ilat, m,
- s, pv, status );
- }
- }
-
-/* If PVi_0 (for the longitude axis) is non-zero, the Cartesian coordinates
- used by the WcsMap (Projection Plane Coordinates, PPC) need to be shifted
- to produce Intermediate World Coordinates (IWC). This shift results in
- the pixel reference position specified by the CRPIXi values (and which
- corresponds to the origin of IWC) mapping on to the fiducial position
- specified by the CRVALi values. The required shifts are just the PPC
- coordinates of the fiducial point. The AST-specific "TPN" projection uses
- longitude projection parameters to define correction terms, and so cannot
- use the above convention (which is part of FITS-WCS paper II). Therefore
- TPN projections always use zero shift between PPC and IWC. */
- for( iax = 0; iax < nwcs; iax++ ) ppcfid[ iax ] = 0.0;
- if( !tpn && astGetPV( map2, axlon, 0 ) != 0.0 ) {
- GetFiducialPPC( (AstWcsMap *) map2, ppcfid + ilon, ppcfid + ilat, status );
- if( ppcfid[ ilon ] == AST__BAD ) ppcfid[ ilon ] = 0.0;
- if( ppcfid[ ilat ] == AST__BAD ) ppcfid[ ilat ] = 0.0;
- ppcfid[ ilon ] *= AST__DR2D;
- ppcfid[ ilat ] *= AST__DR2D;
- }
-
-/* Store the CTYPE, CNAME, EQUINOX, MJDOBS, and RADESYS values. */
- SkySys( this, skyfrm, 1, astGetWcsType( map2 ), store, fits_ilon,
- fits_ilat, s, isoff, method, class, status );
-
-/* Store the LONPOLE and LATPOLE values in the FitsStore. */
- SkyPole( map2, map3, ilon, ilat, wperm, s, store, method, class, status );
-
-/* The values of LONPOLE and LATPOLE stored above (in the FitsStore) will be
- ignored by WcsNative if the WcsMap contains set values for projection
- parameters PVi_3a and/or PVi_4a (these will be used in preference to
- the values in the FitsStore). To avoid this happening we take a copy
- of the WcsMap and clear the relevant parameters (but not if the WcsMap is
- for a TPN projection because TPN uses PVi_3a and PVi_4a for other
- purposes). */
- if( astGetWcsType( map2 ) != AST__TPN ) {
- map2b = astCopy( map2 );
- astClearPV( map2b, axlon, 3 );
- astClearPV( map2b, axlon, 4 );
- } else {
- map2b = astClone( map2 );
- }
-
-/* We will now create the Mapping from WCS coords to IWC coords. In fact,
- we produce the Mapping from IWC to WCS and then invert it. Create the
- first component of this Mapping which implements any shift of origin
- from IWC to PPC. */
- tmap0 = (AstMapping *) astShiftMap( nwcs, ppcfid, "", status );
-
-/* The next component of this Mapping scales the PPC coords from degrees
- to radians on the celestial axes. */
- mat = astMalloc( sizeof( double )*(size_t) nwcs );
- if( astOK ) {
- for( iax = 0; iax < nwcs; iax++ ) mat[ iax ] = 1.0;
- mat[ ilon ] = AST__DD2R;
- mat[ ilat ] = AST__DD2R;
- tmap1 = (AstMapping *) astMatrixMap( nwcs, nwcs, 1, mat, "", status );
- mat = astFree( mat );
- } else {
- tmap1 = NULL;
- }
-
-/* Now create the Mapping from Native Spherical Coords to WCS. */
- tmap2 = WcsNative( NULL, store, s, map2b, fits_ilon, fits_ilat,
- method, class, status );
-
-/* Combine the WcsMap with the above Mapping, to get the Mapping from PPC
- to WCS. */
- tmap3 = (AstMapping *) astCmpMap( map2b, tmap2, 1, "", status );
- tmap2 = astAnnul( tmap2 );
-
-/* If there are more WCS axes than IWC axes, create a UnitMap for the extra
- WCS axes and add it in parallel with tmap3. */
- nwcsmap = astGetNin( map3 );
- if( nwcsmap < nwcs ) {
- tmap2 = (AstMapping *) astUnitMap( nwcs - nwcsmap, "", status );
- tmap4 = (AstMapping *) astCmpMap( tmap3, tmap2, 0, "", status );
- tmap3 = astAnnul( tmap3 );
- tmap2 = astAnnul( tmap2 );
- tmap3 = tmap4;
- nwcsmap = nwcs;
- }
-
-/* The pixel->wcs mapping may include a PermMap which selects some sub-set
- or super-set of the orignal WCS axes. In this case the number of inputs
- and outputs for "tmap3" created above may not equal "nwcs". To avoid this,
- we embed "tmap3" between 2 PermMaps which select the required axes. */
- if( nwcsmap != nwcs || ilon != axlon || ilat != axlat ) {
- inperm = astMalloc( sizeof( int )*(size_t) nwcs );
- outperm = astMalloc( sizeof( int )*(size_t) nwcsmap );
- if( astOK ) {
-
-/* Indicate that no inputs of the PermMap have yet been assigned to any
- outputs */
- for( i = 0; i < nwcs; i++ ) inperm[ i ] = -1;
-
-/* Assign the WcsMap long/lat axes to the WCS Frame long/lat axes */
- inperm[ ilon ] = axlon;
- inperm[ ilat ] = axlat;
-
-/* Assign the remaining inputs arbitrarily (doesn't matter how we do this
- since the WcsMap is effectively a UnitMap on all non-celestial axes). */
- iax = 0;
- for( i = 0; i < nwcs; i++ ) {
- while( iax == axlon || iax == axlat ) iax++;
- if( inperm[ i ] == -1 ) inperm[ i ] = iax++;
- }
-
-/* Do the same for the outputs. */
- for( i = 0; i < nwcsmap; i++ ) outperm[ i ] = -1;
- outperm[ axlon ] = ilon;
- outperm[ axlat ] = ilat;
- iax = 0;
- for( i = 0; i < nwcsmap; i++ ) {
- while( iax == ilon || iax == ilat ) iax++;
- if( outperm[ i ] == -1 ) outperm[ i ] = iax++;
- }
-
-/* Create the PermMap. */
- con = AST__BAD;
- tmap2 = (AstMapping *) astPermMap( nwcs, inperm, nwcsmap,
- outperm, &con, "", status );
-
-/* Sandwich the WcsMap between the PermMap and its inverse. */
- tmap4 = (AstMapping *) astCmpMap( tmap2, tmap3, 1, "", status );
- tmap3 = astAnnul( tmap3 );
- astInvert( tmap2 );
- tmap3 = (AstMapping *) astCmpMap( tmap4, tmap2, 1, "", status );
- tmap2 = astAnnul( tmap2 );
- tmap4 = astAnnul( tmap4 );
- }
- inperm = astFree( inperm );
- outperm = astFree( outperm );
- }
-
-/* Combine these Mappings together. */
- tmap4 = (AstMapping *) astCmpMap( tmap0, tmap1, 1, "", status );
- tmap0 = astAnnul( tmap0 );
- tmap1 = astAnnul( tmap1 );
- ret = (AstMapping *) astCmpMap( tmap4, tmap3, 1, "", status );
- tmap3 = astAnnul( tmap3 );
- tmap4 = astAnnul( tmap4 );
-
-/* Invert this Mapping to get the Mapping from WCS to IWC. */
- astInvert( ret );
-
-/* The spherical rotation involved in converting WCS to IWC can result in
- inappropriate numbering of the FITS axes. For instance, a LONPOLE
- value of 90 degrees causes the IWC axes to be transposed. For this
- reason we re-asses the FITS axis numbers assigned to the celestial
- axes in order to make the IWC axes as close as possible to the pixel
- axes with the same number (but only if the axis order is being
- determined automatically). To do this, we need the Mapping from
- pixel to IWC, which is formed by concatenating the pixel->WCS
- Mapping with the WCS->IWC Mapping. */
- if( astChrMatch( astGetFitsAxisOrder( this ), "<auto>" ) ) {
- tmap0 = (AstMapping *) astCmpMap( map, ret, 1, "", status );
-
-/* Find the outputs of this Mapping which should be associated with each
- input. */
- tperm = astMalloc( sizeof(int)*(size_t) nwcs );
- if( ! WorldAxes( this, tmap0, dim, tperm, status ) ) {
- ret = astAnnul( ret );
- }
-
-/* If the index associated with the celestial axes appear to have been
- swapped... */
- if( ret && astOK && fits_ilon == tperm[ ilat ] &&
- fits_ilat == tperm[ ilon ] ) {
-
-/* Swap the fits axis indices associated with each WCS axis to match. */
- wperm[ ilon ] = fits_ilat;
- wperm[ ilat ] = fits_ilon;
-
-/* Swap the stored CRVAL value for the longitude and latitude axis. */
- val = GetItem( &(store->crval), fits_ilat, 0, s, NULL, method, class, status );
- SetItem( &(store->crval), fits_ilat, 0, s,
- GetItem( &(store->crval), fits_ilon, 0, s, NULL,
- method, class, status ), status );
- SetItem( &(store->crval), fits_ilon, 0, s, val, status );
-
-/* Swap the stored CTYPE value for the longitude and latitude axis. */
- cval = GetItemC( &(store->ctype), fits_ilat, 0, s, NULL, method, class, status );
- if( cval ) {
- temp = astStore( NULL, (void *) cval, strlen( cval ) + 1 );
- cval = GetItemC( &(store->ctype), fits_ilon, 0, s, NULL, method, class, status );
- if( cval ) {
- SetItemC( &(store->ctype), fits_ilat, 0, s, cval, status );
- SetItemC( &(store->ctype), fits_ilon, 0, s, temp, status );
- }
- temp = astFree( temp );
- }
-
-/* Swap the stored CNAME value for the longitude and latitude axis. */
- cval = GetItemC( &(store->cname), fits_ilat, 0, s, NULL, method, class, status );
- if( cval ) {
- temp = astStore( NULL, (void *) cval, strlen( cval ) + 1 );
- cval = GetItemC( &(store->cname), fits_ilon, 0, s, NULL, method, class, status );
- if( cval ) {
- SetItemC( &(store->cname), fits_ilat, 0, s, cval, status );
- SetItemC( &(store->cname), fits_ilon, 0, s, temp, status );
- }
- temp = astFree( temp );
- }
-
-/* Swap the projection parameters asociated with the longitude and latitude
- axes. */
- maxm = GetMaxJM( &(store->pv), s, status );
- for( m = 0; m <= maxm; m++ ){
- val = GetItem( &(store->pv), fits_ilat, m, s, NULL, method, class, status );
- SetItem( &(store->pv), fits_ilat, m, s,
- GetItem( &(store->pv), fits_ilon, m, s, NULL,
- method, class, status ), status );
- SetItem( &(store->pv), fits_ilon, m, s, val, status );
- }
- }
-
-/* Release resources. */
- tperm = astFree( tperm );
- tmap0 = astAnnul( tmap0 );
- }
- map2b = astAnnul( map2b );
- }
-
-/* Release resources. */
- map1 = astAnnul( map1 );
- map2 = astAnnul( map2 );
- map3 = astAnnul( map3 );
-
-/* If no WcsMap was found in the pixel->WCS Mapping, it may be possible
- to describe the celestial axes using a tabular look-up table (i.e. the
- FITS-WCS "_TAB" algorithm). Only do this if the -TAB algorithm is to
- be supported. */
- } else if( extver > 0 ) {
-
-/* Get any pre-existing FitsTable from the FitsStore. This is the table
- in which the tabular data will be stored (if the Mapping can be expressed
- in -TAB form). */
- if( !astMapGet0A( store->tables, AST_TABEXTNAME, &table ) ) table = NULL;
-
-/* See if the transformations for the celestial axes can be expressed in -TAB
- form. The returned Mapping (if any) is the Mapping from (lon,lat)
- (rads) to (psi_lon,psi_lat) (pixels). See FITS-WCS paper III section 6.1.2
- for definition of psi. Scale the values stored in the table from radians
- to degrees. */
- tmap0 = IsMapTab2D( map, AST__DR2D, "deg", wcsfrm, dim, ilon, ilat,
- fits_ilon, fits_ilat, &table, &icolmainlon,
- &icolmainlat, &icolindexlon, &icolindexlat,
- &mlon, &mlat, &interplon, &interplat, status );
- if( tmap0 ) {
-
-/* Store the CTYPE, CNAME, EQUINOX, MJDOBS, and RADESYS values. */
- SkySys( this, skyfrm, 0, 0, store, fits_ilon, fits_ilat, s, isoff,
- method, class, status );
-
-/* If possible, choose the two CRVAL values (which are values on the psi
- axes) so that transforming them using the Mapping returned by
- IsMapTab2D gives the sky reference position stored in the SkyFrame.
- Check the SkyFrame has a defined reference position. */
- if( astTestSkyRef( skyfrm, 0 ) && astTestSkyRef( skyfrm, 1 ) ){
-
-/* Get the longitude and latitude at the reference point in radians. */
- skyfid[ 0 ] = astGetSkyRef( skyfrm, astGetLonAxis( skyfrm ));
- skyfid[ 1 ] = astGetSkyRef( skyfrm, astGetLatAxis( skyfrm ));
-
-/* We use the WCS->psi Mapping to convert the reference point WCS coords
- (rads) into psi coords (pixels). We can only do this if the WCS->psi
- Mapping has a defined forward transformation. */
- if( astGetTranForward( tmap0 ) ) {
- astTran2( tmap0, 1, skyfid, skyfid + 1, 1, crval,
- crval + 1 );
-
-/* If the WCS->psi mapping has an undefined forward transformation, then
- just store the sky reference point coords (in degs) in keywords
- AXREFn, and use 1.0 for the CRVAL values, so that IWC becomes equal
- to (psi-1) i.e. (grid coords - 1). This means the reference point is
- at grid coords (1.0,1.0). Note this choice of 1.0 for CRVAL is not
- arbitrary since it is required by the trick used to create invertable CD
- matrix in function MakeInvertable. */
- } else {
- SetItem( &(store->axref), fits_ilon, 0, s,
- AST__DR2D*skyfid[ 0 ], status );
- SetItem( &(store->axref), fits_ilat, 0, s,
- AST__DR2D*skyfid[ 1 ], status );
- crval[ 0 ] = 1.0;
- crval[ 1 ] = 1.0;
- }
-
-/* If the SkyFrame has no reference position, use 1.0 for the CRVAL values. */
- } else {
- crval[ 0 ] = 1.0;
- crval[ 1 ] = 1.0;
- }
-
-/* Create a Mapping that describes the transformation from the lon and lat
- psi axes to the lon and lat IWC axes (i.e. a ShiftMap that just subtracts
- the CRVAL values from each axis). */
- crval[ 0 ] = -crval[ 0 ];
- crval[ 1 ] = -crval[ 1 ];
- tmap1 = (AstMapping *) astShiftMap( 2, crval, " ", status );
- crval[ 0 ] = -crval[ 0 ];
- crval[ 1 ] = -crval[ 1 ];
-
-/* Create a series compound Mapping that applies the Mapping returned
- by IsMapTab2D first (the Mapping from WCS to psi), followed by the
- Mapping from psi to IWC created above. There-after, use this compound
- Mapping in place of the Mapping returned by IsMapTab2D. It maps WCS to
- IWC. */
- tmap2 = (AstMapping *) astCmpMap( tmap0, tmap1, 1, " ", status );
- (void) astAnnul( tmap0 );
- tmap1 = astAnnul( tmap1 );
- tmap0 = tmap2;
-
-/* Store the CRVAL values */
- SetItem( &(store->crval), fits_ilon, 0, s, crval[ 0 ], status );
- SetItem( &(store->crval), fits_ilat, 0, s, crval[ 1 ], status );
-
-/* Store TAB-specific values in the FitsStore. First the name of the
- FITS binary table extension holding the coordinate info. */
- SetItemC( &(store->ps), fits_ilon, 0, s, AST_TABEXTNAME, status );
- SetItemC( &(store->ps), fits_ilat, 0, s, AST_TABEXTNAME, status );
-
-/* Next the table version number. This is the set (positive) value for the
- TabOK attribute. */
- SetItem( &(store->pv), fits_ilon, 1, s, extver, status );
- SetItem( &(store->pv), fits_ilat, 1, s, extver, status );
-
-/* Also store the table version in the binary table header. */
- astSetFitsI( table->header, "EXTVER", extver, "Table version number",
- 0 );
-
-/* Next the name of the table column containing the main coords array. */
- SetItemC( &(store->ps), fits_ilon, 1, s,
- astColumnName( table, icolmainlon ), status );
- SetItemC( &(store->ps), fits_ilat, 1, s,
- astColumnName( table, icolmainlat ), status );
-
-/* Next the name of the column containing the index array. */
- if( icolindexlon >= 0 ) SetItemC( &(store->ps), fits_ilon, 2, s,
- astColumnName( table, icolindexlon ), status );
- if( icolindexlat >= 0 ) SetItemC( &(store->ps), fits_ilat, 2, s,
- astColumnName( table, icolindexlat ), status );
-
-/* The one-based index of the axes within the coordinate array that
- describes FITS WCS axes "fits_ilon" and "fits_ilat". */
- SetItem( &(store->pv), fits_ilon, 3, s, mlon, status );
- SetItem( &(store->pv), fits_ilat, 3, s, mlat, status );
-
-/* The interpolation method (an AST extension to the published -TAB
- algorithm, communicated through the QVi_4a keyword). */
- SetItem( &(store->pv), fits_ilon, 4, s, interplon, status );
- SetItem( &(store->pv), fits_ilat, 4, s, interplat, status );
-
-/* Also store the FitsTable itself in the FitsStore. */
- astMapPut0A( store->tables, AST_TABEXTNAME, table, NULL );
-
-/* Allocate space for the arrays that define the permutations required
- for the inputs and outputs of a PermMap. */
- inperm = astMalloc( sizeof( double )*nwcs );
- outperm = astMalloc( sizeof( double )*nwcs );
- if( astOK ) {
-
-/* Create the WCS -> IWC Mapping. First create a parallel CmpMap that
- combines the Mapping returned by IsMapTab2D (which transforms the celestial
- axes), with a UnitMap which transforms the non-celestial axes. */
- if( nwcs > 2 ) {
- tmap1 = (AstMapping *) astUnitMap( nwcs - 2, " ", status );
- tmap2 = (AstMapping *) astCmpMap( tmap0, tmap1, 0, " ", status );
- tmap1 = astAnnul( tmap1 );
- } else {
- tmap2 = astClone( tmap0 );
- }
-
-/* Now create a PermMap that permutes the inputs of this CmpMap into the
- order of the axes in the WCS Frame. */
- outperm[ 0 ] = ilon;
- outperm[ 1 ] = ilat;
- j = 0;
- for( i = 2; i < nwcs; i++ ) {
- while( j == ilon || j == ilat ) j++;
- outperm[ i ] = j++;
- }
- for( i = 0; i < nwcs; i++ ) inperm[ outperm[ i ] ] = i;
- tmap1 = (AstMapping *) astPermMap( nwcs, inperm, nwcs, outperm,
- NULL, " ", status );
-
-/* Use this PermMap (and its inverse) to permute the inputs (and outputs)
- of the parallel CmpMap created above. */
- tmap3 = (AstMapping *) astCmpMap( tmap1, tmap2, 1, " ", status );
- tmap2 = astAnnul( tmap2 );
- astInvert( tmap1 );
- tmap2 = (AstMapping *) astCmpMap( tmap3, tmap1, 1, " ", status );
- tmap1 = astAnnul( tmap1 );
- tmap3 = astAnnul( tmap3 );
-
-/* Now create a PermMap that permutes the WCS axes into the FITS axis order. */
- for( i = 0; i < nwcs; i++ ) {
- inperm[ i ] = wperm[ i ];
- outperm[ wperm[ i ] ] = i;
- }
- tmap1 = (AstMapping *) astPermMap( nwcs, inperm, nwcs, outperm,
- NULL, "", status );
-
-/* Use this PermMap to permute the outputs of the "tmap2" Mapping. The
- resulting Mapping is the Mapping from the current Frame to IWC and is
- the Mapping to be returned as the function value. */
- ret = (AstMapping *) astCmpMap( tmap2, tmap1, 1, " ", status );
- tmap1 = astAnnul( tmap1 );
- tmap2 = astAnnul( tmap2 );
- }
-
-/* Free remaining resources. */
- inperm = astFree( inperm );
- outperm = astFree( outperm );
- tmap0 = astAnnul( tmap0 );
- }
- if( table ) table = astAnnul( table );
- }
-
-/* Release resources. */
- ppcfid = astFree( ppcfid );
- }
-
-/* Release resources. */
- wcsfrm = astAnnul( wcsfrm );
- if( skyfrm ) skyfrm = astAnnul( skyfrm );
- if( map ) map = astAnnul( map );
-
-/* If we have a Mapping to return, simplify it. Otherwise, create
- a UnitMap to return. */
- if( ret ) {
- tmap0 = ret;
- ret = astSimplify( tmap0 );
- tmap0 = astAnnul( tmap0 );
- } else {
- ret = (AstMapping *) astUnitMap( nwcs, "", status );
- }
-
-/* Return the result. */
- return ret;
-}
-
-static void ChangePermSplit( AstMapping *map, int *status ){
-/*
-* Name:
-* ChangePermSplit
-
-* Purpose:
-* Change all PermMaps in a Mapping to use the alternate
-* implementation of the astMapSplit method.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void ChangePermSplit( AstMapping *map, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The PemMap class provides two implementations of the astMapSplit
-* method. The implementation used by each PermMap is determined by
-* the value of the PermMap's "PermSplit" attribute. This function
-* searches the supplied Mapping for any PermMaps, and set their
-* PermSplit attribute to 1, indicating that the alternate
-* implementation of astMapSplit should be used.
-
-* Parameters:
-* map
-* Pointer to the Mapping. Modified on exit by setting all
-* PermSplit attributes to 1.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- AstMapping *map1;
- AstMapping *map2;
- int series;
- int invert1;
- int invert2;
-
-/* Check inherited status */
- if( !astOK ) return;
-
-/* If the supplied Mapping is a PermMap, set its PermSplit attribute
- non-zero. */
- if( astIsAPermMap( map ) ) {
- astSetPermSplit( map, 1 );
-
-/* If the supplied Mapping is not a PermMap, attempt to decompose the
- Mapping into two component Mappings. */
- } else {
- astDecompose( map, &map1, &map2, &series, &invert1, &invert2 );
-
-/* If the Mapping could be decomposed, use this function recursively to
- set the PermSplit attributes in each component Mapping. */
- if( map1 && map2 ) {
- ChangePermSplit( map1, status );
- ChangePermSplit( map2, status );
-
-/* Annul the component Mappings. */
- map1 = astAnnul( map1 );
- map2 = astAnnul( map2 );
- } else if( map1 ) {
- map1 = astAnnul( map1 );
- } else if( map2 ) {
- map2 = astAnnul( map2 );
- }
- }
-}
-
-static double *Cheb2Poly( double *c, int nx, int ny, double xmin, double xmax,
- double ymin, double ymax, int *status ){
-/*
-* Name:
-* Cheb2Poly
-
-* Purpose:
-* Converts a two-dimensional Chebyshev polynomial to standard form and
-* scale the arguments.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* double *Cheb2Poly( double *c, int nx, int ny, double xmin, double xmax,
-* double ymin, double ymax, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* Given the coefficients of a two-dimensional Chebychev polynomial P(u,v),
-* find the coefficients of the equivalent standard two-dimensional
-* polynomial Q(x,y). The allowed range of u and v is assumed to be the
-* unit square, and this maps on to the rectangle in (x,y) given by
-* (xmin:xmax,ymin:ymax).
-
-* Parameters:
-* c
-* An array of (nx,ny) elements supplied holding the coefficients of
-* P, such that the coefficient of (Ti(u)*Tj(v)) is held in element
-* (i + j*nx), where "Ti(u)" is the Chebychev polynomial (of the
-* first kind) of order "i" evaluated at "u", and "Tj(v)" is the
-* Chebychev polynomial of order "j" evaluated at "v".
-* nx
-* One more than the maximum power of u within P.
-* ny
-* One more than the maximum power of v within P.
-* xmin
-* X value corresponding to u = -1
-* xmax
-* X value corresponding to u = +1
-* ymin
-* Y value corresponding to v = -1
-* ymax
-* Y value corresponding to v = +1
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to a dynamically allocated array of (nx,ny) elements holding
-* the coefficients of Q, such that the coefficient of (x^i*y^j) is held
-* in element (i + j*nx). Free it using astFree when no longer needed.
-*/
-
-/* Local Variables: */
- double *d;
- double *pa;
- double *pw;
- double *work1;
- double *work2;
- double *work3;
- int *iw1;
- int *iw2;
- int i;
- int j;
-
-/* Check the status and supplied value pointer. */
- if( !astOK ) return NULL;
-
-/* Allocate returned array. */
- d = astMalloc( sizeof( *d )*nx*ny );
-
-/* Allocate workspace. */
- work1 = astMalloc( sizeof( *work1 )*ny );
- work2 = astMalloc( sizeof( *work2 )*ny );
- work3 = astMalloc( sizeof( *work2 )*nx );
- iw1 = astMalloc( sizeof(int)*( nx > ny ? nx : ny ) );
- iw2 = astMalloc( sizeof(int)*( nx > ny ? nx : ny ) );
- if( astOK ) {
-
-/* Thinking of P as a 1D polynomial in v, each coefficient would itself then
- be a 1D polynomial in u:
-
- P = ( c[0] + c[1]*T1(u) + c[2]*T2(u) + ... ) +
- ( c[nx] + c[nx+1]*T1(u) + c[nx+2]*T2(u) + ... )*T1(v) +
- (c[2*nx] + c[2*nx+1]*T1(u) + c[2*nx+2]*T2(u) + ... )*T2(v) +
- ...
- (c[(ny-1)*nx] + c[(ny-1)*nx+1]*T1(u) + c[(ny-1)*nx+2]*T2(u) + ... )T{ny-1}(v)
-
- Use Chpc1 to convert these "polynomial coefficients" to standard
- form, storing the result in the corresponding row of "d" . Also,
- convert them from u to x. */
-
- for( j = 0; j < ny; j++ ) {
- Chpc1( c + j*nx, work3, nx, iw1, iw2, status );
- Shpc1( xmin, xmax, nx, work3, d + j*nx, status );
- }
-
-/* The polynomial value is now:
-
- ( d[0] + d[1]*x + d[2]*x*x + ... ) +
- ( d[nx] + d[nx+1]*x + d[nx+2]*x*x + ... )*T1(v) +
- (d[2*nx] + d[2*nx+1]*x + d[2*nx+2]*x*x + ... )*T2(v) +
- ...
- (d[(ny-1)*nx] + d[(ny-1)*nx+1]*x + d[(ny-1)*nx+2]*x*x + ... )*T{ny-1}(v)
-
- If we rearrange this expression to view it as a 1D polynomial in x,
- rather than v, each coefficient of the new 1D polynomial is then
- itself a polynomial in v:
-
- ( d[0] + d[nx]*T1(v) + d[2*nx]*T2(v) + ... d[(ny-1)*nx]*T{ny-1}(v) ) +
- ( d[1] + d[nx+1]*T1(v) + d[2*nx+1]*T2(v) + ... d[(ny-1)*nx+1]T{ny-1}(v)... )*x +
- ( d[2] + d[nx+2]*T1(v) + d[2*nx+2]*T2(v) + ... d[(ny-1)*nx+2]T{ny-1}(v)... )*x*x +
- ...
- ( d[nx-1] + d[2*nx-1]*T1(v) + d[3*nx-1]*T2(v) + ... d[ny*nx-1]*T{ny-1}(v) )*x*x*...
-
-
- Now use Chpc1 to convert each of these "polynomial coefficients"
- to standard form. We copy each column of the d array into a 1D work array,
- use Shpc1 to modify the values in the work array, and then write
- the modified values back into the current column of d. Also convert
- from v to y. */
-
- for( i = 0; i < nx; i++ ) {
- pa = d + i;
- pw = work1;
- for( j = 0; j < ny; j++ ) {
- *(pw++) = *pa;
- pa += nx;
- }
-
- Chpc1( work1, work2, ny, iw1, iw2, status );
- Shpc1( ymin, ymax, ny, work2, work1, status );
-
- pa = d + i;
- pw = work1;
- for( j = 0; j < ny; j++ ) {
- *pa = *(pw++);
- pa += nx;
- }
- }
-
-/* So the polynomial is now:
-
- ( d[0] + d[nx]*y + d[2*nx]*y*y + ... d[(ny-1)*nx]*y*y*... ) +
- ( d[1] + d[nx+1]*y + d[2*nx+1]*y*y + ... d[(ny-1)*nx+1]*y*y*... )*x +
- ( d[2] + d[nx+2]*y + d[2*nx+2]*y*y + ... d[(ny-1)*nx+2]*y*y*... )*x*x +
- ...
- ( d[nx-1] + d[2*nx-1]*y + d[3*nx-1]*y*y + ... d[ny*nx-1]*y*y*... )*x*x*...
-
- Re-arranging, this is:
-
- ( d[0] + d[1]*x + d[2]*x*x + ... ) +
- ( d[nx] + d[nx+1]*x + d[nx+2]*x*x + ... )*y +
- (d[2*nx] + d[2*nx+1]*x + d[2*nx+2]*x*x + ... )*y*y +
- ...
- (d[(ny-1)*nx] + d[(ny-1)*nx+1]*x + d[(ny-1)*nx+2]*x*x + ... )*y*y*...
-
- as required. */
-
- }
-
-/* Free the workspace. */
- work1 = astFree( work1 );
- work2 = astFree( work2 );
- work3 = astFree( work3 );
- iw1 = astFree( iw1 );
- iw2 = astFree( iw2 );
-
-/* Return the result. */
- return d;
-}
-
-static int CheckFitsName( AstFitsChan *this, const char *name,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* CheckFitsName
-
-* Purpose:
-* Check a keyword name conforms to FITS standards.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int CheckFitsName( AstFitsChan *this, const char *name, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* FITS keywords must contain between 1 and 8 characters, and each
-* character must be an upper-case Latin alphabetic character, a digit,
-* an underscore, or a hyphen. Leading, trailing or embedded white space
-* is not allowed, with the exception of totally blank or null keyword
-* names.
-*
-* If the supplied keyword name is invalid, either a warning is issued
-* (for violations that can be handled - such as illegal characters in
-* keywords), or an error is reported (for more major violations such
-* as the keyname containing an equals sign).
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a string holding the name to check.
-* 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 value of 0 is returned if the supplied name was blank. A value of 1
-* is returned otherwise.
-
-* Notes:
-* - An error is reported if the supplied keyword name does not
-* conform to FITS requirements, and zero is returned.
-*/
-
-/* Local Variables: */
- char buf[100]; /* Buffer for warning text */
- const char *c; /* Pointer to next character in name */
- size_t n; /* No. of characters in supplied name */
- int ret; /* Returned value */
-
-/* Check the global status. */
- if( !astOK ) return 0;
-
-/* Initialise the returned value to indicate that the supplied name was
- blank. */
- ret = 0;
-
-/* Check that the supplied pointer is not NULL. */
- if( name ){
-
-/* Get the number of characters in the name. */
- n = strlen( name );
-
-/* Report an error if the name has too many characters in it. */
- if( n > FITSNAMLEN ){
- astError( AST__BDFTS, "%s(%s): The supplied FITS keyword name ('%s') "
- "has %d characters. FITS only allows up to %d.", status, method,
- class, name, (int) n, FITSNAMLEN );
-
-/* If the name has no characters in it, then assume it is a legal blank
- keyword name. Otherwise, check that no illegal characters occur in the
- name. */
- } else if( n != 0 ) {
-
-/* Whitespace is only allowed in the special case of a name consisting
- entirely of whitespace. Such keywords are used to indicate that the rest
- of the card is a comment. Find the first non-whitespace character in the
- name. */
- c = name;
- while( isspace( ( int ) *(c++) ) );
-
-/* If the name is filled entirely with whitespace, then the name is acceptable
- as the special case. Otherwise, we need to do more checks. */
- if( c - name - 1 < n ){
-
-/* Indicate that the supplied name is not blank. */
- ret = 1;
-
-/* Loop round every character checking that it is one of the legal characters.
- Report an error if any illegal characters are found. */
- c = name;
- while( *c ){
- if( !isFits( (int) *c ) ){
- if( *c == '=' ){
- astError( AST__BDFTS, "%s(%s): An equals sign ('=') was found "
- "before column %d within a FITS keyword name or header "
- "card.", status, method, class, FITSNAMLEN + 1 );
-
- } else if( *c < ' ' ) {
- sprintf( buf, "The FITS keyword name ('%s') contains an "
- "illegal non-printing character (ascii value "
- "%d).", name, *c );
- Warn( this, "badkeyname", buf, method, class, status );
-
-
- } else if( *c > ' ' ) {
- sprintf( buf, "The FITS keyword name ('%s') contains an "
- "illegal character ('%c').", name, *c );
- Warn( this, "badkeyname", buf, method, class, status );
- }
- break;
- }
- c++;
- }
- }
- }
-
-/* Report an error if no pointer was supplied. */
- } else if( astOK ){
- astError( AST__INTER, "CheckFitsName(%s): AST internal error; a NULL "
- "pointer was supplied for the keyword name. ", status,
- astGetClass( this ) );
- }
-
-/* If an error has occurred, return 0. */
- if( !astOK ) ret = 0;
-
-/* Return the answer. */
- return ret;
-}
-
-static void CheckZero( char *text, double value, int width, int *status ){
-/*
-* Name:
-* CheckZero
-
-* Purpose:
-* Ensure that the formatted value zero has no minus sign.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void CheckZero( char *text, double value, int width, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* There is sometimes a problem (perhaps only on DEC UNIX) when formatting
-* the floating-point value 0.0 using C. Sometimes it gives the string
-* "-0". This function fixed this by checking the first character of
-* the supplied string (if the supplied value is zero), and shunting the
-* remaining text one character to the right if it is a minus sign. It
-* returns without action if the supplied value is not zero.
-*
-* In addition, this function also rounds out long sequences of
-* adjacent zeros or nines in the number.
-
-* Parameters:
-* text
-* The formatted value.
-* value
-* The floating value which was formatted.
-* width
-* The minimum field width to use. The value is right justified in
-* this field width. Ignored if zero.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- char *c;
-
-/* Return if no text was supplied. */
- if( !text ) return;
-
-/* If the numerical value is zero, check for the leading minus sign. */
- if( value == 0.0 ) {
-
-/* Find the first non-space character. */
- c = text;
- while( *c && isspace( (int) *c ) ) c++;
-
-/* If the first non-space character is a minus sign, replace it with a
- space. */
- if( *c == '-' ) *c = ' ';
-
-/* Otherwise, round out sequences of zeros or nines. */
- } else {
- RoundFString( text, width, status );
- }
-}
-
-static double ChooseEpoch( AstFitsChan *this, FitsStore *store, char s,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* ChooseEpoch
-
-* Purpose:
-* Choose a FITS keyword value to use for the AST Epoch attribute.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* double ChooseEpoch( AstFitsChan *this, FitsStore *store, char s,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function returns an MJD value in the TDB timescale, which can
-* be used as the Epoch value in an AST Frame. It uses the following
-* preference order: secondary MJD-AVG, primary MJD-AVG, secondary MJD-OBS,
-* primary MJD-OBS. Note, DATE-OBS keywords are converted into MJD-OBS
-* keywords by the SpecTrans function before this function is called.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* A structure containing values for FITS keywords relating to
-* the World Coordinate System.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* method
-* The calling method. Used only in error messages.
-* class
-* The object class. Used only in error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The MJD value.
-
-* Notes:
-* - A value of AST__BAD is returned if an error occurs, or if none
-* of the required keywords can be found in the FitsChan.
-*/
-
-/* Local Variables: */
- const char *timesys; /* The TIMESYS value in the FitsStore */
- double mjd; /* The returned MJD */
-
-/* Initialise the returned value. */
- mjd = AST__BAD;
-
-/* Check the global status. */
- if( !astOK ) return mjd;
-
-/* Otherwise, try to get the secondary MJD-AVG value. */
- mjd = GetItem( &(store->mjdavg), 0, 0, s, NULL, method, class, status );
-
-/* Otherwise, try to get the primary MJD-AVG value. */
- if( mjd == AST__BAD ) mjd = GetItem( &(store->mjdavg), 0, 0, ' ', NULL,
- method, class, status );
-
-/* If the secondary MJD-OBS keyword is present in the FitsChan, gets its
- value. */
- if( mjd == AST__BAD ) mjd = GetItem( &(store->mjdobs), 0, 0, s, NULL,
- method, class, status );
-
-/* Otherwise, try to get the primary MJD-OBS value. */
- if( mjd == AST__BAD ) mjd = GetItem( &(store->mjdobs), 0, 0, ' ', NULL,
- method, class, status );
-
-/* Now convert the MJD value to the TDB timescale. */
- timesys = GetItemC( &(store->timesys), 0, 0, ' ', NULL, method, class, status );
- mjd = TDBConv( mjd, TimeSysToAst( this, timesys, method, class, status ),
- 0, method, class, status );
-
-/* Return the answer. */
- return mjd;
-}
-
-static void Chpc1( double *c, double *d, int n, int *w0, int *w1, int *status ){
-/*
-* Name:
-* Chpc1
-
-* Purpose:
-* Converts a one-dimensional Chebyshev polynomial to standard form.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void Chpc1( double *c, double *d, int n, int *w0, int *w1, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* Given the coefficients of a one-dimensional Chebychev polynomial P(u),
-* find the coefficients of the equivalent standard 1D polynomial Q(u).
-* The allowed range of u is assumed to be the unit interval.
-
-* Parameters:
-* c
-* An array of n elements supplied holding the coefficients of
-* P, such that the coefficient of (Ti(u)) is held in element
-* (i), where "Ti(u)" is the Chebychev polynomial (of the
-* first kind) of order "i" evaluated at "u".
-* d
-* An array of n elements returned holding the coefficients of
-* Q, such that the coefficient of (u^i) is held in element (i).
-* n
-* One more than the highest power of u in P.
-* w0
-* Pointer to a work array of n elements.
-* w1
-* Pointer to a work array of n elements.
-* status
-* Inherited status value
-
-* Notes:
-* - Vaguely inspired by the Numerical Recipes routine "chebpc". But the
-* original had bugs, so I wrote this new version from first principles.
-
-*/
-
-/* Local Variables: */
- int sv;
- int j;
- int k;
-
-/* Check inherited status */
- if( !astOK ) return;
-
-/* Initialise the returned coefficients array. */
- for( j = 0; j < n; j++ ) d[ j ] = 0.0;
-
-/* Use the recurrence relation
-
- T{k+1}(x) = 2.x.T{k}(x) - T{k-1}(x).
-
- w0[i] holds the coefficient of x^i in T{k-1}. w1[i] holds the
- coefficient of x^i in T{k}. Initialise them for T0 (="1") and
- T1 (="x"). */
- for( j = 0; j < n; j++ ) w0[ j ] = w1[ j ] = 0;
- w0[ 0 ] = 1;
- w1[ 1 ] = 1;
-
-/* Update the returned coefficients array to include the T0 and T1 terms. */
- d[ 0 ] = c[ 0 ];
- d[ 1 ] = c[ 1 ];
-
-/* Loop round using the above recurrence relation until we have found
- T{n-1}. */
- for( k = 1; k < n - 1; k++ ){
-
-/* To get the coefficients of T{k+1} shift the contents of w1 up one
- element, introducing a zero at the low end, and then double all the
- values in w1. Finally subtract off the values in w0. This implements
- the above recurrence relationship. Starting at the top end and working
- down to the bottom, store a new value for each element of w1. */
- for( j = n - 1; j > 0; j-- ) {
-
-/* First save the original element of w1 in w0 for use next time. But we
- also need the original w0 element later on so save it first. */
- sv = w0[ j ];
- w0[ j ] = w1[ j ];
-
-/* Double the lower neighbouring w1 element and subtract off the w0
- element saved above. This forms the new value for w1. */
- w1[ j ] = 2*w1[ j - 1 ] - sv;
- }
-
-/* Introduce a zero into the lowest element of w1, saving the original
- value first in w0. Then subtract off the original value of w0. */
- sv = w0[ 0 ];
- w0[ 0 ] = w1[ 0 ];
- w1[ 0 ] = -sv;
-
-/* W1 now contains the coefficients of T{k+1} in w1, and the coefficients
- of T{k} in w0. Multiply these by the supplied coefficient for T{k+1},
- and add them into the returned array. */
- for( j = 0; j <= k + 1; j++ ){
- d[ j ] += c[ k + 1 ]*w1[ j ];
- }
- }
-}
-
-static int ChrLen( const char *string, int *status ){
-/*
-* Name:
-* ChrLen
-
-* Purpose:
-* Return the length of a string excluding any trailing white space.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int ChrLen( const char *string, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function returns the length of a string excluding any trailing
-* white space, or non-printable characters.
-
-* Parameters:
-* string
-* Pointer to the string.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The length of a string excluding any trailing white space and
-* non-printable characters.
-
-* Notes:
-* - A value of zero is returned if a NULL pointer is supplied, or if an
-* error has already occurred.
-*/
-
-/* Local Variables: */
- const char *c; /* Pointer to the next character to check */
- int ret; /* The returned string length */
-
-/* Check the global status. */
- if( !astOK ) return 0;
-
-/* Initialise the returned string length. */
- ret = 0;
-
-/* Check a string has been supplied. */
- if( string ){
-
-/* Check each character in turn, starting with the last one. */
- ret = strlen( string );
- c = string + ret - 1;
- while( ret ){
- if( isprint( (int) *c ) && !isspace( (int) *c ) ) break;
- c--;
- ret--;
- }
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static int CLASSFromStore( AstFitsChan *this, FitsStore *store,
- AstFrameSet *fs, double *dim, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* CLASSFromStore
-
-* Purpose:
-* Store WCS keywords in a FitsChan using FITS-CLASS encoding.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* int CLASSFromStore( AstFitsChan *this, FitsStore *store,
-* AstFrameSet *fs, double *dim, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function copies the WCS information stored in the supplied
-* FitsStore into the supplied FitsChan, using FITS-CLASS encoding.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore.
-* fs
-* Pointer to the FrameSet from which the values in the FitsStore
-* were derived.
-* dim
-* Pointer to an array holding the main array dimensions (AST__BAD
-* if a dimension is not known).
-* 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 value of 1 is returned if succesfull, and zero is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- AstFrame *azelfrm; /* (az,el) frame */
- AstFrame *curfrm; /* Current Frame in supplied FrameSet */
- AstFrame *freqfrm; /* Frame for reference frequency value */
- AstFrame *radecfrm; /* Spatial frame for CRVAL values */
- AstFrame *velofrm; /* Frame for reference velocity value */
- AstFrameSet *fsconv1;/* FrameSet connecting "curfrm" & "radecfrm" */
- AstFrameSet *fsconv2;/* FrameSet connecting "curfrm" & "azelfrm" */
- AstMapping *map1; /* Axis permutation to get (lonaxis,lataxis) = (0,1) */
- AstMapping *map2; /* Mapping from FITS CTYPE to (az,el) */
- AstMapping *map3; /* Mapping from (lon,lat) to (az,el) */
- char *comm; /* Pointer to comment string */
- char *cval; /* Pointer to string keyword value */
- char attbuf[20]; /* Buffer for AST attribute name */
- char combuf[80]; /* Buffer for FITS card comment */
- char lattype[MXCTYPELEN];/* Latitude axis CTYPE */
- char lontype[MXCTYPELEN];/* Longitude axis CTYPE */
- char s; /* Co-ordinate version character */
- char sign[2]; /* Fraction's sign character */
- char spectype[MXCTYPELEN];/* Spectral axis CTYPE */
- double *cdelt; /* Pointer to CDELT array */
- double aval[ 2 ]; /* General purpose array */
- double azel[ 2 ]; /* Reference (az,el) values */
- double cdl; /* CDELT term */
- double crval[ 3 ]; /* CRVAL values converted to rads, etc */
- double delta; /* Spectral axis increment */
- double equ; /* Epoch of reference equinox */
- double fd; /* Fraction of a day */
- double latval; /* CRVAL for latitude axis */
- double lonpole; /* LONPOLE value */
- double lonval; /* CRVAL for longitude axis */
- double mjd99; /* MJD at start of 1999 */
- double p1, p2; /* Projection parameters */
- double radec[ 2 ]; /* Reference (lon,lat) values */
- double rf; /* Rest freq (Hz) */
- double specfactor; /* Factor for converting internal spectral units */
- double val; /* General purpose value */
- double xin[ 3 ]; /* Grid coords at centre of first pixel */
- double xout[ 3 ]; /* WCS coords at centre of first pixel */
- int axlat; /* Index of latitude FITS WCS axis */
- int axlon; /* Index of longitude FITS WCS axis */
- int axspec; /* Index of spectral FITS WCS axis */
- int i; /* Axis index */
- int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */
- int iymdf[ 4 ]; /* Year, month, date, fractional day */
- int j; /* Axis index */
- int jj; /* SlaLib status */
- int naxis2; /* Length of pixel axis 2 */
- int naxis3; /* Length of pixel axis 3 */
- int naxis; /* No. of axes */
- int ok; /* Is FitsSTore OK for IRAF encoding? */
- int prj; /* Projection type */
-
-/* Other initialisation to avoid compiler warnings. */
- lonval = 0.0;
- latval = 0.0;
-
-/* Check the inherited status. */
- if( !astOK ) return 0;
-
-/* Initialise */
- specfactor = 1.0;
-
-/* First check that the values in the FitsStore conform to the
- requirements of the CLASS encoding. Assume they do not to begin with. */
- ok = 0;
-
-/* Just do primary axes. */
- s = ' ';
-
-/* Look for the primary celestial axes. */
- FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status );
-
-/* Get the current Frame from the supplied FrameSet. */
- curfrm = astGetFrame( fs, AST__CURRENT );
-
-/* Spectral and celestial axes must be present in axes 1,2 and 3. */
- if( axspec >= 0 && axspec < 3 &&
- axlon >= 0 && axlon < 3 &&
- axlat >= 0 && axlat < 3 ) {
- ok = 1;
-
-/* If the spatial pixel axes are degenerate (i.e. span only a single
- pixel), modify the CRPIX and CRVAL values in the FitsStore to put
- the reference point at the centre of the one and only spatial pixel. */
- if( store->naxis >= 3 && dim[ axlon ] == 1.0 && dim[ axlat ] == 1.0 ){
- xin[ 0 ] = 1.0;
- xin[ 1 ] = 1.0;
- xin[ 2 ] = 1.0;
- astTranN( fs, 1, 3, 1, xin, 1, 3, 1, xout );
- if( xout[ axlon ] != AST__BAD && xout[ axlat ] != AST__BAD ) {
-
-/* The indices of the spatial axes in the FITS header may not be the same
- as the indices of the spatial axes in the WCS Frame of the supplied
- FrameSet. So search the current Frame for longitude and latitude axes,
- and store the corresponding elements of the "xout" array for later use. */
- for( i = 0; i < 3; i++ ) {
- sprintf( attbuf, "IsLonAxis(%d)", i + 1 );
- if( astHasAttribute( curfrm, attbuf ) ) {
- if( astGetI( curfrm, attbuf ) ) {
- lonval = xout[ i ];
- } else {
- latval = xout[ i ];
- }
- }
- }
-
-/* Store them in the FitsStore. */
- SetItem( &(store->crval), axlon, 0, ' ', lonval*AST__DR2D, status );
- SetItem( &(store->crval), axlat, 0, ' ', latval*AST__DR2D, status );
- SetItem( &(store->crpix), 0, axlon, ' ', 1.0, status );
- SetItem( &(store->crpix), 0, axlat, ' ', 1.0, status );
- }
- }
-
-/* Get the CRVAL values for both spatial axes. */
- latval = GetItem( &( store->crval ), axlat, 0, s, NULL, method, class, status );
- if( latval == AST__BAD ) ok = 0;
- lonval = GetItem( &( store->crval ), axlon, 0, s, NULL, method, class, status );
- if( lonval == AST__BAD ) ok = 0;
-
-/* Get the CTYPE values for both axes. Extract the projection type as
- specified by the last 4 characters in the latitude CTYPE keyword value. */
- cval = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else {
- strcpy( lontype, cval );
- }
- cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- prj = AST__WCSBAD;
- } else {
- strcpy( lattype, cval );
- prj = astWcsPrjType( cval + 4 );
- }
-
-/* Check the projection type is OK. */
- if( prj == AST__WCSBAD ){
- ok = 0;
- } else if( prj != AST__SIN ){
-
-/* Check the projection code is OK. */
- ok = 0;
- if( prj == AST__TAN ||
- prj == AST__ARC ||
- prj == AST__STG ||
- prj == AST__AIT ||
- prj == AST__SFL ) {
- ok = 1;
-
-/* For AIT, and SFL, check that the reference point is the origin of
- the celestial co-ordinate system. */
- if( prj == AST__AIT ||
- prj == AST__SFL ) {
- if( latval != 0.0 || lonval != 0.0 ){
- ok = 0;
-
-/* Change the new SFL projection code to to the older equivalent GLS */
- } else if( prj == AST__SFL ){
- (void) strcpy( lontype + 4, "-GLS" );
- (void) strcpy( lattype + 4, "-GLS" );
-
-/* Change the new AIT projection code to to the older equivalent ATF */
- } else if( prj == AST__AIT ){
- (void) strcpy( lontype + 4, "-ATF" );
- (void) strcpy( lattype + 4, "-ATF" );
- }
- }
- }
-
-/* SIN projections are only acceptable if the associated projection
- parameters are both zero. */
- } else {
- p1 = GetItem( &( store->pv ), axlat, 1, s, NULL, method, class, status );
- p2 = GetItem( &( store->pv ), axlat, 2, s, NULL, method, class, status );
- if( p1 == AST__BAD ) p1 = 0.0;
- if( p2 == AST__BAD ) p2 = 0.0;
- ok = ( p1 == 0.0 && p2 == 0.0 );
- }
-
-/* Identify the celestial coordinate system from the first 4 characters of the
- longitude CTYPE value. Only RA and galactic longitude can be stored using
- FITS-CLASS. */
- if( ok && strncmp( lontype, "RA--", 4 ) &&
- strncmp( lontype, "GLON", 4 ) ) ok = 0;
-
-/* Get the CTYPE values for the spectral axis, and find the CLASS equivalent,
- if possible. */
- cval = GetItemC( &(store->ctype), axspec, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else {
- if( !strncmp( cval, "FREQ", astChrLen( cval ) ) ) {
- strcpy( spectype, "FREQ" );
- } else {
- ok = 0;
- }
- }
-
-/* If OK, check the SPECSYS value is SOURCE. */
- cval = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else if( ok ) {
- if( strncmp( cval, "SOURCE", astChrLen( cval ) ) ) ok = 0;
- }
-
-/* If still OK, ensure the spectral axis units are Hz. */
- cval = GetItemC( &(store->cunit), axspec, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- } else if( ok ) {
- if( !strcmp( cval, "Hz" ) ) {
- specfactor = 1.0;
- } else if( !strcmp( cval, "kHz" ) ) {
- specfactor = 1.0E3;
- } else if( !strcmp( cval, "MHz" ) ) {
- specfactor = 1.0E6;
- } else if( !strcmp( cval, "GHz" ) ) {
- specfactor = 1.0E9;
- } else {
- ok = 0;
- }
- }
- }
-
-/* Save the number of WCS axes */
- naxis = GetMaxJM( &(store->crpix), ' ', status ) + 1;
-
-/* If this is larger than 3, ignore the surplus WCS axes. Note, the
- above code has checked that the spatial and spectral axes are
- WCS axes 0, 1 and 2. */
- if( naxis > 3 ) naxis = 3;
-
-/* Allocate memory to store the CDELT values */
- if( ok ) {
- cdelt = (double *) astMalloc( sizeof(double)*naxis );
- if( !cdelt ) ok = 0;
- } else {
- cdelt = NULL;
- }
-
-/* Check that there is no rotation, and extract the CDELT (diagonal) terms,
- etc. If the spatial axes are degenerate (i.e. cover only a single pixel)
- then ignore any rotation. */
- if( !GetValue( this, FormatKey( "NAXIS", axlon + 1, -1, s, status ), AST__INT,
- &naxis2, 0, 0, method, class, status ) ) {
- naxis2 = 0;
- }
- if( !GetValue( this, FormatKey( "NAXIS", axlat + 1, -1, s, status ), AST__INT,
- &naxis3, 0, 0, method, class, status ) ) {
- naxis3 = 0;
- }
- for( i = 0; i < naxis && ok; i++ ){
- cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
- if( cdl == AST__BAD ) cdl = 1.0;
- for( j = 0; j < naxis && ok; j++ ){
- val = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
- if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0;
- val *= cdl;
- if( i == j ){
- cdelt[ i ] = val;
- } else if( val != 0.0 ){
- if( naxis2 != 1 || naxis3 != 1 ) ok = 0;
- }
- }
- }
-
-/* Get RADECSYS and the reference equinox. */
- cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status );
- equ = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status );
-
-/* If RADECSYS was available... */
- if( cval ){
-
-/* Only FK4 and FK5 are supported in this encoding. */
- if( strcmp( "FK4", cval ) && strcmp( "FK5", cval ) ) ok = 0;
-
-/* If epoch was not available, set a default epoch. */
- if( equ == AST__BAD ){
- if( !strcmp( "FK4", cval ) ){
- equ = 1950.0;
- } else if( !strcmp( "FK5", cval ) ){
- equ = 2000.0;
- } else {
- ok = 0;
- }
-
-/* If an epoch was supplied, check it is consistent with the IAU 1984
- rule. */
- } else {
- if( !strcmp( "FK4", cval ) ){
- if( equ >= 1984.0 ) ok = 0;
- } else if( !strcmp( "FK5", cval ) ){
- if( equ < 1984.0 ) ok = 0;
- } else {
- ok = 0;
- }
- }
-
-/* Check we have a rest frequency */
- rf = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status );
- if( rf == AST__BAD ) ok = 0;
- }
-
-/* If the spatial Frame covers more than a single Frame and requires a LONPOLE
- or LATPOLE keyword, it cannot be encoded using FITS-CLASS. However since
- FITS-CLASS imposes a no rotation restriction, it can tolerate lonpole
- values of +/- 180 degrees. */
- if( ok && ( naxis2 != 1 || naxis3 != 1 ) ) {
- lonpole = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status );
- if( lonpole != AST__BAD && lonpole != -180.0 && lonpole == 180 ) ok = 0;
- if( GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status )
- != AST__BAD ) ok = 0;
- }
-
-/* Only create the keywords if the FitsStore conforms to the requirements
- of the FITS-CLASS encoding. */
- if( ok ) {
-
-/* If celestial axes were added by MakeFitsFrameSet, we need to ensure
- the header contains 3 main array axes. This is because the CLASS
- encoding does not support the WCSAXES keyword. */
- if( store->naxis == 1 ) {
-
-/* Update the "NAXIS" value to 3 or put a new card in at the start. */
- astClearCard( this );
- i = 3;
- SetValue( this, "NAXIS", &i, AST__INT, NULL, status );
-
-/* Put NAXIS2/3 after NAXIS1, or after NAXIS if the FitsChan does not contain
- NAXIS1. These are set to 1 since the spatial axes are degenerate. */
- if( FindKeyCard( this, "NAXIS1", method, class, status ) ) {
- MoveCard( this, 1, method, class, status );
- }
- i = 1;
- SetValue( this, "NAXIS2", &i, AST__INT, NULL, status );
- SetValue( this, "NAXIS3", &i, AST__INT, NULL, status );
- }
-
-/* Find the last WCS related card. */
- FindWcs( this, 1, 1, 0, method, class, status );
-
-/* Get and save CRPIX for all pixel axes. These are required, so break
- if they are not available. */
- for( j = 0; j < naxis && ok; j++ ){
- val = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- } else {
- sprintf( combuf, "Reference pixel on axis %d", j + 1 );
- SetValue( this, FormatKey( "CRPIX", j + 1, -1, s, status ), &val,
- AST__FLOAT, combuf, status );
- }
- }
-
-/* Get and save CRVAL for all intermediate axes. These are required, so
- break if they are not available. Note, the frequency axis CRVAL is
- redefined by FITS-CLASS by reducing it by the RESTFREQ value. */
- for( i = 0; i < naxis && ok; i++ ){
- val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- } else {
- crval[ i ] = val;
- if( i == axspec ) {
- val *= specfactor;
- val -= rf;
- }
- sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 );
- SetValue( this, FormatKey( "CRVAL", i + 1, -1, s, status ), &val,
- AST__FLOAT, combuf, status );
- }
- }
-
-/* Get and save CTYPE for all intermediate axes. These are required, so
- break if they are not available. Use the potentially modified versions
- saved above for the celestial axes. */
- for( i = 0; i < naxis && ok; i++ ){
- if( i == axlat ) {
- cval = lattype;
- } else if( i == axlon ) {
- cval = lontype;
- } else if( i == axspec ) {
- cval = spectype;
- } else {
- cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- }
- if( cval && ( strlen(cval) < 5 || strcmp( cval + 4, "-TAB" ) ) ) {
- comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status );
- if( !comm ) {
- sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 );
- comm = combuf;
- }
- SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval,
- AST__STRING, comm, status );
- } else {
- ok = 0;
- }
- }
-
-/* CDELT values */
- if( axspec != -1 ) cdelt[ axspec ] *= specfactor;
- for( i = 0; i < naxis; i++ ){
- SetValue( this, FormatKey( "CDELT", i + 1, -1, s, status ), cdelt + i,
- AST__FLOAT, "Pixel size", status );
- }
-
-/* Reference equinox */
- if( equ != AST__BAD ) SetValue( this, "EQUINOX", &equ, AST__FLOAT,
- "Epoch of reference equinox", status );
-
-/* Date of observation. */
- val = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status );
- if( val != AST__BAD ) {
-
-/* The format used for the DATE-OBS keyword depends on the value of the
- keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format.
- Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */
- palCaldj( 99, 1, 1, &mjd99, &jj );
- if( val < mjd99 ) {
- palDjcal( 0, val, iymdf, &jj );
- sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ],
- iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) );
- } else {
- palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj );
- palDd2tf( 3, fd, sign, ihmsf );
- sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d",
- iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1],
- ihmsf[2], ihmsf[3] );
- }
-
-/* Now store the formatted string in the FitsChan. */
- cval = combuf;
- SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING,
- "Date of observation", status );
- }
-
-/* Rest frequency */
- SetValue( this, "RESTFREQ", &rf, AST__FLOAT, "[Hz] Rest frequency", status );
-
-/* The image frequency corresponding to the rest frequency (only used for
- double sideband data). */
- val = GetItem( &(store->imagfreq), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- SetValue( this, "IMAGFREQ", &val, AST__FLOAT, "[Hz] Image frequency", status );
- }
-
-/* Ensure the FitsChan contains OBJECT and LINE headers */
- if( !HasCard( this, "OBJECT", method, class, status ) ) {
- cval = " ";
- SetValue( this, "OBJECT", &cval, AST__STRING, NULL, status );
- }
- if( !HasCard( this, "LINE", method, class, status ) ) {
- cval = " ";
- SetValue( this, "LINE", &cval, AST__STRING, NULL, status );
- }
-
-/* CLASS expects the VELO-LSR keyword to hold the radio velocity of the
- reference channel (NOT of the source as I was told!!) with respect to
- the LSRK rest frame. The "crval" array holds the frequency of the
- reference channel in the source rest frame, so we need to convert this
- to get the value for VELO-LSR. Create a SpecFrame describing the
- required frame (other attributes such as Epoch etc are left unset and
- so will be picked up from the supplied FrameSet). We set MinAxes
- and MaxAxes so that the Frame can be used as a template to match the
- 1D or 3D current Frame in the supplied FrameSet. */
- velofrm = (AstFrame *) astSpecFrame( "System=vrad,StdOfRest=lsrk,"
- "Unit=m/s,MinAxes=1,MaxAxes=3", status );
-
-/* Find the spectral axis within the current Frame of the supplied
- FrameSet, using the above "velofrm" as a template. */
- fsconv1 = astFindFrame( curfrm, velofrm, "" );
-
-/* If OK, extract the SpecFrame from the returned FraneSet (this will
- have the attribute values that were assigned explicitly to "velofrm"
- and will have inherited all unset attributes from the supplied
- FrameSet). */
- if( fsconv1 ) {
- velofrm = astAnnul( velofrm );
- velofrm = astGetFrame( fsconv1, AST__CURRENT );
- fsconv1 = astAnnul( fsconv1 );
-
-/* Take a copy of the velofrm and modify its attributes so that it
- describes frequency in the sources rest frame in units of Hz. This is
- the system that CLASS expects for the CRVAL3 keyword. */
- freqfrm = astCopy( velofrm );
- astSet( freqfrm, "System=freq,StdOfRest=Source,Unit=Hz", status );
-
-/* Get a Mapping from frequency to velocity. */
- fsconv1 = astConvert( freqfrm, velofrm, "" );
- if( fsconv1 ) {
-
-/* Use this Mapping to convert the spectral crval value from frequency to
- velocity. Also convert the value for the neighbouring channel. */
- aval[ 0 ] = crval[ axspec ]*specfactor;
- aval[ 1 ] = aval[ 0 ] + cdelt[ axspec ]*specfactor;
- astTran1( fsconv1, 2, aval, 1, aval );
-
-/* Store the value. Also store it as VLSR since this keyword seems to be
- used for the same thing. */
- SetValue( this, "VELO-LSR", aval, AST__FLOAT, "[m/s] Reference velocity", status );
- SetValue( this, "VLSR", aval, AST__FLOAT, "[m/s] Reference velocity", status );
-
-/* The DELTAV keyword holds the radio velocity channel spacing in the
- LSR. */
- delta = aval[ 1 ] - aval[ 0 ];
- SetValue( this, "DELTAV", &delta, AST__FLOAT, "[m/s] Velocity resolution", status );
-
-/* Free remaining resources. */
- fsconv1 = astAnnul( fsconv1 );
- }
- }
- velofrm = astAnnul( velofrm );
-
-/* AZIMUTH and ELEVATIO - the (az,el) equivalent of CRVAL. We need a
- Mapping from the CTYPE spatial system to (az,el). This depends on all
- the extra info like telescope position, epoch, etc. This info is in
- the current Frame in the supplied FrameSet. First get a conversion
- from a sky frame with default axis ordering to the supplied Frame. All
- the extra info is picked up from the supplied Frame since it is not set
- in the template. */
- radecfrm = (AstFrame *) astSkyFrame( "Permute=0,MinAxes=3,MaxAxes=3", status );
- fsconv1 = astFindFrame( curfrm, radecfrm, "" );
-
-/* Now get conversion from the an (az,el) Frame to the supplied Frame. */
- azelfrm = (AstFrame *) astSkyFrame( "System=AZEL,Permute=0,MinAxes=3,MaxAxes=3", status );
- fsconv2 = astFindFrame( curfrm, azelfrm, "" );
-
-/* If both conversions werew possible, concatenate their Mappings to get
- a Mapping from (lon,lat) in the CTYPE system, to (az,el). */
- if( fsconv1 && fsconv2 ) {
- map1 = astGetMapping( fsconv1, AST__CURRENT, AST__BASE );
- map2 = astGetMapping( fsconv2, AST__BASE, AST__CURRENT );
- map3 = (AstMapping *) astCmpMap( map1, map2, 1, "", status );
-
-/* Store the CRVAL (ra,dec) values in the default order. */
- radec[ 0 ] = crval[ axlon ]*AST__DD2R;
- radec[ 1 ] = crval[ axlat ]*AST__DD2R;
-
-/* Transform to (az,el), normalise, convert to degrees and store. */
- astTranN( map3, 1, 2, 1, radec, 1, 2, 1, azel );
- if( azel[ 0 ] != AST__BAD && azel[ 1 ] != AST__BAD ) {
- astNorm( azelfrm, azel );
- azel[ 0 ] *= AST__DR2D;
- azel[ 1 ] *= AST__DR2D;
- SetValue( this, "AZIMUTH", azel, AST__FLOAT, "[Deg] Telescope azimuth", status );
- SetValue( this, "ELEVATIO", azel + 1, AST__FLOAT, "[Deg] Telescope elevation", status );
- }
-
-/* Free resources */
- map1 = astAnnul( map1 );
- map2 = astAnnul( map2 );
- map3 = astAnnul( map3 );
- fsconv1 = astAnnul( fsconv1 );
- fsconv2 = astAnnul( fsconv2 );
- }
- radecfrm = astAnnul( radecfrm );
- azelfrm = astAnnul( azelfrm );
- }
- curfrm = astAnnul( curfrm );
-
-/* Release CDELT workspace */
- if( cdelt ) cdelt = (double *) astFree( (void *) cdelt );
-
-/* Return zero or ret depending on whether an error has occurred. */
- return astOK ? ok : 0;
-}
-
-static void ClassTrans( AstFitsChan *this, AstFitsChan *ret, int axlat,
- int axlon, const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* ClassTrans
-
-* Purpose:
-* Translated non-standard FITS-CLASS headers into equivalent standard
-* ones.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void ClassTrans( AstFitsChan *this, AstFitsChan *ret, int axlat,
-* int axlon, const char *method, const char *class )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function extends the functionality of the SpecTrans function,
-* by converting non-standard WCS keywords into standard FITS-WCS
-* keywords, using the conventions of the FITS-CLASS encoding.
-
-* Parameters:
-* this
-* Pointer to the FitsChan containing the original header cards.
-* ret
-* Pointer to a FitsChan in which to return the standardised header
-* cards.
-* axlat
-* Zero-based index of the celestial latitude axis.
-* axlon
-* Zero-based index of the celestial longitude axis.
-* method
-* Pointer to string holding name of calling method.
-* class
-* Pointer to a string holding the name of the supplied object class.
-*/
-
-/* Local Variables: */
- char *cval; /* Pointer to character string */
- char newtype[ 10 ]; /* New CTYPE value */
- const char *keyname; /* Pointer to keyword name */
- const char *ssyssrc; /* Pointer to SSYSSRC keyword value string */
- double crval; /* CRVAL value */
- double restfreq; /* Rest frequency (Hz) */
- double v0; /* Ref channel velocity in source frame */
- double vref; /* Ref channel velocity in LSR or whatever */
- double vsource; /* Source velocity */
- double zsource; /* Source redshift */
- int axspec; /* Index of spectral axis */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get the rest frequency. */
- restfreq = AST__BAD;
- if( !GetValue2( ret, this, "RESTFRQ", AST__FLOAT, (void *) &restfreq, 0,
- method, class, status ) ){
- GetValue2( ret, this, "RESTFREQ", AST__FLOAT, (void *) &restfreq, 0,
- method, class, status );
- }
- if( restfreq == AST__BAD ) {
- astError( AST__BDFTS, "%s(%s): Keyword RESTFREQ not found in CLASS "
- "FITS header.", status, method, class );
- }
-
-/* Get the index of the spectral axis. */
- if( axlat + axlon == 1 ) {
- axspec = 2;
- } else if( axlat + axlon == 3 ) {
- axspec = 0;
- } else {
- axspec = 1;
- }
-
-/* Get the spectral CTYPE value */
- if( GetValue2( ret, this, FormatKey( "CTYPE", axspec + 1, -1, ' ', status ),
- AST__STRING, (void *) &cval, 0, method, class, status ) ){
-
-/* We can only handle frequency axes at the moment. */
- if( !astChrMatch( "FREQ", cval ) ) {
- astError( AST__BDFTS, "%s(%s): FITS-CLASS keyword %s has value "
- "\"%s\" - CLASS support in AST only includes \"FREQ\" axes.", status,
- method, class, FormatKey( "CTYPE", axspec + 1, -1, ' ', status ),
- cval );
-
-/* CRVAL for the spectral axis needs to be incremented by RESTFREQ if the
- axis represents frequency. */
- } else {
- keyname = FormatKey( "CRVAL", axspec + 1, -1, ' ', status );
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &crval, 1,
- method, class, status ) ) {
- crval += restfreq;
- SetValue( ret, keyname, (void *) &crval, AST__FLOAT, NULL, status );
- }
- }
-
-/* CLASS frequency axes describe source frame frequencies. */
- cval = "SOURCE";
- SetValue( ret, "SPECSYS", (void *) &cval, AST__STRING, NULL, status );
- }
-
-/* If no projection code is supplied for the longitude and latitude axes,
- use "-GLS". This will be translated to "-SFL" by SpecTrans. */
- keyname = FormatKey( "CTYPE", axlon + 1, -1, ' ', status );
- if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method,
- class, status ) ){
- if( strlen(cval) > 4 && !strncmp( " ", cval + 4, 4 ) ) {
- strncpy( newtype, cval, 4 );
- strcpy( newtype + 4, "-GLS" );
- cval = newtype;
- SetValue( ret, keyname, (void *) &cval, AST__STRING, NULL, status );
- }
- }
- keyname = FormatKey( "CTYPE", axlat + 1, -1, ' ', status );
- if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method,
- class, status ) ){
- if( strlen(cval) > 4 && !strncmp( " ", cval + 4, 4 ) ) {
- strncpy( newtype, cval, 4 );
- strcpy( newtype + 4, "-GLS" );
- cval = newtype;
- SetValue( ret, keyname, (void *) &cval, AST__STRING, NULL, status );
- }
- }
-
-/* Look for a keyword with name "VELO-...". This specifies the radio velocity
- at the reference channel, in a standard of rest specified by the "..."
- in the keyword name. If "VELO-..." is not found, look for "VLSR",
- which is the same as "VELO-LSR". */
- if( GetValue2( ret, this, "VELO-%3c", AST__FLOAT, (void *) &vref, 0,
- method, class, status ) ||
- GetValue2( ret, this, "VLSR", AST__FLOAT, (void *) &vref, 0,
- method, class, status ) ){
-
-/* Calculate the radio velocity (in the rest frame of the source) corresponding
- to the frequency at the reference channel. */
- v0 = AST__C*( restfreq - crval )/restfreq;
-
-/* Assume that the source velocity is the difference between this velocity
- and the reference channel velocity given by "VELO-..." */
- vsource = vref - v0;
-
-/* Get the keyword name and find the corresponding SSYSSRC keyword value. */
- keyname = CardName( this, status );
- if( !strcmp( keyname, "VELO-HEL" ) ) {
- ssyssrc = "BARYCENT";
- } else if( !strcmp( keyname, "VELO-OBS" ) || !strcmp( keyname, "VELO-TOP" ) ) {
- ssyssrc = "TOPOCENT";
- } else if( !strcmp( keyname, "VELO-EAR" ) || !strcmp( keyname, "VELO-GEO" ) ) {
- ssyssrc = "GEOCENTR";
- } else {
- ssyssrc = "LSRK";
- }
- SetValue( ret, "SSYSSRC", (void *) &ssyssrc, AST__STRING, NULL, status );
-
-/* Convert from radio velocity to redshift and store as ZSOURCE */
- zsource = ( AST__C / (AST__C - vsource) ) - 1.0;
- SetValue( ret, "ZSOURCE", (void *) &zsource, AST__FLOAT, NULL, status );
- }
-}
-
-static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
-/*
-* Name:
-* ClearAttrib
-
-* Purpose:
-* Clear an attribute value for a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void ClearAttrib( AstObject *this, const char *attrib, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the astClearAttrib protected
-* method inherited from the Channel class).
-
-* Description:
-* This function clears the value of a specified attribute for a
-* FitsChan, so that the default value will subsequently be used.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* 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.
-*/
-
-/* Local Variables: */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_object;
-
-/* Check the attribute name and clear the appropriate attribute. */
-
-/* Card. */
-/* ----- */
- if ( !strcmp( attrib, "card" ) ) {
- astClearCard( this );
-
-/* Encoding. */
-/* --------- */
- } else if ( !strcmp( attrib, "encoding" ) ) {
- astClearEncoding( this );
-
-/* CDMatrix */
-/* -------- */
- } else if ( !strcmp( attrib, "cdmatrix" ) ) {
- astClearCDMatrix( this );
-
-/* FitsAxisOrder. */
-/* ----------- */
- } else if ( !strcmp( attrib, "fitsaxisorder" ) ) {
- astClearFitsAxisOrder( this );
-
-/* FitsDigits. */
-/* ----------- */
- } else if ( !strcmp( attrib, "fitsdigits" ) ) {
- astClearFitsDigits( this );
-
-/* DefB1950 */
-/* -------- */
- } else if ( !strcmp( attrib, "defb1950" ) ) {
- astClearDefB1950( this );
-
-/* TabOK */
-/* ----- */
- } else if ( !strcmp( attrib, "tabok" ) ) {
- astClearTabOK( this );
-
-/* CarLin */
-/* ------ */
- } else if ( !strcmp( attrib, "carlin" ) ) {
- astClearCarLin( this );
-
-/* PolyTan */
-/* ------- */
- } else if ( !strcmp( attrib, "polytan" ) ) {
- astClearPolyTan( this );
-
-/* Iwc */
-/* --- */
- } else if ( !strcmp( attrib, "iwc" ) ) {
- astClearIwc( this );
-
-/* Clean */
-/* ----- */
- } else if ( !strcmp( attrib, "clean" ) ) {
- astClearClean( this );
-
-/* Warnings. */
-/* -------- */
- } else if ( !strcmp( attrib, "warnings" ) ) {
- astClearWarnings( this );
-
-/* If the name was not recognised, test if it matches any of the
- read-only attributes of this class. If it does, then report an
- error. */
- } else if ( astOK && ( !strcmp( attrib, "ncard" ) ||
- !strcmp( attrib, "allwarnings" ) ) ){
- astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" "
- "value for a %s.", status, attrib, astGetClass( this ) );
- astError( AST__NOWRT, "This is a read-only attribute." , status);
-
-/* If the attribute is still not recognised, pass it on to the parent
- method for further interpretation. */
- } else {
- (*parent_clearattrib)( this_object, attrib, status );
- }
-}
-
-static void ClearCard( AstFitsChan *this, int *status ){
-
-/*
-*+
-* Name:
-* astClearCard
-
-* Purpose:
-* Clear the Card attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void astClearCard( AstFitsChan *this )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function clears the Card attribute for the supplied FitsChan by
-* setting it to the index of the first un-used card in the FitsChan.
-* This causes the next read operation performed on the FitsChan to
-* read the first card. Thus, it is equivalent to "rewinding" the FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Notes:
-* - This function attempts to execute even if an error has occurred.
-*-
-*/
-
-/* Local Variables; */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Check the supplied FitsChan. If its is empty, return. */
- if ( !this || !(this->head) ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Set the pointer to the current card so that it points to the card at
- the head of the list. */
- this->card = this->head;
-
-/* If the current card has been read into an AST object, move on to the
- first card which has not, unless we are not skipping such cards. */
- if( CARDUSED(this->card) ){
- MoveCard( this, 1, "astClearCard", astGetClass( this ), status );
- }
-}
-
-static int CnvValue( AstFitsChan *this, int type, int undef, void *buff,
- const char *method, int *status ){
-
-/*
-*
-* Name:
-* CnvValue
-
-* Purpose:
-* Convert a data value into a given FITS data type.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int CnvValue( AstFitsChan *this, int type, int undef, void *buff,
-* const char *method, int *status )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function produces a copy of the data value for the current card
-* converted from its stored data type to the supplied data type.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* type
-* The FITS data type in which to return the data value of the
-* current card.
-* undef
-* Determines what happens if the current card has an undefined
-* value. If "undef" is zero, an error will be reported identifying
-* the undefined keyword value. If "undef" is non-zero, no error is
-* reported and the contents of the output buffer are left unchanged.
-* buf
-* A pointer to a buffer to recieve the converted value. It is the
-* responsibility of the caller to ensure that a suitable buffer is
-* supplied.
-* method
-* Pointer to a string holding the name of the calling method.
-* This is only for use in constructing error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero if the conversion was not possible (in which case NO error is
-* reported), one otherwise.
-
-* Notes:
-* - When converting from floating point to integer, the floating
-* point value is truncated using a C cast.
-* - Non-zero numerical values are considered TRUE, and zero
-* numerical values are considered FALSE. Any string starting with a
-* 'T' or a 'Y' (upper or lower case) is considered TRUE, and anything
-* starting with an 'F' or an 'N' (upper or lower case) is considered
-* FALSE. In addition, a dot ('.') may be placed in front of a 'T' or an
-* 'F'.
-* - A logical TRUE value is represented as a real numerical value of
-* one and the character string "Y". A logical FALSE value is represented
-* by a real numerical value of zero and the character string "N".
-* - When converting from a string to any numerical value, zero is
-* returned if the string is not a formatted value which can be converted
-* into the corresponding type using astSscanf.
-* - Real and imaginary parts of a complex value should be separated by
-* spaces within strings. If a string does contains only a single numerical
-* value, it is assumed to be the real part, and the imaginary part is
-* assumed to be zero.
-* - When converting a complex numerical type to a non-complex numerical
-* type, the returned value is derived from the real part only, the
-* imaginary part is ignored.
-* - Zero is returned if an error has occurred, or if this function
-* should fail for any reason.
-* - If the supplied value is undefined an error will be reported.
-*/
-
-/* Local Variables: */
- int otype; /* Stored data type */
- size_t osize; /* Size of stored data */
- void *odata; /* Pointer to stored data */
-
-/* Check the global error status, and the supplied buffer. */
- if ( !astOK || !buff ) return 0;
-
-/* Get the type in which the data value is stored. */
- otype = CardType( this, status );
-
-/* Get a pointer to the stored data value, and its size. */
- osize = 0;
- odata = CardData( this, &osize, status );
-
-/* Do the conversion. */
- return CnvType( otype, odata, osize, type, undef, buff,
- CardName( this, status ), method, astGetClass( this ),
- status );
-}
-
-static int CnvType( int otype, void *odata, size_t osize, int type, int undef,
- void *buff, const char *name, const char *method,
- const char *class, int *status ){
-/*
-*
-* Name:
-* CnvType
-
-* Purpose:
-* Convert a data value into a given FITS data type.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int CnvType( int otype, void *odata, size_t osize, int type, int undef,
-* void *buff, const char *name, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function produces a copy of the data value for the current card
-* converted from its stored data type to the supplied data type.
-
-* Parameters:
-* otype
-* The type of the supplied data value.
-* odata
-* Pointer to a buffer holding the supplied data value.
-* osize
-* The size of the data value (in bytes - strings include the
-* terminating null).
-* type
-* The FITS data type in which to return the data value of the
-* current card.
-* undef
-* Determines what happens if the supplied data value type is
-* undefined If "undef" is zero, an error will be reported identifying
-* the undefined keyword value. If "undef" is non-zero, no error is
-* reported and the contents of the output buffer are left unchanged.
-* buff
-* A pointer to a buffer to recieve the converted value. It is the
-* responsibility of the caller to ensure that a suitable buffer is
-* supplied.
-* name
-* A pointer to a string holding a keyword name to include in error
-* messages.
-* 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 object class.
-* This is only for use in constructing error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero if the conversion was not possible (in which case NO error is
-* reported), one otherwise.
-
-* Notes:
-* - When converting from floating point to integer, the floating
-* point value is truncated using a C cast.
-* - Non-zero numerical values are considered TRUE, and zero
-* numerical values are considered FALSE. Any string starting with a
-* 'T' or a 'Y' (upper or lower case) is considered TRUE, and anything
-* starting with an 'F' or an 'N' (upper or lower case) is considered
-* FALSE. In addition, a dot ('.') may be placed in front of a 'T' or an
-* 'F'.
-* - A logical TRUE value is represented as a real numerical value of
-* one and the character string "Y". A logical FALSE value is represented
-* by a real numerical value of zero and the character string "N".
-* - When converting from a string to any numerical value, zero is
-* returned if the string isn not a formatted value which can be converted
-* into the corresponding type using astSscanf.
-* - Real and imaginary parts of a complex value should be separated by
-* spaces within strings. If a string does contains only a single numerical
-* value, it is assumed to be the real part, and the imaginary part is
-* assumed to be zero.
-* - When converting a complex numerical type to a non-complex numerical
-* type, the returned value is derived from the real part only, the
-* imaginary part is ignored.
-* - Zero is returned if an error has occurred, or if this function
-* should fail for any reason.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- const char *c; /* Pointer to next character */
- const char *ostring; /* String data value */
- double odouble; /* Double data value */
- int oint; /* Integer data value */
- int ival; /* Integer value read from string */
- int len; /* Length of character string */
- int nc; /* No. of characetsr used */
- int ret; /* Returned success flag */
-
-/* Check the global error status, and the supplied buffer. */
- if ( !astOK || !buff ) return 0;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(NULL);
-
-/* Assume success. */
- ret = 1;
-
-/* If the supplied data type is undefined, report an error unless the
- returned data type is also undefined or an undefined value is
- acceptable for the keyword. */
- if( otype == AST__UNDEF ) {
- if( type != AST__UNDEF && !undef ) {
- ret = 0;
- astError( AST__FUNDEF, "The FITS keyword '%s' has an undefined "
- "value.", status, name );
- }
-
-/* If the returned data type is undefined, the returned value is
- immaterial, so leave the buffer contents unchanged. */
- } else if( type == AST__UNDEF ) {
-
-/* If there is no data value and this is not a COMMENT keyword, or if
- there is a data value and this is a COMMENT card, conversion is not
- possible. */
- } else if( ( odata && otype == AST__COMMENT ) ||
- ( !odata && otype != AST__COMMENT ) ) {
- ret = 0;
-
-/* If there is no data value (and therefore this is a comment card),
- conversion is only possible if the output type is also a comment. */
- } else if( !odata ) {
- if( type != AST__COMMENT ) ret = 0;
-
-/* Otherwise we have a data value, so do each possible combination of
- supplied and stored data types... */
- } else {
-
-/* Convert a AST__FLOAT data value to ... */
- if( otype == AST__FLOAT ){
- odouble = *( (double *) odata );
- if( type == AST__FLOAT ){
- (void) memcpy( buff, odata, osize );
- } else if( type == AST__STRING || type == AST__CONTINUE ){
- if( odouble != AST__BAD ) {
- (void) sprintf( cnvtype_text, "%.*g", DBL_DIG, odouble );
- CheckZero( cnvtype_text, odouble, 0, status );
- } else {
- strcpy( cnvtype_text, BAD_STRING );
- }
- *( (char **) buff ) = cnvtype_text;
- } else if( type == AST__INT ){
- *( (int *) buff ) = (int) odouble;
- } else if( type == AST__LOGICAL ){
- *( (int *) buff ) = ( odouble == 0.0 ) ? 0 : 1;
- } else if( type == AST__COMPLEXF ){
- ( (double *) buff )[ 0 ] = odouble;
- ( (double *) buff )[ 1 ] = 0.0;
- } else if( type == AST__COMPLEXI ){
- ( (int *) buff )[ 0 ] = (int) odouble;
- ( (int *) buff )[ 1 ] = 0;
- } else if( astOK ){
- ret = 0;
- astError( AST__INTER, "CnvType: AST internal programming error - "
- "FITS data-type no. %d not yet supported.", status, type );
- }
-
-/* Convert a AST__STRING data value to ... */
- } else if( otype == AST__STRING || type == AST__CONTINUE ){
- ostring = (char *) odata;
- len = (int) strlen( ostring );
- if( type == AST__FLOAT ){
- if( nc = 0,
- ( 0 == astSscanf( ostring, BAD_STRING " %n", &nc ) )
- && (nc >= len ) ){
- *( (double *) buff ) = AST__BAD;
- } else if( nc = 0,
- ( 1 != astSscanf( ostring, "%lf %n", (double *) buff, &nc ) )
- || (nc < len ) ){
- ret = 0;
- }
- } else if( type == AST__STRING || type == AST__CONTINUE ){
- strncpy( cnvtype_text, (char *) odata, AST__FITSCHAN_FITSCARDLEN );
- *( (char **) buff ) = cnvtype_text;
- } else if( type == AST__INT ){
- if( nc = 0,
- ( 1 != astSscanf( ostring, "%d %n", (int *) buff, &nc ) )
- || (nc < len ) ){
- ret = 0;
- }
- } else if( type == AST__LOGICAL ){
- if( nc = 0,
- ( 1 == astSscanf( ostring, "%d %n", &ival, &nc ) )
- && (nc >= len ) ){
- *( (int *) buff ) = ival ? 1 : 0;
- } else {
- c = ostring;
- while( *c && isspace( (int) *c ) ) c++;
- if( *c == 'y' || *c == 'Y' || *c == 't' || *c == 'T' ||
- ( *c == '.' && ( c[1] == 't' || c[1] == 'T' ) ) ){
- *( (int *) buff ) = 1;
- } else if( *c == 'n' || *c == 'N' || *c == 'f' || *c == 'F' ||
- ( *c == '.' && ( c[1] == 'f' || c[1] == 'F' ) ) ){
- *( (int *) buff ) = 0;
- } else {
- ret = 0;
- }
- }
- } else if( type == AST__COMPLEXF ){
- if( nc = 0,
- ( 1 != astSscanf( ostring, "%lf %lf %n", (double *) buff,
- (double *) buff + 1, &nc ) )
- || (nc < len ) ){
- if( nc = 0,
- ( 1 != astSscanf( ostring, "%lf %n", (double *) buff,
- &nc ) )
- || (nc < len ) ){
- ret = 0;
- } else {
- ( (double *) buff )[ 1 ] = 0.0;
- }
- }
- } else if( type == AST__COMPLEXI ){
- if( nc = 0,
- ( 1 != astSscanf( ostring, "%d %d %n", (int *) buff,
- (int *) buff + 1, &nc ) )
- || (nc < len ) ){
- if( nc = 0,
- ( 1 != astSscanf( ostring, "%d %n", (int *) buff, &nc ) )
- || (nc < len ) ){
- ret = 0;
- } else {
- ( (int *) buff )[ 1 ] = 0;
- }
- }
- } else if( astOK ){
- ret = 0;
- astError( AST__INTER, "CnvType: AST internal programming error - "
- "FITS data-type no. %d not yet supported.", status, type );
- }
-
-/* Convert an AST__INT data value to ... */
- } else if( otype == AST__INT ){
- oint = *( (int *) odata );
- if( type == AST__FLOAT ){
- *( (double *) buff ) = (double) oint;
- } else if( type == AST__STRING || type == AST__CONTINUE ){
- (void) sprintf( cnvtype_text, "%d", oint );
- *( (char **) buff ) = cnvtype_text;
- } else if( type == AST__INT ){
- (void) memcpy( buff, odata, osize );
- } else if( type == AST__LOGICAL ){
- *( (int *) buff ) = oint ? 1 : 0;
- } else if( type == AST__COMPLEXF ){
- ( (double *) buff )[ 0 ] = (double) oint;
- ( (double *) buff )[ 1 ] = 0.0;
- } else if( type == AST__COMPLEXI ){
- ( (int *) buff )[ 0 ] = oint;
- ( (int *) buff )[ 1 ] = 0;
- } else if( astOK ){
- ret = 0;
- astError( AST__INTER, "CnvType: AST internal programming error - "
- "FITS data-type no. %d not yet supported.", status, type );
- }
-
-/* Convert a LOGICAL data value to ... */
- } else if( otype == AST__LOGICAL ){
- oint = *( (int *) odata );
- if( type == AST__FLOAT ){
- *( (double *) buff ) = oint ? 1.0 : 0.0;
- } else if( type == AST__STRING || type == AST__CONTINUE ){
- if( oint ){
- strcpy( cnvtype_text, "Y" );
- } else {
- strcpy( cnvtype_text, "N" );
- }
- *( (char **) buff ) = cnvtype_text;
- } else if( type == AST__INT ){
- *( (int *) buff ) = oint;
- } else if( type == AST__LOGICAL ){
- (void) memcpy( buff, odata, osize );
- } else if( type == AST__COMPLEXF ){
- ( (double *) buff )[ 0 ] = oint ? 1.0 : 0.0;
- ( (double *) buff )[ 1 ] = 0.0;
- } else if( type == AST__COMPLEXI ){
- ( (int *) buff )[ 0 ] = oint ? 1 : 0;
- ( (int *) buff )[ 1 ] = 0;
- } else if( astOK ){
- ret = 0;
- astError( AST__INTER, "CnvType: AST internal programming error - "
- "FITS data-type no. %d not yet supported.", status, type );
- }
-
-/* Convert a AST__COMPLEXF data value to ... */
- } else if( otype == AST__COMPLEXF ){
- odouble = ( (double *) odata )[ 0 ];
- if( type == AST__FLOAT ){
- *( (double *) buff ) = odouble;
- } else if( type == AST__STRING || type == AST__CONTINUE ){
- (void) sprintf( cnvtype_text0, "%.*g", DBL_DIG, ( (double *) odata )[ 0 ] );
- CheckZero( cnvtype_text0, ( (double *) odata )[ 0 ], 0, status );
- (void) sprintf( cnvtype_text1, "%.*g", DBL_DIG, ( (double *) odata )[ 1 ] );
- CheckZero( cnvtype_text1, ( (double *) odata )[ 1 ], 0, status );
- (void) sprintf( cnvtype_text, "%s %s", cnvtype_text0, cnvtype_text1 );
- *( (char **) buff ) = cnvtype_text;
- } else if( type == AST__INT ){
- *( (int *) buff ) = (int) odouble;
- } else if( type == AST__LOGICAL ){
- *( (int *) buff ) = ( odouble == 0.0 ) ? 0 : 1;
- } else if( type == AST__COMPLEXF ){
- (void) memcpy( buff, odata, osize );
- } else if( type == AST__COMPLEXI ){
- ( (int *) buff )[ 0 ] = (int) odouble;
- ( (int *) buff )[ 1 ] = (int) ( (double *) odata )[ 1 ];
- } else if( astOK ){
- ret = 0;
- astError( AST__INTER, "CnvType: AST internal programming error - "
- "FITS data-type no. %d not yet supported.", status, type );
- }
-
-/* Convert a AST__COMPLEXI data value to ... */
- } else if( otype == AST__COMPLEXI ){
- oint = ( (int *) odata )[ 0 ];
- if( type == AST__FLOAT ){
- *( (double *) buff ) = (double) oint;
- } else if( type == AST__STRING || type == AST__CONTINUE ){
- (void) sprintf( cnvtype_text, "%d %d", ( (int *) odata )[ 0 ],
- ( (int *) odata )[ 1 ] );
- *( (char **) buff ) = cnvtype_text;
- } else if( type == AST__INT ){
- *( (int *) buff ) = oint;
- } else if( type == AST__LOGICAL ){
- *( (int *) buff ) = oint ? 1 : 0;
- } else if( type == AST__COMPLEXF ){
- ( (double *) buff )[ 0 ] = (double) oint;
- ( (double *) buff )[ 1 ] = (double) ( (int *) odata )[ 1 ];
- } else if( type == AST__COMPLEXI ){
- (void) memcpy( buff, odata, osize );
- } else if( astOK ){
- ret = 0;
- astError( AST__INTER, "CnvType: AST internal programming error - "
- "FITS data-type no. %d not yet supported.", status, type );
- }
- } else if( astOK ){
- ret = 0;
- astError( AST__INTER, "CnvType: AST internal programming error - "
- "FITS data-type no. %d not yet supported.", status, type );
- }
- }
- return ret;
-}
-
-static int ComBlock( AstFitsChan *this, int incr, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* ComBlock
-
-* Purpose:
-* Delete a AST comment block in a Native-encoded FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int ComBlock( AstFitsChan *this, int incr, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function looks for a block of comment cards as defined below,
-* and deletes all the cards in the block, if a suitable block is found.
-*
-* Comment blocks consist of a contiguous sequence of COMMENT cards. The
-* text of each card should start and end with the 3 characters "AST".
-* The block is delimited above by a card containing all +'s (except
-* for the two "AST" strings), and below by a card containing all -'s.
-*
-* The block is assumed to start on the card which is adjacent to the
-* current card on entry.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* incr
-* This should be either +1 or -1, and is the increment between
-* adjacent cards in the comment block. A value of +1 means
-* that the card following the current card is taken as the first in
-* the block, and subsequent cards are checked. The block must then
-* end with a line of -'s. If -1 is supplied, then the card
-* preceding the current card is taken as the first in the block,
-* and preceding cards are checked. The block must then end with
-* a row of +'s.
-* 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:
-* 1 if a block was found and deleted, 0 otherwise.
-
-* Notes:
-* - The pointer to the current card is returned unchanged.
-*/
-
-/* Local Variables: */
- FitsCard *card0; /* Pointer to current FitsCard on entry */
- char del; /* Delimiter character */
- char *text; /* Pointer to the comment text */
- int i; /* Card index within the block */
- int ncard; /* No. of cards in the block */
- int ret; /* The returned flag */
- size_t len; /* Length of the comment text */
-
-/* Check the global status. */
- if( !astOK ) return 0;
-
-/* Save the pointer to the current card. */
- card0 = this->card;
-
-/* Initialise the returned flag to indicate that we have not found a
- comment block. */
- ret = 0;
-
-/* Move on to the first card in the block. If this is not possible (due to
- us already being at the start or end of the FitsChan), then return. */
- if( MoveCard( this, incr, method, class, status ) == 1 ) {
-
-/* Store the character which is used in the delimiter line for the
- comment block. */
- del = ( incr == 1 ) ? '-' : '+';
-
-/* Initialise the number of cards in the comment block to zero. */
- ncard = 0;
-
-/* Loop round until the end (or start) of the comment block is found.
- Leave the loop if an error occurs. */
- while( astOK ) {
-
-/* Is this card a comment card? If not, then we have failed to find a
- complete comment block. Break out of the loop. */
- if( CardType( this, status ) != AST__COMMENT ) break;
-
-/* Increment the number of cards in the comment block. */
- ncard++;
-
-/* Get the text of the comment, and its length. */
- text = CardComm( this, status );
- if( text ){
- len = strlen( text );
-
-/* Check the first 3 characters. Break out of the loop if they are not
- "AST". */
- if( strncmp( "AST", text, 3 ) ) break;
-
-/* Check the last 3 characters. Break out of the loop if they are not
- "AST". */
- if( strcmp( "AST", text + len - 3 ) ) break;
-
-/* If the comment is the appropriate block delimiter (a line of +'s or
- -'s depending on the direction), then set the flag to indicate that we
- have a complete comment block and leave the loop. Allow spaces to be
- included. Exclude the "AST" strings at begining and end from the check. */
- ret = 1;
- for( i = 3; i < len - 3; i++ ) {
- if( text[ i ] != del && text[ i ] != ' ' ) {
- ret = 0;
- break;
- }
- }
- }
- if( ret ) break;
-
-/* Move on to the next card. If this is not possible (due to us already
- being at the start or end of the FitsChan), then break out of the loop. */
- if( MoveCard( this, incr, method, class, status ) == 0 ) break;
- }
-
-/* Re-instate the original current card. */
- this->card = card0;
-
-/* If we found a complete comment block, mark it (which is equivalent to
- deleting it except that memory of the cards location within the
- FitsChan is preserved for future use), and then re-instate the original
- current card. */
- if( ret && astOK ) {
- for( i = 0; i < ncard; i++ ) {
- MoveCard( this, incr, method, class, status );
- MarkCard( this, status );
- }
- this->card = card0;
- }
- }
-
-/* If an error occurred, indicate that coment block has been deleted. */
- if( !astOK ) ret = 0;
- return ret;
-}
-
-static char *ConcatWAT( AstFitsChan *this, int iaxis, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* ConcatWAT
-
-* Purpose:
-* Concatenate all the IRAF "WAT" keywords for an axis.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* char *ConcatWAT( AstFitsChan *this, int iaxis, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function searches the supplied FitsChan for any keywords of
-* the form "WATi_j", where i and j are integers and i is equal to the
-* supplied "iaxis" value plus one, and concatenates their string
-* values into a single string. Such keywords are created by IRAF to
-* describe their non-standard ZPX and TNX projections.
-
-* Parameters:
-* this
-* The FistChan.
-* iaxis
-* The zero-based index of the axis to be retrieved.
-* method
-* The name of the calling method to include in error messages.
-* class
-* The object type to include in error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to a dynamically allocated, null terminated string
-* containing a copy of the concatentated WAT values. This string must
-* be freed by the caller (using astFree) when no longer required.
-*
-* A NULL pointer will be returned if there are no WAT kewyords for
-* the requested axis in the FitsChan.
-
-* Notes:
-* - A NULL pointer value will be returned if this function is
-* invoked with the global error status set or if it should fail
-* for any reason.
-*/
-
-/* Local Variables: */
- char keyname[ FITSNAMLEN + 5 ];/* Keyword name */
- char *wat; /* Pointer to a single WAT string */
- char *result; /* Returned string */
- int watlen; /* Length of total WAT string (inc. term null)*/
- int j; /* WAT index */
- size_t size; /* Length of string value */
-
-/* Initialise returned value. */
- result = NULL;
-
-/* Check inherited status */
- if( !astOK ) return result;
-
-/* Rewind the FitsChan. */
- astClearCard( this );
-
-/* Concatenate all the IRAF "WAT" keywords together for this axis. These
- keywords are marked as having been used, so that they are not written
- out when the FitsChan is deleted. */
- watlen = 1;
- j = 1;
- size = 0;
- sprintf( keyname, "WAT%d_%.3d", iaxis + 1, j );
- while( astOK ) {
-
-/* Search forward from the current card for the next WAT card. If no
- found, try searching again from the start of the FitsChan. If not found
- evenm then, break. */
- if( ! FindKeyCard( this, keyname, method, class, status ) ) {
- astClearCard( this );
- if( ! FindKeyCard( this, keyname, method, class, status ) ) break;
- }
-
- wat = (char *) CardData( this, &size, status );
- result = (char *) astRealloc( (void *) result,
- watlen - 1 + size );
- if( result ) {
- strcpy( result + watlen - 1, wat );
- watlen += size - 1;
- MarkCard( this, status );
- MoveCard( this, 1, method, class, status );
- j++;
- sprintf( keyname, "WAT%d_%.3d", iaxis + 1, j );
- } else {
- break;
- }
- }
-
-/* Return the result. */
- return result;
-}
-
-static int CountFields( const char *temp, char type, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* CountFields
-
-* Purpose:
-* Count the number of field specifiers in a template string.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int CountFields( const char *temp, char type, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns the number of fields which include the
-* specified character type in the supplied string.
-
-* Parameters:
-* temp
-* Pointer to a null terminated string holding the template.
-* type
-* A single character giving the field type to be counted (e.g.
-* 'd', 'c' or 'f').
-* 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:
-* The number of fields.
-
-* Notes:
-* - No error is reported if the parameter "type" is not a valid
-* field type specifier, but zero will be returned.
-* - An error is reported if the template has any invalid field
-* specifiers in it.
-* - A value of zero is returned if an error has already occurred,
-* or if this function should fail for any reason.
-*/
-
-/* Local Variables: */
- const char *b; /* Pointer to next template character */
- int nf; /* No. of fields found so far */
-
-/* Check global status. */
- if( !astOK ) return 0;
-
-/* Initialise a pointer to the start of the template string. */
- b = temp;
-
-/* Initialise the number of fields found so far. */
- nf = 0;
-
-/* Go through the string. */
- while( *b && astOK ){
-
-/* If the current character is a '%', a field is starting. */
- if( *b == '%' ){
-
-/* Skip over the field width (if supplied). */
- if( isdigit( (int) *(++b) ) ) b++;
-
-/* Report an error if the end of the string occurs within the field. */
- if( !*b ) {
- astError( AST__BDFMT, "%s(%s): Incomplete field specifier found "
- "at end of filter template '%s'.", status, method, class,
- temp );
- break;
-
-/* Report an error if the field type is illegal. */
- } else if( *b != 'd' && *b != 'c' && *b != 'f' ) {
- astError( AST__BDFMT, "%s(%s): Illegal field type or width "
- "specifier '%c' found in filter template '%s'.", status,
- method, class, *b, temp );
- break;
- }
-
-/* Compare the field type with the supplied type, and increment the
- number of fields found if it is the correct type. */
- if( *b == type ) nf++;
- }
-
-/* Move on to the next character. */
- b++;
- }
-
-/* If an error has occurred, return 0. */
- if( !astOK ) nf = 0;
-
-/* Return the answer. */
- return nf;
-}
-
-static void CreateKeyword( AstFitsChan *this, const char *name,
- char keyword[ FITSNAMLEN + 1 ], int *status ){
-
-/*
-* Name:
-* CreateKeyword
-
-* Purpose:
-* Create a unique un-used keyword for a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void CreateKeyword( AstFitsChan *this, const char *name,
-* char keyword[ FITSNAMLEN + 1 ], int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function takes a name which forms the basis of a FITS
-* keyword and appends a sequence number (encoded as a pair of
-* legal FITS keyword characters) so as to generate a unique FITS
-* keyword which has not previously been used in the FitsChan
-* supplied.
-*
-* It is intended for use when several keywords with the same name
-* must be stored in a FitsChan, since to comply strictly with the
-* FITS standard keywords should normally be unique (otherwise
-* external software which processes the keywords might omit one or
-* other of the values).
-*
-* An attempt is also made to generate keywords in a form that is
-* unlikely to clash with those from other sources (in as far as
-* this is possible with FITS). In any event, a keyword that
-* already appears in the FitsChan will not be re-used.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a constant null-terminated string containing the
-* name on which the new keyword should be based. This should be
-* a legal FITS keyword in itself, except that it should be at
-* least two characters shorter than the maximum length, in
-* order to accommodate the sequence number characters.
-*
-* If this string is too long, it will be silently
-* truncated. Mixed case is permitted, as all characters
-* supplied are converted to upper case before use.
-* keyword
-* A character array in which the generated unique keyword will
-* be returned, null terminated.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- const char *seq_chars = SEQ_CHARS;/* Pointer to characters used for encoding */
- char seq_char; /* The first sequence character */
- const char *class; /* Object clas */
- int found; /* Keyword entry found in list? */
- int limit; /* Sequence number has reached limit? */
- int nc; /* Number of basic keyword characters */
- int seq; /* The sequence number */
-
-/* Check the global error status. */
- if( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Store the object class. */
- class = astGetClass( this );
-
-/* On the first invocation only, determine the number of characters
- being used to encode sequence number information and save this
- value. */
- if( createkeyword_seq_nchars < 0 ) createkeyword_seq_nchars = (int) strlen( seq_chars );
-
-/* Copy the name supplied into the output array, converting to upper
- case. Leave space for two characters to encode a sequence
- number. Terminate the resulting string. */
- for( nc = 0; ( nc < ( FITSNAMLEN - 2 ) ) && name[ nc ]; nc++ ) {
- keyword[ nc ] = toupper( name[ nc ] );
- }
- keyword[ nc ] = '\0';
-
-/* We now search the list of sequence numbers already allocated to
- find the next one to use for this keyword. */
- if( this->keyseq ) {
- found = astMapGet0I( this->keyseq, keyword, &seq );
- } else {
- found = 0;
- this->keyseq = astKeyMap( " ", status );
- }
-
-/* If the keyword was not found in the list, create a new list entry
- to describe it. */
- if( !found ) seq = 0;
-
-/* If OK, loop to find a new sequence number which results in a FITS
- keyword that hasn't already been used to store data in the
- FitsChan. */
- if( astOK ) {
- while( 1 ) {
-
-/* Determine if the sequence number just obtained has reached the
- upper limit. This is unlikely to happen in practice, but if it
- does, we simply re-use this maximum value. Otherwise, we increment
- the sequence number last used for this keyword to obtain a new
- one. */
- limit = ( seq >= ( createkeyword_seq_nchars * createkeyword_seq_nchars - 1 ) );
- if( !limit ) seq++;
-
-/* Encode the sequence number into two characters and append them to
- the original keyword (with a terminating null). */
- seq_char = seq_chars[ seq / createkeyword_seq_nchars ];
- keyword[ nc ] = seq_char;
- keyword[ nc + 1 ] = seq_chars[ seq % createkeyword_seq_nchars ];
- keyword[ nc + 2 ] = '\0';
-
-/* If the upper sequence number limit has not been reached, try to
- look up the resulting keyword in the FitsChan to see if it has
- already been used. Quit searching when a suitable keyword is
- found. */
- if ( limit || !HasCard( this, keyword, "astWrite", class, status ) ) break;
- }
-
-/* Store the update sequence number in the keymap. The keys into this
- keymap are the base keyword name without the appended sequence string, so
- temporaily terminate the returned keyword name to exclude the sequence
- string. */
- keyword[ nc ] = '\0';
- astMapPut0I( this->keyseq, keyword, seq, NULL );
- keyword[ nc ] = seq_char;
- }
-}
-
-static double DateObs( const char *dateobs, int *status ) {
-/*
-* Name:
-* DateObs
-
-* Purpose:
-* Convert a FITS DATE-OBS keyword value to a MJD.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* double DateObs( const char *dateobs, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Extracts the date and time fields from the supplied string and converts
-* them into a modified Julian Date. Supports both old "dd/mm/yy"
-* format, and the new "ccyy-mm-ddThh:mm:ss[.sss...]" format.
-
-* Parameters:
-* dateobs
-* Pointer to the DATE-OBS string.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The Modified Julian Date corresponding to the supplied DATE-OBS
-* string.
-
-* Notes:
-* - The value AST__BAD is returned (without error) if the supplied
-* string does not conform to the requirements of a FITS DATE-OBS value,
-* or if an error has already occurred.
-*/
-
-/* Local Variables: */
- double days; /* The hours, mins and secs as a fraction of a day */
- double ret; /* The returned MJD value */
- double secs; /* The total value of the two seconds fields */
- int dd; /* The day field from the supplied string */
- int fsc; /* The fractional seconds field from the supplied string */
- int hr; /* The hour field from the supplied string */
- int j; /* SLALIB status */
- int len; /* The length of the supplied string */
- int mm; /* The month field from the supplied string */
- int mn; /* The minute field from the supplied string */
- int nc; /* Number of characters used */
- int ok; /* Was the string of a legal format? */
- int rem; /* The least significant digit in fsc */
- int sc; /* The whole seconds field from the supplied string */
- int yy; /* The year field from the supplied string */
-
-/* Check the global status. */
- if( !astOK ) return AST__BAD;
-
-/* Initialise the returned value. */
- ret = AST__BAD;
-
-/* Save the length of the supplied string. */
- len = (int) strlen( dateobs );
-
-/* Extract the year, month, day, hour, minute, second and fractional
- seconds fields from the supplied string. Assume initially that the
- string does not match any format. */
- ok = 0;
-
-/* First check for the old "dd/mm/yy" format. */
- if( nc = 0,
- ( astSscanf( dateobs, " %2d/%2d/%d %n", &dd, &mm, &yy, &nc ) == 3 ) &&
- ( nc >= len ) ){
- ok = 1;
- hr = 0;
- mn = 0;
- sc = 0;
- fsc = 0;
-
-/* Otherwise, check for the new short format "ccyy-mm-dd". */
- } else if( nc = 0,
- ( astSscanf( dateobs, " %4d-%2d-%2d %n", &yy, &mm, &dd, &nc ) == 3 ) &&
- ( nc >= len ) ){
- ok = 1;
- hr = 0;
- mn = 0;
- sc = 0;
- fsc = 0;
-
-/* Otherwise, check for the new format "ccyy-mm-ddThh:mm:ss" without a
- fractional seconds field or the trailing Z. */
- } else if( nc = 0,
- ( astSscanf( dateobs, " %4d-%2d-%2dT%2d:%2d:%2d %n", &yy, &mm, &dd,
- &hr, &mn, &sc, &nc ) == 6 ) && ( nc >= len ) ){
- ok = 1;
- fsc = 0;
-
-/* Otherwise, check for the new format "ccyy-mm-ddThh:mm:ss.sss" with a
- fractional seconds field but without the trailing Z. */
- } else if( nc = 0,
- ( astSscanf( dateobs, " %4d-%2d-%2dT%2d:%2d:%2d.%d %n", &yy, &mm, &dd,
- &hr, &mn, &sc, &fsc, &nc ) == 7 ) && ( nc >= len ) ){
- ok = 1;
-
-/* Otherwise, check for the new format "ccyy-mm-ddThh:mm:ssZ" without a
- fractional seconds field but with the trailing Z. */
- } else if( nc = 0,
- ( astSscanf( dateobs, " %4d-%2d-%2dT%2d:%2d:%2dZ %n", &yy, &mm, &dd,
- &hr, &mn, &sc, &nc ) == 6 ) && ( nc >= len ) ){
- ok = 1;
- fsc = 0;
-
-/* Otherwise, check for the new format "ccyy-mm-ddThh:mm:ss.sssZ" with a
- fractional seconds field and the trailing Z. */
- } else if( nc = 0,
- ( astSscanf( dateobs, " %4d-%2d-%2dT%2d:%2d:%2d.%dZ %n", &yy, &mm, &dd,
- &hr, &mn, &sc, &fsc, &nc ) == 7 ) && ( nc >= len ) ){
- ok = 1;
- }
-
-/* If the supplied string was legal, create a MJD from the separate fields. */
- if( ok ) {
-
-/* Get the MJD at the start of the day. */
- palCaldj( yy, mm, dd, &ret, &j );
-
-/* If succesful, convert the hours, minutes and seconds to a fraction of
- a day, and add it onto the MJD found above. */
- if( j == 0 ) {
-
-/* Obtain a floating point representation of the fractional seconds
- field. */
- secs = 0.0;
- while ( fsc > 0 ) {
- rem = ( fsc % 10 );
- fsc /= 10;
- secs = 0.1 * ( secs + (double) rem );
- }
-
-/* Add on the whole seconds field. */
- secs += (double) sc;
-
-/*Convert the hours, minutes and seconds to a fractional day. */
- palDtf2d( hr, mn, secs, &days, &j );
-
-/* If succesful, add this onto the returned MJD. */
- if( j == 0 ) {
- ret = ret + days;
-
-/* If the conversion to MJD failed, return AST__BAD. */
- } else {
- ret = AST__BAD;
- }
- } else {
- ret = AST__BAD;
- }
- }
-
-/* Return the result. */
- return ret;
-}
-
-static void DeleteCard( AstFitsChan *this, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* DeleteCard
-
-* Purpose:
-* Delete the current card from a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void DeleteCard( AstFitsChan *this, const char *method,
-* const char *class )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The current card is removed from the circular linked list of structures
-* stored in the supplied FitsChan, and the memory used to store the
-* structure is then freed.
-
-* Parameters:
-* this
-* Pointer to the FitsChan containing the list.
-* method
-* Name of calling method.
-* class
-* Object class.
-
-* Notes:
-* - This function returns without action if the FitsChan is
-* currently at "end-of-file".
-* - The next card becomes the current card.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- FitsCard *card; /* Pointer to the current card */
- FitsCard *next; /* Pointer to next card in list */
- FitsCard *prev; /* Pointer to previous card in list */
-
-/* Return if the supplied object or current card is NULL. */
- if( !this || !this->card ) return;
-
-/* Get a pointer to the card to be deleted (the current card). */
- card = (FitsCard *) this->card;
-
-/* Remove it from the KeyMap holding all keywords. */
- astMapRemove( this->keywords, card->name );
-
-/* Move the current card on to the next card. */
- MoveCard( this, 1, method, class, status );
-
-/* Save pointers to the previous and next cards in the list. */
- prev = GetLink( card, PREVIOUS, method, class, status );
- next = GetLink( card, NEXT, method, class, status );
-
-/* If the backwards link points back to the supplied card, then it must
- be the only one left on the list. */
- if( prev == card ) prev = NULL;
- if( next == card ) next = NULL;
-
-/* If the list head is to be deleted, store a value for the new list
- head. */
- if( this->head == (void *) card ) this->head = (void *) next;
-
-/* Free the memory used to hold the data value. */
- (void) astFree( card->data );
-
-/* Free the memory used to hold any comment. */
- if( card->comment ) (void) astFree( (void *) card->comment );
-
-/* Free the memory used to hold the whole structure. */
- (void) astFree( (void *) card );
-
-/* Fix up the links between the two adjacent cards in the list, unless the
- supplied card was the last one in the list. */
- if( prev && next ){
- next->prev = prev;
- prev->next = next;
- } else {
- this->head = NULL;
- this->card = NULL;
- }
-
-/* Return. */
- return;
-}
-
-static void DelFits( AstFitsChan *this, int *status ){
-
-/*
-*++
-* Name:
-c astDelFits
-f AST_DELFITS
-
-* Purpose:
-* Delete the current FITS card in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-c void astDelFits( AstFitsChan *this )
-f CALL AST_DELFITS( THIS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function deletes the current FITS card from a FitsChan. The
-f This routine deletes the current FITS card from a FitsChan. The
-* current card may be selected using the Card attribute (if its index
-c is known) or by using astFindFits (if only the FITS keyword is
-f is known) or by using AST_FINDFITS (if only the FITS keyword is
-* known).
-*
-* After deletion, the following card becomes the current card.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - This function returns without action if the FitsChan is
-* initially positioned at the "end-of-file" (i.e. if the Card
-* attribute exceeds the number of cards in the FitsChan).
-* - If there are no subsequent cards in the FitsChan, then the
-* Card attribute is left pointing at the "end-of-file" after
-* deletion (i.e. is set to one more than the number of cards in
-* the FitsChan).
-*--
-*/
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Delete the current card. The next card will be made the current card. */
- DeleteCard( this, "astDelFits", astGetClass( this ), status );
-}
-
-static void DistortMaps( AstFitsChan *this, FitsStore *store, char s,
- int naxes, AstMapping **map1, AstMapping **map2,
- AstMapping **map3, AstMapping **map4,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* DistortMap
-
-* Purpose:
-* Create a Mapping representing a FITS-WCS Paper IV distortion code.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void DistortMaps( AstFitsChan *this, FitsStore *store, char s,
-* int naxes, AstMapping **map1, AstMapping **map2,
-* AstMapping **map3, AstMapping **map4,
-* const char *method, const char *class )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function checks the CTYPE keywords in the supplied FitsStore to see
-* if they contain a known distortion code (following the syntax described
-* in FITS-WCS paper IV). If so, Mappings are returned which represent the
-* distortions to be applied at each stage in the pixel->IWC chain. If
-* any distortion codes are found in the FitsStore CTYPE values, whether
-* recognised or not, the CTYPE values in the FitsStore are modified to
-* remove the distortion code. Warnings about any unknown or inappropriate
-* distortion codes are added to the FitsChan.
-
-* Parameters:
-* this
-* The FitsChan. ASTWARN cards may be added to this FitsChan if any
-* anomalies are found in the keyword values in the FitsStore.
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* naxes
-* The number of intermediate world coordinate axes (WCSAXES).
-* map1
-* Address of a location at which to store a pointer to a Mapping
-* which describes any distortion to be applied to pixel
-* coordinates, prior to performing the translation specified by the
-* CRPIXj keywords. NULL is returned if no distortion is necessary.
-* map2
-* Address of a location at which to store a pointer to a Mapping
-* which describes any distortion to be applied to translated pixel
-* coordinates, prior to performing the PC matrix multiplication.
-* NULL is returned if no distortion is necessary.
-* map3
-* Address of a location at which to store a pointer to a Mapping
-* which describes any distortion to be applied to unscaled IWC
-* coordinates, prior to performing the CDELT matrix multiplication.
-* NULL is returned if no distortion is necessary.
-* map4
-* Address of a location at which to store a pointer to a Mapping
-* which describes any distortion to be applied to scaled IWC
-* coordinates, after performing the CDELT matrix multiplication.
-* NULL is returned if no distortion is necessary.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-*/
-
-/* Local Variables: */
- AstMapping *tmap1; /* Mapping pointer */
- AstMapping *tmap2; /* Mapping pointer */
- char *ctype; /* Pointer to CTYPE value */
- char code[ 4 ]; /* Projection code extracted from CTYPE */
- char dist[ 4 ]; /* Distortion code extracted from CTYPE */
- char msgbuf[ 250 ]; /* Buffer for warning message */
- char type[ 5 ]; /* Axis type extracted from CTYPE */
- double *dim; /* Array holding array dimensions */
- int found_axes[ 2 ]; /* Index of axes with the distortion code */
- int i; /* FITS axis index */
- int nc; /* No. of characters in CTYPE without "-SIP" */
- int nfound; /* No. of axes with the distortion code */
- int warned; /* Have any ASTWARN cards been issued? */
-
-/* Initialise pointers to the returned Mappings. */
- *map1 = NULL;
- *map2 = NULL;
- *map3 = NULL;
- *map4 = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return;
-
-/* Allocate memory to hold the image dimensions. */
- dim = (double *) astMalloc( sizeof(double)*naxes );
- if( dim ){
-
-/* Note the image dimensions, if known. If not, store AST__BAD values. */
- for( i = 0; i < naxes; i++ ){
- if( !astGetFitsF( this, FormatKey( "NAXIS", i + 1, -1, ' ', status ),
- dim + i ) ) dim[ i ] = AST__BAD;
- }
-
-/* First check each known distortion type... */
-
-/* "-SIP": Spitzer (http://irsa.ipac.caltech.edu/data/SPITZER/docs/files/spitzer/shupeADASS.pdf)
- ============= */
-
-/* Spitzer distortion is limited to 2D. Check the first two axes to see if
- they have "-SIP" codes at the end of their CTYPE values. If they do,
- terminate the ctype string in order to exclude the distortion code (this
- is so that later functions do not need to allow for the possibility of a
- distortion code being present in the CTYPE value). */
- ctype = GetItemC( &(store->ctype), 0, 0, s, NULL, method, class, status );
- if( ctype ){
- nc = astChrLen( ctype ) - 4;
- if( nc >= 0 && !strcmp( ctype + nc, "-SIP" ) ) {
- ctype[ nc ] = 0;
- ctype = GetItemC( &(store->ctype), 1, 0, s, NULL, method, class, status );
- if( ctype ) {
- nc = astChrLen( ctype ) - 4;
- if( nc >= 0 && !strcmp( ctype + nc, "-SIP" ) ) {
- ctype[ nc ] = 0;
-
-/* Create a Mapping describing the distortion (other axes are passed
- unchanged by this Mapping), and add it in series with the returned map2
- (Spitzer distortion is applied to the translated pixel coordinates). */
- tmap1 = SIPMapping( dim, store, s, naxes, method, class, status );
- if( ! *map2 ) {
- *map2 = tmap1;
- } else {
- tmap2 = (AstMapping *) astCmpMap( *map2, tmap1, 1, "", status );
- *map2 = astAnnul( *map2 );
- tmap1 = astAnnul( tmap1 );
- *map2 = tmap2;
- }
- }
- }
- }
- }
-
-/* Check that the "-SIP" code is not included in any axes other than axes
- 0 and 1. Issue a warning if it is, and remove it. */
- warned = 0;
- for( i = 2; i < naxes; i++ ){
- ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- if( ctype ){
- nc = astChrLen( ctype ) - 4;
- if( nc >= 0 && !strcmp( ctype + nc, "-SIP" ) ) {
- if( !warned ){
- warned = 1;
- sprintf( msgbuf, "The \"-SIP\" distortion code can only be "
- "used on axes 1 and 2, but was found in keyword "
- "%s (='%s'). The distortion will be ignored.",
- FormatKey( "CTYPE", i + 1, -1, ' ', status ), ctype );
- Warn( this, "distortion", msgbuf, method, class, status );
- }
- ctype[ nc ] = 0;
- }
- }
- }
-
-/* "-ZPX": IRAF (http://iraf.noao.edu/projects/ccdmosaic/zpx.html)
- ============= */
-
-/* An IRAF ZPX header uses a ZPX projection within each CTYPE value in place
- of the basic ZPN projection. The SpecTrans function converts -ZPX" to
- "-ZPN-ZPX" (i.e. a basic projection of ZPN with a distortion code of
- "-ZPX"). This function then traps and processes the "-ZPX" distortion
- code. */
-
-/* Look for axes that have the "-ZPX" code in their CTYPE values. If any
- are found, check that there are exactly two such axes, and terminate the
- ctype strings in order to exclude the distortion code (this is so that
- later functions do not need to allow for the possibility of a distortion
- code being present in the CTYPE value)*/
- nfound = 0;
- for( i = 0; i < naxes; i++ ){
- ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- if( ctype && 3 == astSscanf( ctype, "%4s-%3s-%3s", type, code, dist ) ){
- if( !strcmp( "ZPX", dist ) ){
- if( nfound < 2 ) found_axes[ nfound ] = i;
- nfound++;
- ctype[ 8 ] = 0;
- }
- }
- }
-
-/* Issue a warning if more than two ZPX axes were found. */
- if( nfound > 2 ) {
- Warn( this, "distortion", "More than two axes were found "
- "with the \"-ZPX\" projection code. A ZPN projection "
- "will be used instead.", method, class, status );
-
-/* Otherwise, create a Mapping describing the distortion (other axes are passed
- unchanged by this Mapping), and add it in series with the returned map4
- (ZPX distortion is applied to the translated, rotated, scaled IWC
- coordinates). */
- } else if( nfound == 2 ){
- tmap1 = ZPXMapping( this, store, s, naxes, found_axes, method,
- class, status );
- if( ! *map4 ) {
- *map4 = tmap1;
- } else {
- tmap2 = (AstMapping *) astCmpMap( *map4, tmap1, 1, "", status );
- *map4 = astAnnul( *map4 );
- tmap1 = astAnnul( tmap1 );
- *map4 = tmap2;
- }
- }
-
-/* (There are currently no other supported distortion codes.) */
-
-/* Finally, check all axes looking for any remaining (and therefore
- unsupported) distortion codes. Issue a warning about them and remove
- them.
- =================================================================== */
-
-/* Indicate that we have not yet issued a warning. */
- warned = 0;
-
-/* Do each IWC axis. */
- for( i = 0; i < naxes; i++ ){
-
-/* Get the CTYPE value for this axis. */
- ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- if( ctype ) {
-
-/* See if has the "4-3-3" form described in FITS-WCS paper IV. */
- if( 3 == astSscanf( ctype, "%4s-%3s-%3s", type, code, dist ) ){
-
-/* Add an ASTWARN card to the FitsChan. Only issue one warning (this avoids
- multiple warnings about the same distortion code in multiple CTYPE values). */
- if( !warned ){
- warned = 1;
- sprintf( msgbuf, "The header contains CTYPE values (e.g. "
- "%s = '%s') which "
- "include a distortion code \"-%s\". AST "
- "currently ignores this distortion. The code "
- "has been removed from the CTYPE values.",
- FormatKey( "CTYPE", i + 1, -1, ' ', status ), ctype, dist );
- Warn( this, "distortion", msgbuf, method, class, status );
- }
-
-/* Terminate the CTYPE value in the FitsStore in order to exclude the distortion
- code. This means that later functions will not need to take account of
- distortion codes. */
- ctype[ 8 ] = 0;
- }
- }
- }
- }
-
-/* Free resources. */
- dim = astFree( dim );
-}
-
-static void DSBSetUp( AstFitsChan *this, FitsStore *store,
- AstDSBSpecFrame *dsb, char s, double crval,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* DSBSetUp
-
-* Purpose:
-* Modify an AstDSBSpecFrame object to reflect the contents of a FitsStore.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* void DSBSetUp( AstFitsChan *this, FitsStore *store,
-* AstDSBSpecFrame *dsb, char s, double crval,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function sets the attributes of the supplied DSBSpecFrame to
-* reflect the values in the supplied FitsStore.
-
-* Parameters:
-* this
-* The FitsChan.
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* dsb
-* Pointer to the DSBSpecFrame.
-* s
-* Alternate axis code.
-* crval
-* The spectral CRVAL value, in the spectral system represented by
-* the supplied DSBSPecFrame.
-* 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.
-
-* Notes:
-* - This implementation follows the conventions of the FITS-CLASS encoding.
-*/
-
-/* Local Variables: */
- AstDSBSpecFrame *dsb_src; /* New DSBSpecFrame in which StdOfRest is source */
- AstDSBSpecFrame *dsb_topo;/* New DSBSpecFrame in which StdOfRest is topo */
- AstFrameSet *fs; /* FrameSet connecting two standards of rest */
- double dsbcentre; /* Topocentric reference (CRVAL) frequency */
- double in[2]; /* Source rest and image frequencies */
- double lo; /* Topocentric Local Oscillator frequency */
- double out[2]; /* Topocentric rest and image frequencies */
-
-/* Check the global status. */
- if ( !astOK ) return;
-
-/* In order to determine the topocentric IF, we need the topocentric
- frequencies corresponding to the RESTFREQ and IMAGFREQ values in the
- FITS header. The values stored in the FITS header are measured in Hz,
- in the source's rest frame, so we need a mapping from frequency in the
- source rest frame to topocentric frequency. Take a copy of the supplied
- DSBSpecFrame and then set its attributes to represent frequency in the
- sources rest frame. */
- dsb_src = astCopy( dsb );
- astSetStdOfRest( dsb_src, AST__SCSOR );
- astSetSystem( dsb_src, AST__FREQ );
- astSetUnit( dsb_src, 0, "Hz" );
-
-/* Take a copy of this DSBSpecFrame and set its standard of rest to
- topocentric. */
- dsb_topo = astCopy( dsb_src );
- astSetStdOfRest( dsb_topo, AST__TPSOR );
-
-/* Now get the Mapping between these. */
- fs = astConvert( dsb_src, dsb_topo, "" );
- dsb_src = astAnnul( dsb_src );
- dsb_topo = astAnnul( dsb_topo );
-
-/* Check a conversion was found. */
- if( fs != NULL ) {
-
-/* Use this Mapping to transform the rest frequency and the image
- frequency from the standard of rest of the source to that of the
- observer. */
- in[ 0 ] = astGetRestFreq( dsb );
- in[ 1 ] = GetItem( &(store->imagfreq), 0, 0, s, NULL, method, class, status );
- astTran1( fs, 2, in, 1, out );
-
-/* The intermediate frequency is half the distance between these two
- frequencies. Note, the IF value is signed so as to put the rest
- frequency in the observed sideband. */
- if( out[ 0 ] != AST__BAD && out[ 1 ] != AST__BAD ) {
-
-/* Store the spectral CRVAL value as the centre frequency of the
- DSBSpecFrame. The public astSetD method interprets the supplied value
- as a value in the spectral system described by the other SpecFrame
- attributes. */
- astSetD( dsb, "DSBCentre", crval );
-
-/* To calculate the topocentric IF we need the topocentric frequency
- equivalent of CRVAL. So take a copy of the DSBSpecFrame, then set it to
- represent topocentric frequency, and read back the DSBCentre value. */
- dsb_topo = astCopy( dsb );
- astSetStdOfRest( dsb_topo, AST__TPSOR );
- astSetSystem( dsb_topo, AST__FREQ );
- astSetUnit( dsb_topo, 0, "Hz" );
- dsbcentre = astGetD( dsb_topo, "DSBCentre" );
- dsb_topo = astAnnul( dsb_topo );
-
-/* We also need the topocentric Local Oscillator frequency. This is
- assumed to be half way between the topocentric IMAGFREQ and RESTFREQ
- values. */
- lo = 0.5*( out[ 1 ] + out[ 0 ] );
-
-/* Set the IF to be the difference between the Local Oscillator frequency
- and the CRVAL frequency. */
- astSetIF( dsb, lo - dsbcentre );
-
-/* Set the DSBSpecFrame to represent the observed sideband */
- astSetC( dsb, "SideBand", "observed" );
- }
-
-/* Free resources. */
- fs = astAnnul( fs );
- }
-}
-
-static int DSSFromStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* DSSFromStore
-
-* Purpose:
-* Store WCS keywords in a FitsChan using DSS encoding.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* int DSSFromStore( AstFitsChan *this, FitsStore *store,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function copies the WCS information stored in the supplied
-* FitsStore into the supplied FitsChan, using DSS encoding.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore.
-* 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 value of 1 is returned if succesfull, and zero is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- const char *comm; /* Pointer to comment string */
- char *cval; /* Pointer to string keyword value */
- const char *pltdecsn;/* PLTDECSN keyword value */
- double amdx[20]; /* AMDXi keyword value */
- double amdy[20]; /* AMDYi keyword value */
- double cdelt; /* CDELT element */
- double cnpix1; /* CNPIX1 keyword value */
- double cnpix2; /* CNPIX2 keyword value */
- double pc; /* PC element */
- double pltdecd; /* PLTDECD keyword value */
- double pltdecm; /* PLTDECM keyword value */
- double pltdecs; /* PLTDECS keyword value */
- double pltrah; /* PLTRAH keyword value */
- double pltram; /* PLTRAM keyword value */
- double pltras; /* PLTRAS keyword value */
- double pltscl; /* PLTSCL keyword value */
- double ppo1; /* PPO1 keyword value */
- double ppo2; /* PPO2 keyword value */
- double ppo3; /* PPO3 keyword value */
- double ppo4; /* PPO4 keyword value */
- double ppo5; /* PPO5 keyword value */
- double ppo6; /* PPO6 keyword value */
- double pvx[22]; /* X projection parameter values */
- double pvy[22]; /* Y projection parameter values */
- double val; /* General purpose value */
- double xpixelsz; /* XPIXELSZ keyword value */
- double ypixelsz; /* YPIXELSZ keyword value */
- int i; /* Loop count */
- int gottpn; /* Is the projection a "TPN" projection? */
- int m; /* Parameter index */
- int ret; /* Returned value. */
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Check the image is 2 dimensional. */
- if( GetMaxJM( &(store->crpix), ' ', status ) != 1 ) return ret;
-
-/* Check the first axis is RA with a TAN or TPN projection. */
- cval = GetItemC( &(store->ctype), 0, 0, ' ', NULL, method, class, status );
- if( !cval ) return ret;
- gottpn = !strcmp( "RA---TPN", cval );
- if( strcmp( "RA---TAN", cval ) && !gottpn ) return ret;
-
-/* Check the second axis is DEC with a TAN or TPN projection. */
- cval = GetItemC( &(store->ctype), 1, 0, ' ', NULL, method, class, status );
- if( !cval ) return ret;
- if( gottpn ) {
- if( strcmp( "DEC--TPN", cval ) ) return ret;
- } else {
- if( strcmp( "DEC--TAN", cval ) ) return ret;
- }
-
-/* Check that LONPOLE is undefined or is 180 degrees. */
- val = GetItem( &(store->lonpole), 0, 0, ' ', NULL, method, class, status );
- if( val != AST__BAD && val != 180.0 ) return ret;
-
-/* Check that the RA/DEC system is FK5. */
- cval = GetItemC( &(store->radesys), 0, 0, ' ', NULL, method, class, status );
- if( !cval || strcmp( "FK5", cval ) ) return ret;
-
-/* Check that equinox is not defined or is 2000.0 */
- val = GetItem( &(store->equinox), 0, 0, ' ', NULL, method, class, status );
- if( val != AST__BAD && val != 2000.0 ) return ret;
-
-/* Get the pixel sizes from the PC/CDELT keywords. They must be defined and
- not be zero. */
- cdelt = GetItem( &(store->cdelt), 0, 0, ' ', NULL, method, class, status );
- if( cdelt == AST__BAD ) return ret;
- pc = GetItem( &(store->pc), 0, 0, ' ', NULL, method, class, status );
- if( pc == AST__BAD ) pc = 1.0;
- xpixelsz = cdelt*pc;
- cdelt = GetItem( &(store->cdelt), 1, 0, ' ', NULL, method, class, status );
- if( cdelt == AST__BAD ) return ret;
- pc = GetItem( &(store->pc), 1, 1, ' ', NULL, method, class, status );
- if( pc == AST__BAD ) pc = 1.0;
- ypixelsz = cdelt*pc;
- if( xpixelsz == 0.0 || ypixelsz == 0.0 ) return ret;
- xpixelsz *= -1000.0;
- ypixelsz *= 1000.0;
-
-/* Check the off-diagonal PC terms are zero. DSS does not allow any rotation. */
- val = GetItem( &(store->pc), 0, 1, ' ', NULL, method, class, status );
- if( val != AST__BAD && val != 0.0 ) return ret;
- val = GetItem( &(store->pc), 1, 0, ' ', NULL, method, class, status );
- if( val != AST__BAD && val != 0.0 ) return ret;
-
-/* Get the required projection parameter values from the store, supplying
- appropriate values if a simple TAN projection is being used. */
- for( m = 0; m < 22; m++ ){
- pvx[ m ] = GetItem( &(store->pv), 0, m, ' ', NULL, method, class, status );
- if( pvx[ m ] == AST__BAD || !gottpn ) pvx[ m ] = ( m == 1 ) ? 1.0 : 0.0;
- pvy[ m ] = GetItem( &(store->pv), 1, m, ' ', NULL, method, class, status );
- if( pvy[ m ] == AST__BAD || !gottpn ) pvy[ m ] = ( m == 1 ) ? 1.0 : 0.0;
- }
-
-/* Check that no other projection parameters have been set. */
- if( GetMaxJM( &(store->pv), ' ', status ) > 21 ) return ret;
-
-/* Check that specific parameters take their required zero value. */
- if( pvx[ 3 ] != 0.0 || pvy[ 3 ] != 0.0 ) return ret;
- for( m = 11; m < 17; m++ ){
- if( pvx[ m ] != 0.0 || pvy[ m ] != 0.0 ) return ret;
- }
- if( pvx[ 18 ] != 0.0 || pvy[ 18 ] != 0.0 ) return ret;
- if( pvx[ 20 ] != 0.0 || pvy[ 20 ] != 0.0 ) return ret;
-
-/* Check that other projection parameters are related correctly. */
- if( !astEQUAL( 2*pvx[ 17 ], pvx[ 19 ] ) ) return ret;
- if( !astEQUAL( pvx[ 17 ], pvx[ 21 ] ) ) return ret;
- if( !astEQUAL( 2*pvy[ 17 ], pvy[ 19 ] ) ) return ret;
- if( !astEQUAL( pvy[ 17 ], pvy[ 21 ] ) ) return ret;
-
-/* Initialise all polynomial co-efficients to zero. */
- for( m = 0; m < 20; m++ ){
- amdx[ m ] = 0.0;
- amdy[ m ] = 0.0;
- }
-
-/* Polynomial co-efficients. There is redundancy here too, so we
- arbitrarily choose to leave AMDX/Y7 and AMDX/Y12 set to zero. */
- amdx[ 0 ] = 3600.0*pvx[ 1 ];
- amdx[ 1 ] = 3600.0*pvx[ 2 ];
- amdx[ 2 ] = 3600.0*pvx[ 0 ];
- amdx[ 3 ] = 3600.0*pvx[ 4 ];
- amdx[ 4 ] = 3600.0*pvx[ 5 ];
- amdx[ 5 ] = 3600.0*pvx[ 6 ];
- amdx[ 7 ] = 3600.0*pvx[ 7 ];
- amdx[ 8 ] = 3600.0*pvx[ 8 ];
- amdx[ 9 ] = 3600.0*pvx[ 9 ];
- amdx[ 10 ] = 3600.0*pvx[ 10 ];
- amdx[ 12 ] = 3600.0*pvx[ 17 ];
- amdy[ 0 ] = 3600.0*pvy[ 1 ];
- amdy[ 1 ] = 3600.0*pvy[ 2 ];
- amdy[ 2 ] = 3600.0*pvy[ 0 ];
- amdy[ 3 ] = 3600.0*pvy[ 4 ];
- amdy[ 4 ] = 3600.0*pvy[ 5 ];
- amdy[ 5 ] = 3600.0*pvy[ 6 ];
- amdy[ 7 ] = 3600.0*pvy[ 7 ];
- amdy[ 8 ] = 3600.0*pvy[ 8 ];
- amdy[ 9 ] = 3600.0*pvy[ 9 ];
- amdy[ 10 ] = 3600.0*pvy[ 10 ];
- amdy[ 12 ] = 3600.0*pvy[ 17 ];
-
-/* The plate scale is the mean of the first X and Y co-efficients. */
- pltscl = 0.5*( amdx[ 0 ] + amdy[ 0 ] );
-
-/* There is redundancy in the DSS encoding. We can choose an arbitrary
- pixel corner (CNPIX1, CNPIX2) so long as we use the corresponding origin
- for the cartesian co-ordinate system in which the plate centre is
- specified (PPO3, PPO6). Arbitrarily set CNPIX1 and CNPIX2 to one. */
- cnpix1 = 1.0;
- cnpix2 = 1.0;
-
-/* Find the corresponding plate centre PPO3 and PPO6 (other co-efficients
- are set to zero). */
- ppo1 = 0.0;
- ppo2 = 0.0;
- val = GetItem( &(store->crpix), 0, 0, ' ', NULL, method, class, status );
- if( val == AST__BAD ) return ret;
- ppo3 = xpixelsz*( val + cnpix1 - 0.5 );
- ppo4 = 0.0;
- ppo5 = 0.0;
- val = GetItem( &(store->crpix), 0, 1, ' ', NULL, method, class, status );
- if( val == AST__BAD ) return ret;
- ppo6 = ypixelsz*( val + cnpix2 - 0.5 );
-
-/* The reference RA. Get it in degrees. */
- val = GetItem( &(store->crval), 0, 0, ' ', NULL, method, class, status );
- if( val == AST__BAD ) return ret;
-
-/* Convert to hours and ensure it is in the range 0 to 24 */
- val /= 15.0;
- while( val < 0 ) val += 24.0;
- while( val >= 24.0 ) val -= 24.0;
-
-/* Split into hours, mins and seconds. */
- pltrah = (int) val;
- val = 60.0*( val - pltrah );
- pltram = (int) val;
- pltras = 60.0*( val - pltram );
-
-/* The reference DEC. Get it in degrees. */
- val = GetItem( &(store->crval), 1, 0, ' ', NULL, method, class, status );
- if( val == AST__BAD ) return ret;
-
-/* Ensure it is in the range -180 to +180 */
- while( val < -180.0 ) val += 360.0;
- while( val >= 180.0 ) val -= 360.0;
-
-/* Save the sign. */
- if( val > 0.0 ){
- pltdecsn = "+";
- } else {
- pltdecsn = "-";
- val = -val;
- }
-
-/* Split into degrees, mins and seconds. */
- pltdecd = (int) val;
- val = 60.0*( val - pltdecd );
- pltdecm = (int) val;
- pltdecs = 60.0*( val - pltdecm );
-
-/* Store the DSS keywords in the FitsChan. */
- SetValue( this, "CNPIX1", &cnpix1, AST__FLOAT, "X corner (pixels)", status );
- SetValue( this, "CNPIX2", &cnpix2, AST__FLOAT, "Y corner (pixels)", status );
- SetValue( this, "PPO1", &ppo1, AST__FLOAT, "Orientation co-efficients", status );
- SetValue( this, "PPO2", &ppo2, AST__FLOAT, "", status );
- SetValue( this, "PPO3", &ppo3, AST__FLOAT, "", status );
- SetValue( this, "PPO4", &ppo4, AST__FLOAT, "", status );
- SetValue( this, "PPO5", &ppo5, AST__FLOAT, "", status );
- SetValue( this, "PPO6", &ppo6, AST__FLOAT, "", status );
- SetValue( this, "XPIXELSZ", &xpixelsz, AST__FLOAT, "X pixel size (microns)", status );
- SetValue( this, "YPIXELSZ", &ypixelsz, AST__FLOAT, "Y pixel size (microns)", status );
- SetValue( this, "PLTRAH", &pltrah, AST__FLOAT, "RA at plate centre", status );
- SetValue( this, "PLTRAM", &pltram, AST__FLOAT, "", status );
- SetValue( this, "PLTRAS", &pltras, AST__FLOAT, "", status );
- SetValue( this, "PLTDECD", &pltdecd, AST__FLOAT, "DEC at plate centre", status );
- SetValue( this, "PLTDECM", &pltdecm, AST__FLOAT, "", status );
- SetValue( this, "PLTDECS", &pltdecs, AST__FLOAT, "", status );
- SetValue( this, "PLTDECSN", &pltdecsn, AST__STRING, "", status );
- SetValue( this, "PLTSCALE", &pltscl, AST__FLOAT, "Plate scale (arcsec/mm)", status );
- comm = "Plate solution x co-efficients";
- for( i = 0; i < 20; i++ ){
- SetValue( this, FormatKey( "AMDX", i + 1, -1, ' ', status ), amdx + i,
- AST__FLOAT, comm, status );
- comm = NULL;
- }
- comm = "Plate solution y co-efficients";
- for( i = 0; i < 20; i++ ){
- SetValue( this, FormatKey( "AMDY", i + 1, -1, ' ', status ), amdy + i,
- AST__FLOAT, comm, status );
- comm = NULL;
- }
-
-/* If no error has occurred, return one. */
- if( astOK ) ret = 1;
-
-/* Return the answer. */
- return ret;
-}
-
-static void DSSToStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* DSSToStore
-
-* Purpose:
-* Extract WCS information from the supplied FitsChan using a DSS
-* encoding, and store it in the supplied FitsStore.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void DSSToStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function extracts DSS keywords from the supplied FitsChan, and
-* stores the corresponding WCS information in the supplied FitsStore.
-* The conversion from DSS encoding to standard WCS encoding is
-* described in an ear;y draft of the Calabretta & Greisen paper
-* "Representations of celestial coordinates in FITS" (A&A, in prep.),
-* and uses the now deprecated "TAN with polynomial corrections",
-* which is still supported by the WcsMap class as type AST__TPN.
-* Here we use "lambda=1" (i.e. plate co-ordinate are measured in mm,
-* not degrees).
-*
-* It is assumed that DSS images are 2 dimensional.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore structure.
-* 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.
-*/
-
-/* Local Variables: */
- char *text; /* Pointer to textual keyword value */
- char pltdecsn[11]; /* First 10 non-blank characters from PLTDECSN keyword */
- char keyname[10]; /* Buffer for keyword name */
- double amdx[20]; /* AMDXi keyword value */
- double amdy[20]; /* AMDYi keyword value */
- double cnpix1; /* CNPIX1 keyword value */
- double cnpix2; /* CNPIX2 keyword value */
- double crval2; /* Equivalent CRVAL2 keyword value */
- double dummy; /* Unused keyword value */
- double pltdecd; /* PLTDECD keyword value */
- double pltdecm; /* PLTDECM keyword value */
- double pltdecs; /* PLTDECS keyword value */
- double pltrah; /* PLTRAH keyword value */
- double pltram; /* PLTRAM keyword value */
- double pltras; /* PLTRAS keyword value */
- double ppo3; /* PPO3 keyword value */
- double ppo6; /* PPO6 keyword value */
- double pv; /* Projection parameter value */
- double xpixelsz; /* XPIXELSZ keyword value */
- double ypixelsz; /* YPIXELSZ keyword value */
- int i; /* Loop count */
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* Get the optional DSS keywords, supplying defaults for any missing keywords. */
- cnpix1 = 0.0;
- cnpix2 = 0.0;
- GetValue( this, "CNPIX1", AST__FLOAT, &cnpix1, 0, 1, method, class, status );
- GetValue( this, "CNPIX2", AST__FLOAT, &cnpix2, 0, 1, method, class, status );
-
-/* Get the required DSS keywords. Report an error if any are missing. */
- GetValue( this, "PPO3", AST__FLOAT, &ppo3, 1, 1, method, class, status );
- GetValue( this, "PPO6", AST__FLOAT, &ppo6, 1, 1, method, class, status );
- GetValue( this, "XPIXELSZ", AST__FLOAT, &xpixelsz, 1, 1, method, class, status );
- GetValue( this, "YPIXELSZ", AST__FLOAT, &ypixelsz, 1, 1, method, class, status );
- GetValue( this, "PLTRAH", AST__FLOAT, &pltrah, 1, 1, method, class, status );
- GetValue( this, "PLTRAM", AST__FLOAT, &pltram, 1, 1, method, class, status );
- GetValue( this, "PLTRAS", AST__FLOAT, &pltras, 1, 1, method, class, status );
- GetValue( this, "PLTDECD", AST__FLOAT, &pltdecd, 1, 1, method, class, status );
- GetValue( this, "PLTDECM", AST__FLOAT, &pltdecm, 1, 1, method, class, status );
- GetValue( this, "PLTDECS", AST__FLOAT, &pltdecs, 1, 1, method, class, status );
-
-/* Copy the first 10 non-blank characters from the PLTDECSN keyword. */
- GetValue( this, "PLTDECSN", AST__STRING, &text, 1, 1, method, class, status );
- if( astOK ) {
- text += strspn( text, " " );
- text[ strcspn( text, " " ) ] = 0;
- strncpy( pltdecsn, text, 10 );
- }
-
-/* Read other related keywords. We do not need these, but we read them
- so that they are not propagated to any output FITS file. */
- GetValue( this, "PLTSCALE", AST__FLOAT, &dummy, 0, 1, method, class, status );
- GetValue( this, "PPO1", AST__FLOAT, &dummy, 0, 1, method, class, status );
- GetValue( this, "PPO2", AST__FLOAT, &dummy, 0, 1, method, class, status );
- GetValue( this, "PPO4", AST__FLOAT, &dummy, 0, 1, method, class, status );
- GetValue( this, "PPO5", AST__FLOAT, &dummy, 0, 1, method, class, status );
-
-/* Get the polynomial co-efficients. These can be defaulted if they are
- missing, so do not report an error. */
- for( i = 0; i < 20; i++ ){
- (void) sprintf( keyname, "AMDX%d", i + 1 );
- amdx[i] = AST__BAD;
- GetValue( this, keyname, AST__FLOAT, amdx + i, 0, 1, method, class, status );
- (void) sprintf( keyname, "AMDY%d", i + 1 );
- amdy[i] = AST__BAD;
- GetValue( this, keyname, AST__FLOAT, amdy + i, 0, 1, method, class, status );
- }
-
-/* Check the above went OK. */
- if( astOK ) {
-
-/* Calculate and store the equivalent PV projection parameters. */
- if( amdx[2] != AST__BAD ) {
- pv = amdx[2]/3600.0;
- SetItem( &(store->pv), 0, 0, ' ', pv, status );
- }
- if( amdx[0] != AST__BAD ) {
- pv = amdx[0]/3600.0;
- SetItem( &(store->pv), 0, 1, ' ', pv, status );
- }
- if( amdx[1] != AST__BAD ) {
- pv = amdx[1]/3600.0;
- SetItem( &(store->pv), 0, 2, ' ', pv, status );
- }
- if( amdx[3] != AST__BAD && amdx[6] != AST__BAD ) {
- pv = ( amdx[3] + amdx[6] )/3600.0;
- SetItem( &(store->pv), 0, 4, ' ', pv, status );
- }
- if( amdx[4] != AST__BAD ) {
- pv = amdx[4]/3600.0;
- SetItem( &(store->pv), 0, 5, ' ', pv, status );
- }
- if( amdx[5] != AST__BAD && amdx[6] != AST__BAD ) {
- pv = ( amdx[5] + amdx[6] )/3600.0;
- SetItem( &(store->pv), 0, 6, ' ', pv, status );
- }
- if( amdx[7] != AST__BAD && amdx[11] != AST__BAD ) {
- pv = ( amdx[7] + amdx[11] )/3600.0;
- SetItem( &(store->pv), 0, 7, ' ', pv, status );
- }
- if( amdx[8] != AST__BAD ) {
- pv = amdx[8]/3600.0;
- SetItem( &(store->pv), 0, 8, ' ', pv, status );
- }
- if( amdx[9] != AST__BAD && amdx[11] != AST__BAD ) {
- pv = ( amdx[9] + amdx[11] )/3600.0;
- SetItem( &(store->pv), 0, 9, ' ', pv, status );
- }
- if( amdx[10] != AST__BAD ) {
- pv = amdx[10]/3600.0;
- SetItem( &(store->pv), 0, 10, ' ', pv, status );
- }
- if( amdx[12] != AST__BAD ) {
- pv = amdx[12]/3600.0;
- SetItem( &(store->pv), 0, 17, ' ', pv, status );
- SetItem( &(store->pv), 0, 19, ' ', 2*pv, status );
- SetItem( &(store->pv), 0, 21, ' ', pv, status );
- }
- if( amdy[2] != AST__BAD ) {
- pv = amdy[2]/3600.0;
- SetItem( &(store->pv), 1, 0, ' ', pv, status );
- }
- if( amdy[0] != AST__BAD ) {
- pv = amdy[0]/3600.0;
- SetItem( &(store->pv), 1, 1, ' ', pv, status );
- }
- if( amdy[1] != AST__BAD ) {
- pv = amdy[1]/3600.0;
- SetItem( &(store->pv), 1, 2, ' ', pv, status );
- }
- if( amdy[3] != AST__BAD && amdy[6] != AST__BAD ) {
- pv = ( amdy[3] + amdy[6] )/3600.0;
- SetItem( &(store->pv), 1, 4, ' ', pv, status );
- }
- if( amdy[4] != AST__BAD ) {
- pv = amdy[4]/3600.0;
- SetItem( &(store->pv), 1, 5, ' ', pv, status );
- }
- if( amdy[5] != AST__BAD && amdy[6] != AST__BAD ) {
- pv = ( amdy[5] + amdy[6] )/3600.0;
- SetItem( &(store->pv), 1, 6, ' ', pv, status );
- }
- if( amdy[7] != AST__BAD && amdy[11] != AST__BAD ) {
- pv = ( amdy[7] + amdy[11] )/3600.0;
- SetItem( &(store->pv), 1, 7, ' ', pv, status );
- }
- if( amdy[8] != AST__BAD ) {
- pv = amdy[8]/3600.0;
- SetItem( &(store->pv), 1, 8, ' ', pv, status );
- }
- if( amdy[9] != AST__BAD && amdy[11] != AST__BAD ) {
- pv = ( amdy[9] + amdy[11] )/3600.0;
- SetItem( &(store->pv), 1, 9, ' ', pv, status );
- }
- if( amdy[10] != AST__BAD ) {
- pv = amdy[10]/3600.0;
- SetItem( &(store->pv), 1, 10, ' ', pv, status );
- }
- if( amdy[12] != AST__BAD ) {
- pv = amdy[12]/3600.0;
- SetItem( &(store->pv), 1, 17, ' ', pv, status );
- SetItem( &(store->pv), 1, 19, ' ', 2*pv, status );
- SetItem( &(store->pv), 1, 21, ' ', pv, status );
- }
-
-/* Calculate and store the equivalent CRPIX values. */
- if( xpixelsz != 0.0 ) {
- SetItem( &(store->crpix), 0, 0, ' ',
- ( ppo3/xpixelsz ) - cnpix1 + 0.5, status );
- } else if( astOK ){
- astError( AST__BDFTS, "%s(%s): FITS keyword XPIXELSZ has illegal "
- "value 0.0", status, method, class );
- }
- if( ypixelsz != 0.0 ) {
- SetItem( &(store->crpix), 0, 1, ' ',
- ( ppo6/ypixelsz ) - cnpix2 + 0.5, status );
- } else if( astOK ){
- astError( AST__BDFTS, "%s(%s): FITS keyword YPIXELSZ has illegal "
- "value 0.0", status, method, class );
- }
-
-/* Calculate and store the equivalent CRVAL values. */
- SetItem( &(store->crval), 0, 0, ' ',
- 15.0*( pltrah + pltram/60.0 + pltras/3600.0 ), status );
- crval2 = pltdecd + pltdecm/60.0 + pltdecs/3600.0;
- if( !strcmp( pltdecsn, "-") ) crval2 = -crval2;
- SetItem( &(store->crval), 1, 0, ' ', crval2, status );
-
-/* Calculate and store the equivalent PC matrix. */
- SetItem( &(store->pc), 0, 0, ' ', -0.001*xpixelsz, status );
- SetItem( &(store->pc), 1, 1, ' ', 0.001*ypixelsz, status );
-
-/* Set values of 1.0 for the CDELT values. */
- SetItem( &(store->cdelt), 0, 0, ' ', 1.0, status );
- SetItem( &(store->cdelt), 1, 0, ' ', 1.0, status );
-
-/* Store remaining constant items */
- SetItem( &(store->lonpole), 0, 0, ' ', 180.0, status );
- SetItem( &(store->equinox), 0, 0, ' ', 2000.0, status );
- SetItemC( &(store->radesys), 0, 0, ' ', "FK5", status );
- SetItem( &(store->wcsaxes), 0, 0, ' ', 2.0, status );
- store->naxis = 2;
- SetItemC( &(store->ctype), 0, 0, ' ', "RA---TPN", status );
- SetItemC( &(store->ctype), 1, 0, ' ', "DEC--TPN", status );
- }
-}
-
-static void EmptyFits( AstFitsChan *this, int *status ){
-
-/*
-*++
-* Name:
-c astEmptyFits
-f AST_EMPTYFITS
-
-* Purpose:
-* Delete all cards in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-c void astEmptyFits( AstFitsChan *this )
-f CALL AST_EMPTYFITS( THIS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* deletes all cards and associated information from a FitsChan.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - This method simply deletes the cards currently in the FitsChan.
-c Unlike astWriteFits,
-f Unlike AST_WRITEFITS,
-* they are not first written out to the sink function or sink file.
-* - Any Tables or warnings stored in the FitsChan are also deleted.
-* - This method attempt to execute even if an error has occurred
-* previously.
-*--
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- const char *class; /* Pointer to string holding object class */
- const char *method; /* Pointer to string holding calling method */
- int old_ignore_used; /* Original setting of ignore_used variable */
-
-/* Check a FitsChan was supplied. */
- if( !this ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Store the method and class strings. */
- method = "astEmpty";
- class = astGetClass( this );
-
-/* Delete all cards from the circular linked list stored in the FitsChan,
- starting with the card at the head of the list. */
- old_ignore_used = ignore_used;
- ignore_used = 0;
- astClearCard( this );
- while( !astFitsEof( this ) ) DeleteCard( this, method, class, status );
- ignore_used = old_ignore_used;
-
-/* Delete the KeyMap which holds keywords and the latest sequence number
- used by each of them. */
- if( this->keyseq ) this->keyseq = astAnnul( this->keyseq );
-
-/* Delete the KeyMap holding the keyword names. */
- if( this->keywords ) this->keywords = astAnnul( this->keywords );
-
-/* Free any memory used to hold the Warnings attribute value. */
- this->warnings = astFree( this->warnings );
-
-/* Other objects in the FitsChan structure. */
- if( this->tables ) this->tables = astAnnul( this->tables );
-}
-
-static int EncodeFloat( char *buf, int digits, int width, int maxwidth,
- double value, int *status ){
-/*
-*
-* Name:
-* EncodeFloat
-
-* Purpose:
-* Formats a floating point value.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int EncodeFloat( char *buf, int digits, int width, int maxwidth,
-* double value, int *status )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function formats the value using a G format specified in order
-* to use the minimum field width (trailing zeros are not printed).
-* However, the G specifier does not include a decimal point unless it
-* is necessary. FITS requires that floating point values always include
-* a decimal point, so this function inserts one, if necessary.
-
-* Parameters:
-* buf
-* A character string into which the value is written.
-* digits
-* The number of digits after the decimal point. If the supplied value
-* is negative, the number of digits actually used may be reduced if
-* the string would otherwise extend beyond the number of columns
-* allowed by the FITS standard. If the value is positive, the
-* specified number of digits are always produced, even if it means
-* breaking the FITS standard.
-* width
-* The minimum field width to use. The value is right justified in
-* this field width.
-* maxwidth
-* The maximum field width to use. A value of zero is returned if
-* the maximum field width is exceeded.
-* value
-* The value to format.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The field width actually used, or zero if the value could not be
-* formatted. This does not include the trailing null character.
-
-* Notes:
-* - If there is room, a trailing zero is also added following the
-* inserted decimal point.
-*/
-
-/* Local Variables: */
- char *c;
- char *w, *r;
- int i;
- int ldigits;
- int n;
- int ret;
-
-/* Check the global error status. */
- if ( !astOK ) return 0;
-
-/* The supplied value of "digits" may be negative. Obtain the positive
- value giving the initial number of decimal digits to use. */
- ldigits = ( digits > 0 ) ? digits : -digits;
-
-/* Loop until a suitably encoded value has been obtained. */
- while( 1 ){
-
-/* Write the value into the buffer. Most are formatted with a G specifier.
- This will result in values between -0.001 and -0.0001 being formatted
- without an exponent, and thus occupying (ldigits+6) characters. With
- an exponent, these values would be formatted in (ldigits+5) characters
- thus saving one character. This is important because the default value
- of ldigits is 15, resulting in 21 characters being used by the G
- specifier. This is one more than the maximum allowed by the FITS
- standard. Using an exponent instead would result in 20 characters
- being used without any loss of precision, thus staying within the FITS
- limit. Note, the precision used with the E specifier is one less than
- with the G specifier because the digit to the left of the decimal place
- is significant with the E specifier, and so we only need (ldigits-1)
- significant digits to the right of the decimal point. */
- if( value > -0.001 && value < -0.0001 ) {
- (void) sprintf( buf, "%*.*E", width, ldigits - 1, value );
- } else {
- (void) sprintf( buf, "%*.*G", width, ldigits, value );
- }
-
-/* Check that the value zero is not encoded with a minus sign (e.g. "-0.").
- This also rounds out long sequences of zeros or nines. */
- CheckZero( buf, value, width, status );
-
-/* If the formatted value includes an exponent, it will have 2 digits.
- If the exponent includes a leading zero, remove it. */
- if( ( w = strstr( buf, "E-0" ) ) ) {
- w += 2;
- } else if( ( w = strstr( buf, "E+0" ) ) ){
- w += 2;
- } else if( ( w = strstr( buf, "E0" ) ) ){
- w += 1;
- }
-
-/* If a leading zero was found, shuffle everything down from the start of
- the string by one character, over-writing the redundant zero, and insert
- a space at the start of the string. */
- if( w ) {
- r = w - 1 ;
- while( w != buf ) *(w--) = *(r--);
- *w = ' ';
- }
-
-/* If the used field width was too large, reduce it and try again, so
- long as we are allowed to change the number of digits being used. */
- ret = strlen( buf );
- if( ret > width && digits < 0 ){
- ldigits -= ( ret - width );
-
-/* Otherwise leave the loop. Return zero field width if the maximum field
- width was exceeded. */
- } else {
- if( ret > maxwidth ) ret = 0;
- break;
- }
- }
-
-/* If a formatted value was obtained, we need to ensure that the it includes
- a decimal point. */
- if( ret ){
-
-/* Get a pointer to the first digit in the buffer. */
- c = strpbrk( buf, "0123456789" );
-
-/* Something funny is going on if there are no digits in the buffer,
- so return a zero field width. */
- if( !c ){
- ret = 0;
-
-/* Otherwise... */
- } else {
-
-/* Find the number of digits following and including the first digit. */
- n = strspn( c, "0123456789" );
-
-/* If the first non-digit character is a decimal point, do nothing. */
- if( c[ n ] != '.' ){
-
-/* If there are two or more leading spaces, move the start of the string
- two character to the left, and insert ".0" in the gap created. This
- keeps the field right justified within the desired field width. */
- if( buf[ 0 ] == ' ' && buf[ 1 ] == ' ' ){
- for( i = 2; i < c - buf + n; i++ ) buf[ i - 2 ] = buf[ i ];
- c[ n - 2 ] = '.';
- c[ n - 1 ] = '0';
-
-/* If there is just one leading space, move the start of the string
- one character to the left, and insert "." in the gap created. This
- keeps the field right justified within the desired field width. */
- } else if( buf[ 0 ] == ' ' ){
- for( i = 0; i < n; i++ ) c[ i - 1 ] = c[ i ];
- c[ n - 1 ] = '.';
-
-/* If there are no leading spaces we need to move the end of the string
- to the right. This will result in the string no longer being right
- justified in the required field width. Return zero if there is
- insufficient room for an extra character. */
- } else {
- ret++;
- if( ret > maxwidth ){
- ret = 0;
-
-/* Otherwise, more the end of the string one place to the right and insert
- the decimal point. */
- } else {
- for( i = strlen( c ); i >= n; i-- ) c[ i + 1 ] = c[ i ];
- c[ n ] = '.';
- }
- }
- }
- }
- }
-
-/* Return the field width. */
- return ret;
-}
-
-static int EncodeValue( AstFitsChan *this, char *buf, int col, int digits,
- const char *method, int *status ){
-
-/*
-* Name:
-* EncodeValue
-
-* Purpose:
-* Encode the current card's keyword value into a string.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int EncodeValue( AstFitsChan *this, char *buf, int col, int digits,
-* const char *method, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function encodes the keyword value defined in the current card
-* of the supplied FitsChan and stores it at the start of the supplied
-* buffer. The number of characters placed in the buffer is returned
-* (not including a terminating null).
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* buf
-* The buffer to receive the formatted value. This should be at least
-* 70 characters long.
-* col
-* The column number within the FITS header card corresponding to the
-* start of "buf".
-* digits
-* The number of digits to use when formatting floating point
-* values. If the supplied value is negative, the number of digits
-* actually used may be reduced if the string would otherwise extend
-* beyond the number of columns allowed by the FITS standard. If the
-* value is positive, the specified number of digits are always
-* produced, even if it means breaking the FITS standard.
-* method
-* Pointer to a string holding the name of the calling method.
-* This is only for use in constructing error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The number of columns used by the encoded value.
-
-* Notes:
-* - The function returns 0 if an error has already occurred
-* or if an error occurs for any reason within this function.
-*/
-
-/* Local Variables: */
- char *c; /* Pointer to next character */
- char *name; /* Pointer to the keyword name */
- double dval; /* Keyword value */
- void *data; /* Pointer to keyword value */
- int i; /* Loop count */
- int ilen; /* Length of imaginary part */
- int len; /* Returned length */
- int quote; /* Quote character found? */
- int rlen; /* Length of real part */
- int type; /* Data type for keyword in current card */
-
-/* Check the global status. */
- if( !astOK ) return 0;
-
-/* Initialise returned length. */
- len = 0;
-
-/* Get the data type of the keyword. */
- type = CardType( this, status );
-
-/* Get a pointer to the data value in the current card. */
- data = CardData( this, NULL, status );
-
-/* Return if there is no defined value associated with the keyword in the
- current card. */
- if( type != AST__UNDEF ) {
-
-/* Get the name of the keyword. */
- name = CardName( this, status );
-
-/* Go through each supported data type (roughly in the order of
- decreasing usage)... */
-
-/* AST__FLOAT - stored internally in a variable of type "double". Right
- justified to column 30 in the header card. */
- if( type == AST__FLOAT ){
- dval = *( (double *) data );
- len = EncodeFloat( buf, digits, FITSRLCOL - FITSNAMLEN - 2,
- AST__FITSCHAN_FITSCARDLEN - col + 1, dval, status );
- if( len <= 0 && astOK ) {
- astError( AST__BDFTS, "%s(%s): Cannot encode floating point value "
- "%g into a FITS header card for keyword '%s'.", status, method,
- astGetClass( this ), dval, name );
- }
-
-/* AST__STRING & AST__CONTINUE - stored internally in a null terminated array of
- type "char". The encoded string is enclosed in single quotes, starting
- at FITS column 11 and ending in at least column 20. Single quotes
- in the string are replaced by two adjacent single quotes. */
- } else if( type == AST__STRING || type == AST__CONTINUE ){
- c = (char *) data;
-
-/* Enter the opening quote. */
- len = 0;
- buf[ len++ ] = '\'';
-
-/* Inspect each character, looking for quotes. */
- for ( i = 0; c[ i ]; ) {
- quote = ( c[ i ] == '\'' );
-
-/* If it will not fit into the header card (allowing for doubled
- quotes), give up here. */
- if ( len + ( quote ? 2 : 1 ) > AST__FITSCHAN_FITSCARDLEN - col ) break;
-
-/* Otherwise, copy it into the output buffer and double any quotes. */
- buf[ len++ ] = c[ i ];
- if ( quote ) buf[ len++ ] = '\'';
-
-/* Look at the next character. */
- i++;
- }
-
-/* Pad the string out to the required minimum length with blanks and
- add the final quote. */
- while( len < FITSSTCOL - col ) buf[ len++ ] = ' ';
- buf[ len++ ] = '\'';
-
-/* Inspect any characters that weren't used. If any are non-blank,
- report an error. */
- for ( ; c[ i ]; i++ ) {
- if ( !isspace( c[ i ] ) ) {
- astError( AST__BDFTS,
- "%s(%s): Cannot encode string '%s' into a FITS "
- "header card for keyword '%s'.", status, method, astGetClass( this ),
- (char *) data, name );
- break;
- }
- }
-
-/* INTEGER - stored internally in a variable of type "int". Right justified
- to column 30 in the header card. */
- } else if( type == AST__INT ){
- len = sprintf( buf, "%*d", FITSRLCOL - col + 1,
- *( (int *) data ) );
- if( len < 0 || len > AST__FITSCHAN_FITSCARDLEN - col ) {
- astError( AST__BDFTS, "%s(%s): Cannot encode integer value %d into a "
- "FITS header card for keyword '%s'.", status, method, astGetClass( this ),
- *( (int *) data ), name );
- }
-
-/* LOGICAL - stored internally in a variable of type "int". Represented by
- a "T" or "F" in column 30 of the FITS header card. */
- } else if( type == AST__LOGICAL ){
- for( i = 0; i < FITSRLCOL - col; i++ ) buf[ i ] = ' ';
- if( *( (int *) data ) ){
- buf[ FITSRLCOL - col ] = 'T';
- } else {
- buf[ FITSRLCOL - col ] = 'F';
- }
- len = FITSRLCOL - col + 1;
-
-/* AST__COMPLEXF - stored internally in an array of two "doubles". The real
- part is right justified to FITS column 30. The imaginary part is right
- justified to FITS column 50. */
- } else if( type == AST__COMPLEXF ){
- dval = ( (double *) data )[ 0 ];
- rlen = EncodeFloat( buf, digits, FITSRLCOL - FITSNAMLEN - 2,
- AST__FITSCHAN_FITSCARDLEN - col + 1, dval, status );
- if( rlen <= 0 || rlen > AST__FITSCHAN_FITSCARDLEN - col ) {
- astError( AST__BDFTS, "%s(%s): Cannot encode real part of a complex "
- "floating point value [%g,%g] into a FITS header card "
- "for keyword '%s'.", status, method, astGetClass( this ), dval,
- ( (double *) data )[ 1 ], name );
- } else {
- dval = ( (double *) data )[ 1 ];
- ilen = EncodeFloat( buf + rlen, digits,
- FITSIMCOL - FITSRLCOL,
- AST__FITSCHAN_FITSCARDLEN - col - rlen, dval, status );
- if( ilen <= 0 ) {
- astError( AST__BDFTS, "%s(%s): Cannot encode imaginary part of a "
- "complex floating point value [%g,%g] into a FITS header "
- "card for keyword '%s'.", status, method, astGetClass( this ),
- ( (double *) data )[ 0 ], dval, name );
- } else {
- len = ilen + rlen;
- }
- }
-
-/* AST__COMPLEXI - stored internally in a an array of two "ints". */
- } else if( type == AST__COMPLEXI ){
- rlen = sprintf( buf, "%*d", FITSRLCOL - col + 1,
- ( (int *) data )[ 0 ] );
- if( rlen < 0 || rlen > AST__FITSCHAN_FITSCARDLEN - col ) {
- astError( AST__BDFTS, "%s(%s): Cannot encode real part of a complex "
- "integer value [%d,%d] into a FITS header card "
- "for keyword '%s'.", status, method, astGetClass( this ),
- ( (int *) data )[ 0 ],
- ( (int *) data )[ 1 ], name );
- } else {
- ilen = sprintf( buf + rlen, "%*d", FITSIMCOL - FITSRLCOL + 1,
- ( (int *) data )[ 1 ] );
- if( ilen < 0 || ilen > AST__FITSCHAN_FITSCARDLEN - col - rlen ) {
- astError( AST__BDFTS, "%s(%s): Cannot encode imaginary part of a "
- "complex integer value [%d,%d] into a FITS header card "
- "for keyword '%s'.", status, method, astGetClass( this ),
- ( (int *) data )[ 0 ],
- ( (int *) data )[ 1 ], name );
- } else {
- len = ilen + rlen;
- }
- }
-
-/* Report an internal (ast) programming error if the keyword is of none of the
- above types. */
- } else if( astOK ){
- astError( AST__INTER, "EncodeValue: AST internal programming error - "
- "FITS %s data-type not yet supported.", status,
- type_names[ type ] );
- }
- }
-
-/* If an error has occurred, return zero length. */
- if( !astOK ) len = 0;
-
-/* Return the answer. */
- return len;
-}
-
-static AstGrismMap *ExtractGrismMap( AstMapping *map, int iax,
- AstMapping **new_map, int *status ){
-/*
-* Name:
-* ExtractGrismMap
-
-* Purpose:
-* Extract a GrismMap from the end of the supplied Mapping.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstGrismMap *ExtractGrismMap( AstMapping *map, int iax,
-* AstMapping **new_map, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function examines the supplied Mapping; if the specified output
-* coordinate of the Mapping is created directly by an un-inverted GrismMap,
-* then a pointer to the GrismMap is returned as the function value. A new
-* Mapping is also returned via parameter "new_map" which is a copy of
-* the supplied Mapping, except that the GrismMap is replaced with a
-* UnitMap. If no GrismMap is found, NULL is returned for both Mappings.
-* The condition that "the specified output coordinate of the Mapping is
-* created directly by an un-inverted GrismMap" means that the output
-* of the GrismMap is no subsequently modified by any further Mappings
-* before being returned as the "iax"th output of the supplied Mapping.
-* This means the GrismMap must be "at the end of" a CmpMap, not in
-* the middle of the CmpMap.
-
-* Parameters:
-* map
-* Pointer to the Mapping to check.
-* iax
-* The index for the output coordinate to be checked.
-* new_map
-* Pointer to a location at which to return a pointer to a new
-* Mapping which is a copy of "map" except that the GrismMap is
-* replaced by a UnitMap. NULL is returned if the specified output
-* was not created by a GrismMap.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The extracted GrismMap, or NULL if the specified output was not
-* created by a GrismMap.
-*/
-
-/* Local Variables: */
- AstMapping *mapa; /* First component Mapping */
- AstMapping *mapb; /* Second component Mapping */
- AstMapping *new_mapa; /* Replacement for first component Mapping */
- AstMapping *new_mapb; /* Replacement for second component Mapping */
- AstGrismMap *ret; /* Returned GrismMap */
- int inva; /* Invert attribute for mapa within the CmpMap */
- int invb; /* Invert attribute for mapb within the CmpMap */
- int na; /* Number of outputs for mapa */
- int old_inva; /* Current Invert attribute for mapa */
- int old_invb; /* Current Invert attribute for mapb */
- int series; /* Are component Mappings applied in series? */
-
-/* Initialise */
- ret = NULL;
- *new_map = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* If the supplied Mapping is a GrismMap which has not been inverted,
- return it as the function value and return a UnitMap as the new
- Mapping. */
- if( astIsAGrismMap( map ) ) {
- if( !astGetInvert( map ) ) {
- ret = astClone( map );
- *new_map = (AstMapping *) astUnitMap( 1, "", status );
- }
-
-/* If the supplied Mapping is a CmpMap, get its two component Mappings,
- see if they are applied in parallel or series, and get the Invert
- attribute values which the component Mappings had at the time the
- CmpMap was created. */
- } else if( astIsACmpMap( map ) ) {
- astDecompose( map, &mapa, &mapb, &series, &inva, &invb );
-
-/* Temporaily reset the Invert attributes of the component Mappings back to
- the values they had when the CmpMap was created. */
- old_inva = astGetInvert( mapa );
- old_invb = astGetInvert( mapb );
- astSetInvert( mapa, inva );
- astSetInvert( mapb, invb );
-
-/* If the supplied Mapping is a series CmpMap, attempt to extract a
- GrismMap from the second component Mapping ("mapb"). The first
- component Mapping ("mapa") is unchanged. We do not need to consdier
- the first component since we are only interested in GrismMaps which are
- at the end of the CmpMap. */
- if( series ) {
- ret = ExtractGrismMap( mapb, iax, &new_mapb, status );
- if( ret ) new_mapa = astClone( mapa );
-
-/* If the supplied Mapping is a parallel CmpMap, attempt to extract a
- GrismMap from the component Mapping which produces output "iax". The
- other component Mapping is unchanged. */
- } else {
- na = astGetNout( mapa );
- if( iax < na ) {
- ret = ExtractGrismMap( mapa, iax, &new_mapa, status );
- if( ret ) new_mapb = astClone( mapb );
- } else {
- ret = ExtractGrismMap( mapb, iax - na, &new_mapb, status );
- if( ret ) new_mapa = astClone( mapa );
- }
- }
-
-/* If succesful, create a new CmpMap to return. */
- if( ret ) {
- *new_map = (AstMapping *) astCmpMap( new_mapa, new_mapb, series, "", status );
- new_mapa = astAnnul( new_mapa );
- new_mapb = astAnnul( new_mapb );
- }
-
-/* Re-instate the original Invert attributes of the component Mappings. */
- astSetInvert( mapa, old_inva );
- astSetInvert( mapb, old_invb );
-
-/* Annul the component Mapping pointers. */
- mapa = astAnnul( mapa );
- mapb = astAnnul( mapb );
- }
-
-/* Return the result. */
- return ret;
-}
-
-static int MakeBasisVectors( AstMapping *map, int nin, int nout,
- double *g0, AstPointSet *psetg,
- AstPointSet *psetw, int *status ){
-/*
-* Name:
-* MakeBasisVectors
-
-* Purpose:
-* Create a set of basis vectors in grid coordinates
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int MakeBasisVectors( AstMapping *map, int nin, int nout,
-* double *g0, AstPointSet *psetg,
-* AstPointSet *psetw, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns a set of unit vectors in grid coordinates,
-* one for each grid axis. Each unit vector is parallel to the
-* corresponding grid axis, and rooted at a specified grid position
-* ("g0"). The IWC coordinates corresponding to "g0" and to the end of
-* each of the unit vectors are also returned, together with a flag
-* indicating if all the IWC coordinate values are good.
-
-* Parameters:
-* map
-* A pointer to a Mapping which transforms grid coordinates into
-* intermediate world coordinates (IWC). The number of outputs must
-* be greater than or equal to the number of inputs.
-* nin
-* The number of inputs for "map" (i.e. the number of grid axes).
-* nout
-* The number of outputs for "map" (i.e. the number of IWC axes).
-* g0
-* Pointer to an array of holding the grid coordinates at the
-* "root" position.
-* psetg
-* A pointer to a PointSet which can be used to hold the required
-* grid positions. This should have room for nin+1 positions. On
-* return, the first position holds "g0", and the subsequent "nin"
-* positions hold are offset from "g0" by unit vectors along the
-* corresponding grid axis.
-* psetw
-* A pointer to a PointSet which can be used to hold the required
-* IWC position. This should also have room for nin+1 positions. On
-* return, the values are the IWC coordinates corresponding to the
-* grid positions returned in "psetg".
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A value of 1 is returned if all the axis values in "psetw" are good.
-* Zero is returned otherwise.
-
-* Notes:
-* - Zero is returned if an error occurs.
-*/
-
-/* Local Variables: */
- double **ptrg;
- double **ptrw;
- double *c;
- int i;
- int ii;
- int j;
- int ret;
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Get pointers to the data in the two supplied PointSets. */
- ptrg = astGetPoints( psetg );
- ptrw = astGetPoints( psetw );
-
-/* Check the pointers can be used safely. */
- if( astOK ) {
-
-/* Assume success. */
- ret = 1;
-
-/* Store the required grid positions in PointSet "pset1". The first
- position is the supplied root grid position, g0. The next "nin"
- positions are offset from the root position by a unit vector along
- each grid axis in turn. Store values for each grid axis in turn. */
- for( i = 0; i < nin; i++ ) {
-
-/* Get a pointer to the first axis value for this grid axis. */
- c = ptrg[ i ];
-
-/* Initially set all values for this axis to the supplied root grid value. */
- for( ii = 0; ii < nin + 1; ii++ ) c[ ii ] = g0[ i ];
-
-/* Modify the value corresponding to the vector along this grid axis. */
- c[ i + 1 ] += 1.0;
- }
-
-/* Transform these grid positions in IWC positions using the supplied
- Mapping. */
- (void) astTransform( map, psetg, 1, psetw );
-
-/* Check that all the transformed positions are good. */
- for( j = 0; j < nout; j++ ) {
- c = ptrw[ j ];
- for( ii = 0; ii < nin + 1; ii++, c++ ) {
- if( *c == AST__BAD ) {
- ret = 0;
- break;
- }
- }
- }
- }
-
-/* Return the result. */
- return ret;
-}
-
-static int FindBasisVectors( AstMapping *map, int nin, int nout,
- double *dim, AstPointSet *psetg,
- AstPointSet *psetw, int *status ){
-/*
-* Name:
-* FindBasisVectors
-
-* Purpose:
-* Find the a set of basis vectors in grid coordinates
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int FindBasisVectors( AstMapping *map, int nin, int nout,
-* double *dim, AstPointSet *psetg,
-* AstPointSet *psetw, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns a set of unit vectors in grid coordinates,
-* one for each grid axis. Each unit vector is parallel to the
-* corresponding grid axis, and rooted at a specified grid position
-* ("g0"). The IWC coordinates corresponding to "g0" and to the end of
-* each of the unit vectors are also returned, together with a flag
-* indicating if all the IWC coordinate values are good.
-
-* Parameters:
-* map
-* A pointer to a Mapping which transforms grid coordinates into
-* intermediate world coordinates (IWC). The number of outputs must
-* be greater than or equal to the number of inputs.
-* nin
-* The number of inputs for "map" (i.e. the number of grid axes).
-* nout
-* The number of outputs for "map" (i.e. the number of IWC axes).
-* dim
-* Array dimensions, in pixels, if known (otherwise supplied a NULL
-* pointer to values of AST__BAD).
-* psetg
-* A pointer to a PointSet which can be used to hold the required
-* grid position. This should have room for nin+1 positions. On
-* return, the first position holds the "root" position and the
-* subsequent "nin" positions hold are offset from root position
-* by unit vectors along the corresponding grid axis.
-* psetw
-* A pointer to a PointSet which can be used to hold the required
-* IWC position. This should also have room for nin+1 positions. On
-* return, the values are the IWC coordinates corresponding to the
-* grid positions returned in "psetg".
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A value of 1 is returned if a set of basis vectors was found
-* succesfully. Zero is returned otherwise.
-
-* Notes:
-* - Zero is returned if an error occurs.
-*/
-
-/* Local Variables: */
- double *g0;
- double dd;
- double ddlim;
- int i;
- int ii;
- int ret;
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Allocate an array to store the candidate root position. */
- g0 = astMalloc( sizeof( double )*(size_t) nin );
- if( astOK ) {
-
-/* First try the grid centre, if known. */
- ddlim = 0;
- ret = 0;
- if( dim ) {
- ret = 1;
- for( i = 0; i < nin; i++ ) {
- if( dim[ i ] != AST__BAD ) {
- g0[ i ] = 0.5*( 1 + dim[ i ] );
- if( dim[ i ] > ddlim ) ddlim = dim[ i ];
- } else {
- ret = 0;
- break;
- }
- }
- }
- if( ret ) ret = MakeBasisVectors( map, nin, nout, g0, psetg, psetw, status );
-
-/* If this did not produce a set of good IWC positions, try grid position
- (1,1,1...). */
- if( !ret ) {
- for( i = 0; i < nin; i++ ) g0[ i ] = 1.0;
- ret = MakeBasisVectors( map, nin, nout, g0, psetg, psetw, status );
- }
-
-/* If this did not produce a set of good IWC positions, try a sequence of
- grid positions which move an increasing distance along each grid axis
- from (1,1,1,...). Stop when we get further than "ddlim" from the
- origin. */
- dd = 10.0;
- if( ddlim == 0.0 ) ddlim = 10240.0;
- while( !ret && dd <= ddlim ) {
-
-/* First try positions which extend across the middle of the data set.
- If the image dimensions are known, make the line go from the "bottom
- left corner" towards the "top right corner", taking the aspect ratio
- of the image into account. Otherise, just use a vector of (1,1,1,..) */
- for( i = 0; i < nin; i++ ) {
- if( dim && dim[ i ] != AST__BAD ) {
- g0[ i ] = dd*dim[ i ]/ddlim;
- } else {
- g0[ i ] = dd;
- }
- }
- ret = MakeBasisVectors( map, nin, nout, g0, psetg, psetw, status );
-
-/* If the above didn't produce good positions, try moving out along each
- grid axis in turn. */
- for( ii = 0; !ret && ii < nin; ii++ ) {
- for( i = 0; i < nin; i++ ) g0[ i ] = 1.0;
- g0[ ii ] = dd;
- ret = MakeBasisVectors( map, nin, nout, g0, psetg, psetw, status );
- }
-
-/* Go further out from the origin for the next set of tests (if any). */
- dd *= 2.0;
- }
- }
-
-/* Free resources. */
- g0 = astFree( g0 );
-
-/* Return the result. */
- return ret;
-}
-
-static int FindLonLatSpecAxes( FitsStore *store, char s, int *axlon, int *axlat,
- int *axspec, const char *method, const char *class, int *status ) {
-/*
-* Name:
-* FindLonLatSpecAxes
-
-* Purpose:
-* Search the CTYPE values in a FitsStore for celestial and spectral axes.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int FindLonLatSpecAxes( FitsStore *store, char s, int *axlon, int *axlat,
-* int *axspec, const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* The supplied FitsStore is searched for axes with a specified axis
-* description character which describe celestial longitude or latitude
-* or spectral position.
-
-* Parameters:
-* store
-* A structure containing values for FITS keywords relating to
-* the World Coordinate System.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* axlon
-* Address of a location at which to return the index of the
-* longitude axis (if found). This is the value of "i" within the
-* keyword name "CTYPEi". A value of -1 is returned if no longitude
-* axis is found.
-* axlat
-* Address of a location at which to return the index of the
-* latitude axis (if found). This is the value of "i" within the
-* keyword name "CTYPEi". A value of -1 is returned if no latitude
-* axis is found.
-* axspec
-* Address of a location at which to return the index of the
-* spectral axis (if found). This is the value of "i" within the
-* keyword name "CTYPEi". A value of -1 is returned if no spectral
-* axis is found.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* One is returned if both celestial axes were found. Zero is returned if
-* either axis was not found. The presence of a spectral axis does not
-* affect the returned value.
-
-* Notes:
-* - If an error occurs, zero is returned.
-*/
-
-/* Local Variables: */
- char *assys;
- char *astype;
- char algcode[5];
- char stype[5];
- const char *ctype;
- double dval;
- int i;
- int wcsaxes;
-
-/* Initialise */
- *axlon = -1;
- *axlat = -1;
- *axspec = -1;
-
-/* Check the global status. */
- if ( !astOK ) return 0;
-
-/* Obtain the number of FITS WCS axes in the header. If the WCSAXES header
- was specified, use it. Otherwise assume it is the same as the number
- of pixel axes. */
- dval = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status );
- if( dval != AST__BAD ) {
- wcsaxes = (int) dval + 0.5;
- } else {
- wcsaxes = store->naxis;
- }
-
-/* Loop round the FITS WCS axes, getting each CTYPE value. */
- for( i = 0; i < wcsaxes && astOK; i++ ){
- ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
-
-/* Check a value was found. */
- if( ctype ) {
-
-/* First check for spectral axes, either FITS-WCS or AIPS-like. */
- if( IsSpectral( ctype, stype, algcode, status ) ||
- IsAIPSSpectral( ctype, &astype, &assys, status ) ) {
- *axspec = i;
-
-/* Otherwise look for celestial axes. Celestial axes must have a "-" as the
- fifth character in CTYPE. */
- } else if( ctype[4] == '-' ) {
-
-/* See if this is a longitude axis (e.g. if the first 4 characters of CTYPE
- are "RA--" or "xLON" or "yzLN" ). */
- if( !strncmp( ctype, "RA--", 4 ) ||
- !strncmp( ctype, "AZ--", 4 ) ||
- !strncmp( ctype + 1, "LON", 3 ) ||
- !strncmp( ctype + 2, "LN", 2 ) ){
- *axlon = i;
-
-/* Otherwise see if it is a latitude axis. */
- } else if( !strncmp( ctype, "DEC-", 4 ) ||
- !strncmp( ctype, "EL--", 4 ) ||
- !strncmp( ctype + 1, "LAT", 3 ) ||
- !strncmp( ctype + 2, "LT", 2 ) ){
- *axlat = i;
- }
- }
- }
- }
-
-/* Indicate failure if an error occurred. */
- if( !astOK ) {
- *axlon = -1;
- *axlat = -1;
- *axspec = -1;
- }
-
-/* Return the result. */
- return ( *axlat != -1 && *axlon != -1 );
-}
-
-static void FindWcs( AstFitsChan *this, int last, int all, int rewind,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* FindWcs
-
-* Purpose:
-* Find the first or last FITS WCS related keyword in a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void FindWcs( AstFitsChan *this, int last, int all, int rewind,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A search is made through the FitsChan for the first or last card
-* which relates to a FITS WCS keyword (any encoding). If "last" is
-* non-zero, the next card becomes the current card. If "last" is
-* zero, the WCS card is left as the current card. Cards marked as
-* having been read are included or not, as specified by "all".
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* last
-* If non-zero, the last WCS card is searched for. Otherwise, the
-* first WCS card is searched for.
-* all
-* If non-zero, then cards marked as having been read are included
-* in the search. Otherwise such cards are ignored.
-* rewind
-* Only used if "last" is zero (i.e. the first card is being
-* searched for). If "rewind" is non-zero, then the search starts
-* from the first card in the FitsChan. If zero, the search starts
-* from the current card.
-* 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.
-
-* Notes:
-* - The FitsChan is left at end-of-file if no FITS-WCS keyword cards
-* are found in the FitsChan.
-*-
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- const char *keyname; /* Keyword name from current card */
- int nfld; /* Number of fields in keyword template */
- int old_ignore_used; /* Original value of variable ignore_used */
-
-/* Check the global status. Also check the FitsChan is not empty. */
- if( !astOK || !this->head ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Indicate that we should, or should not, skip over cards marked as having
- been read. */
- old_ignore_used = ignore_used;
- ignore_used = all ? 0 : 1;
-
-/* If required, set the FitsChan to start or end of file. */
- if( last ) {
- astSetCard( this, INT_MAX );
- } else if( rewind ) {
- astClearCard( this );
- }
-
-/* If the current card is marked as used, and we are skipping used cards,
- move on to the next unused card */
- if( CARDUSED( this->card ) ) MoveCard( this, last?-1:1, method, class, status );
-
-/* Check each card moving backwards from the end to the start, or
- forwards from the start to the end, until a WCS keyword is found,
- or the other end of the FitsChan is reached. */
- while( astOK ){
-
-/* Get the keyword name from the current card. */
- keyname = CardName( this, status );
-
-/* Save a pointer to the keyword if it is the first non-null, non-comment
- card. */
- if( keyname ) {
-
-/* If it matches any of the WCS keywords, move on one card
- and break out of the loop. */
- if( Match( keyname, "CRVAL%d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CRPIX%d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CDELT%d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CROTA%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CTYPE%d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CUNIT%d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PC%3d%3d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CD%3d%3d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CD%1d_%1d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PC%1d_%1d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "LONGPOLE", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "LONPOLE%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "LATPOLE%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PROJP%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PV%d_%d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PS%d_%d%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "EPOCH", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "EQUINOX%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "MJD-OBS", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "DATE-OBS", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "TIMESYS", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "RADECSYS", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "RADESYS%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "C%1dVAL%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "C%1dPIX%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "C%1dELT%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "C%1dYPE%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "C%1dNIT%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CNPIX1", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "CNPIX2", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PPO%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "AMDX%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "AMDY%d", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "XPIXELSZ", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "YPIXELSZ", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PLTRAH", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PLTRAM", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PLTRAS", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PLTDECD", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PLTDECM", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PLTDECS", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PLTDECSN", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PLTSCALE", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PPO1", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PPO2", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PPO4", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "PPO5", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "WCSNAME%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "SPECSYS%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "SSYSSRC%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "ZSOURCE%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "VELOSYS%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "RESTFRQ%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "MJD_AVG%0c", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "OBSGEO-X", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "OBSGEO-Y", 0, NULL, &nfld, method, class, status ) ||
- Match( keyname, "OBSGEO-Z", 0, NULL, &nfld, method, class, status ) ) {
- if( last ) MoveCard( this, 1, method, class, status );
- break;
- }
- }
-
-/* Leave the FitsChan at end-of-file if no WCS cards were found. */
- if( (last && FitsSof( this, status ) ) ||
- (!last && astFitsEof( this ) ) ) {
- astSetCard( this, INT_MAX );
- break;
- } else {
- MoveCard( this, last?-1:1, method, class, status );
- }
- }
-
-/* Re-instate the original flag indicating if cards marked as having been
- read should be skipped over. */
- ignore_used = old_ignore_used;
-
-/* Return. */
- return;
-}
-
-static int FindString( int n, const char *list[], const char *test,
- const char *text, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* FindString
-
-* Purpose:
-* Find a given string within an array of character strings.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int FindString( int n, const char *list[], const char *test,
-* const char *text, const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function identifies a supplied string within a supplied
-* array of valid strings, and returns the index of the string within
-* the array. The test option may not be abbreviated, but case is
-* insignificant.
-
-* Parameters:
-* n
-* The number of strings in the array pointed to be "list".
-* list
-* A pointer to an array of legal character strings.
-* test
-* A candidate string.
-* text
-* A string giving a description of the object, parameter,
-* attribute, etc, to which the test value refers.
-* This is only for use in constructing error messages. It should
-* start with a lower case letter.
-* 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:
-* The index of the identified string within the supplied array, starting
-* at zero.
-
-* Notes:
-* - A value of -1 is returned if an error has already occurred, or
-* if this function should fail for any reason (for instance if the
-* supplied option is not specified in the supplied list).
-*/
-
-/* Local Variables: */
- int ret; /* The returned index */
-
-/* Check global status. */
- if( !astOK ) return -1;
-
-/* Compare the test string with each element of the supplied list. Leave
- the loop when a match is found. */
- for( ret = 0; ret < n; ret++ ) {
- if( !Ustrcmp( test, list[ ret ], status ) ) break;
- }
-
-/* Report an error if the supplied test string does not match any element
- in the supplied list. */
- if( ret >= n && astOK ) {
- astError( AST__RDERR, "%s(%s): Illegal value '%s' supplied for %s.", status,
- method, class, test, text );
- ret = -1;
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static int FitOK( int n, double *act, double *est, double tol, int *status ) {
-/*
-* Name:
-* FitOK
-
-* Purpose:
-* See if a fit is usable.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int FitOK( int n, double *act, double *est, double tol, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function is supplied with a set of actual data values, and the
-* corresponding values estimated by some fitting process. It tests
-* that the RMS residual between them is no more than "tol".
-
-* Parameters:
-* n
-* Number of data points.
-* act
-* Pointer to the start of the actual data values.
-* est
-* Pointer to the start of the estimated data values.
-* tol
-* The largest acceptable RMS error between "act" and "est".
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A value of 1 is returned if the two sets of values agree. Zero is
-* returned otherwise.
-
-* Notes:
-* - Zero is returned if an error occurs.
-*/
-
-/* Local Variables: */
- int ret, i;
- double s1, s2;
- double *px, *py, diff, mserr;
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Initialise the sum of the squared residuals, and the number summed. */
- s1 = 0.0;
- s2 = 0.0;
-
-/* Initialise pointers to the next actual and estimated values to use. */
- px = act;
- py = est;
-
-/* Loop round all pairs of good actual and estimate value. */
- for( i = 0; i < n; i++, px++, py++ ){
- if( *px != AST__BAD && *py != AST__BAD ) {
-
-/* Increment the sums need to find the RMS residual between the actual
- and estimated values. */
- diff = *px - *py;
- s1 += diff*diff;
- s2 += 1.0;
- }
- }
-
-/* If the sums are usable... */
- if( s2 > 0.0 ) {
-
-/* Form the mean squared residual, and check if it is less than the
- squared error limit. */
- mserr = s1/s2;
- if( mserr < tol*tol ) ret = 1;
- }
-
-/* Return the result. */
- return ret;
-}
-
-static int FitsAxisOrder( AstFitsChan *this, int nwcs, AstFrame *wcsfrm,
- int *perm, int *status ){
-/*
-* Name:
-* FitsAxisOrder
-
-* Purpose:
-* Return the order of WCS axes specified by attribute FitsAxisOrder.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int FitsAxisOrder( AstFitsChan *this, int nwcs, AstFrame *wcsfrm,
-* int *perm, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns an array indicating the order of the WCS axes
-* within the output FITS header, as specified by the FitsAxisOrder
-* attribute.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* nwcs
-* The number of axes in "wcsfrm".
-* wcsfrm
-* The Frame containing the output WCS axes.
-* perm
-* Pointer to an array of "nwcs" integers. On exit, element "k"
-* of this array holds the zero-based index of the FITS-WCS axis
-* (i.e. one less than the value of "i" in the keyword names
-* "CTYPEi", "CRVALi", etc) that describes the k'th axis in "wcsfrm".
-* In other words, "perm[ast_index] = fits_index". The order is
-* determined by the FitsAxisOrder attribute. If this attribute is
-* "<copy>" or "<auto>", then "perm[k]=k" for all k on exit (i.e.
-* a unit mapping between axes in "wcsfrm" and the FITS header).
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Returns zero if the FitsAxisOrder attribute is "<auto">, and
-* non-zero otherwise. This is a flag indicating if the returned
-* values in "perm" can be used s they are.
-
-*/
-
-/* Local Variables: */
- AstKeyMap *km; /* KeyMap holding axis indices keyed by axis symbols */
- char **words; /* Pointer to array of words from FitsAxisOrder */
- char attr_name[15];/* Attribute name */
- const char *attr; /* Pointer to a string holding the FitsAxisOrder value */
- int i; /* Loop count */
- int j; /* Zero-based axis index */
- int k; /* Zero-based axis index */
- int nword; /* Number of words in FitsAxisOrder */
- int result; /* Retrned value */
-
-/* Check the inherited status. */
- if( !astOK ) return 0;
-
-/* Initialise the returned array to a unit mapping from Frame axis to
- FITS axis. */
- for( i = 0; i < nwcs; i++ ) perm[ i ] = i;
-
-/* Get the FitsAxisOrder attribute value, and set the returned value to
- indicate if it is "<auto>". */
- attr = astGetFitsAxisOrder( this );
- result = !astChrMatch( attr, "<auto>" );
-
-/* Return immediately if it is "<auto>" or "<copy>". */
- if( result && !astChrMatch( attr, "<copy>" ) ) {
-
-/* Create a KeyMap in which each key is the Symbol for an axis and the
- associated value is the zero based index of the axis within "wcsfrm". */
- km = astKeyMap( "KeyCase=0", status );
- for( i = 0; i < nwcs; i++ ){
- sprintf( attr_name, "Symbol(%d)", i + 1 );
- astMapPut0I( km, astGetC( wcsfrm, attr_name ), i, NULL );
- }
-
-/* Split the FitsAxisOrder value into a collection of space-separated words. */
- words = astChrSplit( attr, &nword );
-
-/* Loop round them all. */
- k = 0;
- for( i = 0; i < nword; i++ ) {
-
-/* Get the zero based index within "wcsfrm" of the axis that has a Symbol
- equal to the current word from FitsAxisOrder. */
- if( astMapGet0I( km, words[ i ], &j ) ) {
-
-/* If this "wcsfrm" axis has already been used, report an error. */
- if( j < 0 ) {
- if( astOK ) astError( AST__ATTIN, "astWrite(fitschan): "
- "attribute FitsAxisOrder (%s) refers to axis "
- "%s more than once.", status, attr, words[ i ] );
-
-/* Otherwise, set the corresponding element of the returned array, and
- ensure this axis cannot be used again by assigning it an index of -1
- in the KeyMap. */
- } else {
- perm[ j ] = k++;
- astMapPut0I( km, words[ i ], -1, NULL );
- }
- }
-
-/* Free the memory holding the copy of the word. */
- words[ i ] = astFree( words[ i ] );
- }
-
-/* Report an error if any wcsfrm axes were not included in FitsAxisOrder. */
- if( astOK ) {
- for( i = 0; i < nwcs; i++ ){
- sprintf( attr_name, "Symbol(%d)", i + 1 );
- if( astMapGet0I( km, astGetC( wcsfrm, attr_name ), &j ) ) {
- if( j >= 0 ) {
- astError( AST__ATTIN, "astWrite(fitschan): attribute FitsAxisOrder "
- "(%s) does not specify a position for WCS axis '%s'.",
- status, attr, astGetC( wcsfrm, attr_name ) );
- break;
- }
- }
- }
- }
-
-/* Free resources. */
- words = astFree( words );
- km = astAnnul( km );
- }
-
- return result;
-}
-
-static int FitsFromStore( AstFitsChan *this, FitsStore *store, int encoding,
- double *dim, AstFrameSet *fs, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* FitsFromStore
-
-* Purpose:
-* Store WCS keywords in a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* int FitsFromStore( AstFitsChan *this, FitsStore *store, int encoding,
-* double *dim, AstFrameSet *fs, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function copies the WCS information stored in the supplied
-* FitsStore into the supplied FitsChan, using a specified encoding.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore.
-* encoding
-* The encoding to use.
-* dim
-* Pointer to an array holding the array dimensions (AST__BAD
-* indicates that the dimenson is not known).
-* 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 value of 1 is returned if succesfull, and zero is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- int ret;
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Set the current card so that it points to the last WCS-related keyword
- in the FitsChan (whether previously read or not). Any new WCS related
- keywords either over-write pre-existing cards for the same keyword, or
- (if no pre-existing card exists) are inserted after the last WCS related
- keyword. */
- FindWcs( this, 1, 1, 0, method, class, status );
-
-/* Do each non-standard FITS encoding... */
- if( encoding == DSS_ENCODING ){
- ret = DSSFromStore( this, store, method, class, status );
- } else if( encoding == FITSPC_ENCODING ){
- ret = PCFromStore( this, store, method, class, status );
- } else if( encoding == FITSIRAF_ENCODING ){
- ret = IRAFFromStore( this, store, method, class, status );
- } else if( encoding == FITSAIPS_ENCODING ){
- ret = AIPSFromStore( this, store, method, class, status );
- } else if( encoding == FITSAIPSPP_ENCODING ){
- ret = AIPSPPFromStore( this, store, method, class, status );
- } else if( encoding == FITSCLASS_ENCODING ){
- ret = CLASSFromStore( this, store, fs, dim, method, class, status );
-
-/* Standard FITS-WCS encoding */
- } else {
- ret = WcsFromStore( this, store, method, class, status );
- }
-
-/* If there are any Tables in the FitsStore move the KeyMap that contains
- them from the FitsStore to the FitsChan, from where they can be
- retrieved using the public astGetTables method. */
- if( astMapSize( store->tables ) > 0 ) {
- if( !this->tables ) this->tables = astKeyMap( " ", status );
- astMapCopy( this->tables, store->tables );
- (void) astAnnul( store->tables );
- store->tables = astKeyMap( " ", status );
- }
-
-/* If an error has occurred, return zero. */
- if( !astOK ) ret = 0;
-
-/* Return the answer. */
- return ret;
-}
-
-static FitsStore *FitsToStore( AstFitsChan *this, int encoding,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* FitsToStore
-
-* Purpose:
-* Return a pointer to a FitsStore structure containing WCS information
-* read from the supplied FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* FitsStore *FitsToStore( AstFitsChan *this, int encoding,
-* const char *method, const char *class )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function creates a new FitsStore containing WCS information
-* read from the supplied FitsChan using the specified encoding. An
-* error is reported and a null pointer returned if the FitsChan does
-* not contain usable WCS information with the specified encoding.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* encoding
-* The encoding to use.
-* 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.
-
-* Returned Value:
-* A pointer to a new FitsStore, or NULL if an error has occurred. The
-* FitsStore should be released using FreeStore function when it is no
-* longer needed.
-*/
-
-/* Local Variables: */
- AstFitsChan *trans;
- FitsStore *ret;
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Allocate memory for the new FitsStore, and store NULL pointers in it. */
- ret = (FitsStore *) astMalloc( sizeof(FitsStore) );
- if( ret ) {
- ret->cname = NULL;
- ret->ctype = NULL;
- ret->ctype_com = NULL;
- ret->cunit = NULL;
- ret->ps = NULL;
- ret->radesys = NULL;
- ret->wcsname = NULL;
- ret->wcsaxes = NULL;
- ret->pc = NULL;
- ret->cdelt = NULL;
- ret->crpix = NULL;
- ret->crval = NULL;
- ret->equinox = NULL;
- ret->latpole = NULL;
- ret->lonpole = NULL;
- ret->mjdobs = NULL;
- ret->mjdavg = NULL;
- ret->dut1 = NULL;
- ret->pv = NULL;
- ret->specsys = NULL;
- ret->ssyssrc = NULL;
- ret->obsgeox = NULL;
- ret->obsgeoy = NULL;
- ret->obsgeoz = NULL;
- ret->restfrq = NULL;
- ret->restwav = NULL;
- ret->zsource = NULL;
- ret->velosys = NULL;
- ret->asip = NULL;
- ret->bsip = NULL;
- ret->apsip = NULL;
- ret->bpsip = NULL;
- ret->imagfreq = NULL;
- ret->axref = NULL;
- ret->naxis = 0;
- ret->timesys = NULL;
- ret->tables = astKeyMap( " ", status );
- ret->skyref = NULL;
- ret->skyrefp = NULL;
- ret->skyrefis = NULL;
- }
-
-/* Call the routine apropriate to the encoding. */
- if( encoding == DSS_ENCODING ){
- DSSToStore( this, ret, method, class, status );
-
-/* All other foreign encodings are treated as variants of FITS-WCS. */
- } else {
-
-/* Create a new FitsChan containing standard translations for any
- non-standard keywords in the supplied FitsChan. The non-standard
- keywords are marked as provisionally read in the supplied FitsChan. */
- trans = SpecTrans( this, encoding, method, class, status );
-
-/* Copy the required values to the FitsStore, using keywords in "trans"
- in preference to those in "this". */
- WcsToStore( this, trans, ret, method, class, status );
-
-/* Delete the temporary FitsChan holding translations of non-standard
- keywords. */
- if( trans ) trans = (AstFitsChan *) astDelete( trans );
-
-/* Store the number of pixel axes. This is taken as the highest index used
- in any primary CRPIX keyword. */
- ret->naxis = GetMaxJM( &(ret->crpix), ' ', status ) + 1;
- }
-
-/* If an error has occurred, free the returned FitsStore, and return a null
- pointer. */
- if( !astOK ) ret = FreeStore( ret, status );
-
-/* Return the answer. */
- return ret;
-}
-
-static void FreeItem( double ****item, int *status ){
-/*
-* Name:
-* FreeItem
-
-* Purpose:
-* Frees all dynamically allocated memory associated with a specified
-* item in a FitsStore.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void FreeItem( double ****item, int *status );
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Frees all dynamically allocated memory associated with the specified
-* item in a FitsStore. A NULL pointer is stored in the FitsStore.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->crval) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (j), and the pointer locates an
-* array of axis keyword values. These arrays of keyword values have
-* one element for every pixel axis (i) or projection parameter (m).
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - This function attempt to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- int si; /* Integer co-ordinate version index */
- int j; /* Intermediate co-ordinate axis index */
- int oldstatus; /* Old error status value */
- int oldreport; /* Old error reporting value */
-
-/* Other initialisation to avoid compiler warnings. */
- oldreport = 0;
-
-/* Check the supplied pointer */
- if( item && *item ){
-
-/* Start a new error reporting context. */
- oldstatus = astStatus;
- if( !astOK ) {
- oldreport = astReporting( 0 );
- astClearStatus;
- }
-
-/* Loop round each coordinate version. */
- for( si = 0; si < astSizeOf( (void *) *item )/sizeof(double **);
- si++ ){
-
-/* Check the pointer stored for this co-ordinate version is not null. */
- if( (*item)[si] ) {
-
-/* Loop round the intermediate axes. */
- for( j = 0; j < astSizeOf( (void *) (*item)[si] )/sizeof(double *);
- j++ ){
-
-/* Free the pixel axis/parameter index pointer. */
- (*item)[si][j] = (double *) astFree( (void *) (*item)[si][j] );
- }
-
-/* Free the intermediate axes pointer */
- (*item)[si] = (double **) astFree( (void *) (*item)[si] );
- }
- }
-
-/* Free the co-ordinate versions pointer */
- *item = (double ***) astFree( (void *) *item );
-
-/* If there was an error status on entry to this function, re-instate it.
- Otherwise, allow any new error status to remain. */
- if( oldstatus ){
- if( !astOK ) astClearStatus;
- astSetStatus( oldstatus );
- astReporting( oldreport );
- }
- }
-}
-
-static void FreeItemC( char *****item, int *status ){
-/*
-* Name:
-* FreeItemC
-
-* Purpose:
-* Frees all dynamically allocated memory associated with a specified
-* string item in a FitsStore.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void FreeItemC( char *****item, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Frees all dynamically allocated memory associated with the specified
-* string item in a FitsStore. A NULL pointer is stored in the FitsStore.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->ctype) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (j), and the pointer locates an
-* array of axis keyword values. These arrays of keyword values have
-* one element (a char pointyer) for every pixel axis (i) or
-* projection parameter (m).
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- int si; /* Integer co-ordinate version index */
- int i; /* Intermediate co-ordinate axis index */
- int jm; /* Pixel co-ordinate axis or parameter index */
- int oldstatus; /* Old error status value */
- int oldreport; /* Old error reporting value */
-
-/* Other initialisation to avoid compiler warnings. */
- oldreport = 0;
-
-/* Check the supplied pointer */
- if( item && *item ){
-
-/* Start a new error reporting context. */
- oldstatus = astStatus;
- if( !astOK ) {
- oldreport = astReporting( 0 );
- astClearStatus;
- }
-
-/* Loop round each coordinate version. */
- for( si = 0; si < astSizeOf( (void *) *item )/sizeof(char ***);
- si++ ){
-
-/* Check the pointer stored for this co-ordinate version is not null. */
- if( (*item)[si] ) {
-
-/* Loop round the intermediate axes. */
- for( i = 0; i < astSizeOf( (void *) (*item)[si] )/sizeof(char **);
- i++ ){
-
-/* Check the pointer stored for this intermediate axis is not null. */
- if( (*item)[si][i] ) {
-
-/* Loop round the pixel axes or parameter values. */
- for( jm = 0; jm < astSizeOf( (void *) (*item)[si][i] )/sizeof(char *);
- jm++ ){
-
-/* Free the string. */
- (*item)[si][i][jm] = (char *) astFree( (void *) (*item)[si][i][jm] );
- }
-
-/* Free the pixel axes/parameter pointer */
- (*item)[si][i] = (char **) astFree( (void *) (*item)[si][i] );
- }
- }
-
-/* Free the intermediate axes pointer */
- (*item)[si] = (char ***) astFree( (void *) (*item)[si] );
- }
- }
-
-/* Free the co-ordinate versions pointer */
- *item = (char ****) astFree( (void *) *item );
-
-/* If there was an error status on entry to this function, re-instate it.
- Otherwise, allow any new error status to remain. */
- if( oldstatus ){
- if( !astOK ) astClearStatus;
- astSetStatus( oldstatus );
- astReporting( oldreport );
- }
- }
-}
-
-static FitsStore *FreeStore( FitsStore *store, int *status ){
-/*
-* Name:
-* FreeStore
-
-* Purpose:
-* Free dynamic arrays stored in a FitsStore structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* FitsStore *FreeStore( FitsStore *store, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function frees all dynamically allocated arrays stored in the
-* supplied FitsStore structure, and returns a NULL pointer.
-
-* Parameters:
-* store
-* Pointer to the structure to clean.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - This function attempts to execute even if an error exists on entry.
-*/
-
-/* Return if no FitsStore was supplied. */
- if( !store ) return NULL;
-
-/* Free each of the dynamic arrays stored in the FitsStore. */
- FreeItemC( &(store->cname), status );
- FreeItemC( &(store->ctype), status );
- FreeItemC( &(store->ctype_com), status );
- FreeItemC( &(store->cunit), status );
- FreeItemC( &(store->radesys), status );
- FreeItemC( &(store->wcsname), status );
- FreeItemC( &(store->specsys), status );
- FreeItemC( &(store->ssyssrc), status );
- FreeItemC( &(store->ps), status );
- FreeItemC( &(store->timesys), status );
- FreeItem( &(store->pc), status );
- FreeItem( &(store->cdelt), status );
- FreeItem( &(store->crpix), status );
- FreeItem( &(store->crval), status );
- FreeItem( &(store->equinox), status );
- FreeItem( &(store->latpole), status );
- FreeItem( &(store->lonpole), status );
- FreeItem( &(store->mjdobs), status );
- FreeItem( &(store->dut1), status );
- FreeItem( &(store->mjdavg), status );
- FreeItem( &(store->pv), status );
- FreeItem( &(store->wcsaxes), status );
- FreeItem( &(store->obsgeox), status );
- FreeItem( &(store->obsgeoy), status );
- FreeItem( &(store->obsgeoz), status );
- FreeItem( &(store->restfrq), status );
- FreeItem( &(store->restwav), status );
- FreeItem( &(store->zsource), status );
- FreeItem( &(store->velosys), status );
- FreeItem( &(store->asip), status );
- FreeItem( &(store->bsip), status );
- FreeItem( &(store->apsip), status );
- FreeItem( &(store->bpsip), status );
- FreeItem( &(store->imagfreq), status );
- FreeItem( &(store->axref), status );
- store->tables = astAnnul( store->tables );
- FreeItem( &(store->skyref), status );
- FreeItem( &(store->skyrefp), status );
- FreeItemC( &(store->skyrefis), status );
- return (FitsStore *) astFree( (void *) store );
-}
-
-static char *FormatKey( const char *key, int c1, int c2, char s, int *status ){
-/*
-* Name:
-* FormatKey
-
-* Purpose:
-* Format a keyword name with indices and co-ordinate version character.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* char *FormatKey( const char *key, int c1, int c2, char s, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function formats a keyword name by including the supplied
-* axis/parameter indices and co-ordinate version character.
-
-* Parameters:
-* key
-* The base name of the keyword (e.g. "CD", "CRVAL", etc).
-* c1
-* An integer value to append to the end of the keyword. Ignored if
-* less than zero.
-* c2
-* A second integer value to append to the end of the keyword. Ignored if
-* less than zero. This second integer is preceded by an underscore.
-* s
-* The co-ordinate version character to append to the end of the
-* final string. Ignored if blank.
-* status
-* Pointer to the inherited status variable.
-* Returned Value;
-* A pointer to a static character buffer containing the final string.
-* NULL if an error occurs.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS
- char *ret;
- int len;
- int nc;
-
-/* Initialise */
- ret = NULL;
-
-/* Check inherited status */
- if( !astOK ) return ret;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(NULL);
-
-/* No characters stored yet. A value of -1 is used to indicate that an
- error has occurred. */
- len = 0;
-
-/* Store the supplied keyword base name. */
- if( len >= 0 && ( nc = sprintf( formatkey_buff + len, "%s", key ) ) >= 0 ){
- len += nc;
- } else {
- len = -1;
- }
-
-/* If index c1 has been supplied, append it to the end of the string. */
- if( c1 >= 0 ) {
- if( len >= 0 && ( nc = sprintf( formatkey_buff + len, "%d", c1 ) ) >= 0 ){
- len += nc;
- } else {
- len = -1;
- }
-
-/* If index c2 has been supplied, append it to the end of the string,
- preceded by an underscore. */
- if( c2 >= 0 ) {
- if( len >= 0 && ( nc = sprintf( formatkey_buff + len, "_%d", c2 ) ) >= 0 ){
- len += nc;
- } else {
- len = -1;
- }
- }
- }
-
-/* If a co-ordinate version character has been supplied, append it to the end
- of the string. */
- if( s != ' ' ) {
- if( len >= 0 && ( nc = sprintf( formatkey_buff + len, "%c", s ) ) >= 0 ){
- len += nc;
- } else {
- len = -1;
- }
- }
-
-/* Report an error if necessary */
- if( len < 0 && astOK ) {
- astError( AST__INTER, "FormatKey(fitschan): AST internal error; failed "
- "to format the keyword %s with indices %d and %d, and "
- "co-ordinate version %c.", status, key, c1, c2, s );
- ret = NULL;
- } else {
- ret = formatkey_buff;
- }
- return formatkey_buff;
-}
-
-static AstObject *FsetFromStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* FsetFromStore
-
-* Purpose:
-* Create a FrameSet using the the information previously stored in
-* the suppllied FitsStore structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstObject *FsetFromStore( AstFitsChan *this, FitsStore *store,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function creates a new FrameSet containing WCS information
-* stored in the supplied FitsStore. A null pointer is returned and no
-* error is reported if this is not possible.
-
-* Parameters:
-* this
-* The FitsChan from which the keywords were read. Warning messages
-* are added to this FitsChan if the celestial co-ordinate system is
-* not recognized.
-* store
-* Pointer to the FitsStore.
-* 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 pointer to the new FrameSet, or a null pointer if no FrameSet
-* could be constructed.
-
-* Notes:
-* - The pixel Frame is given a title of "Pixel Coordinates", and
-* each axis in the pixel Frame is given a label of the form "Pixel
-* axis <n>", where <n> is the axis index (starting at one).
-* - The FITS CTYPE keyword values are used to set the labels for any
-* non-celestial axes in the physical coordinate Frames, and the FITS
-* CUNIT keywords are used to set the corresponding units strings.
-* - On exit, the pixel Frame is the base Frame, and the physical
-* Frame derived from the primary axis descriptions is the current Frame.
-* - Extra Frames are added to hold any secondary axis descriptions. All
-* axes within such a Frame refer to the same coordinate version ('A',
-* 'B', etc).
-*/
-
-/* Local Variables: */
- AstFrame *frame; /* Pointer to pixel Frame */
- AstFrameSet *ret; /* Pointer to returned FrameSet */
- char buff[ 20 ]; /* Buffer for axis label */
- char s; /* Co-ordinate version character */
- int i; /* Pixel axis index */
- int physical; /* Index of primary physical co-ordinate Frame */
- int pixel; /* Index of pixel Frame in returned FrameSet */
- int use; /* Has this co-ordinate version been used? */
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return (AstObject *) ret;
-
-/* Only proceed if there are some axes. */
- if( store->naxis ) {
-
-/* Create a Frame describing the pixel coordinate system. Give it the Domain
- GRID. */
- frame = astFrame( store->naxis, "Title=Pixel Coordinates,Domain=GRID", status );
-
-/* Store labels for each pixel axis. */
- if( astOK ){
- for( i = 0; i < store->naxis; i++ ){
- sprintf( buff, "Pixel axis %d", i + 1 );
- astSetLabel( frame, i, buff );
- }
- }
-
-/* Create the FrameSet initially holding just the pixel coordinate frame
- (this becomes the base Frame). */
- ret = astFrameSet( frame, "", status );
-
-/* Annul the pointer to the pixel coordinate Frame. */
- frame = astAnnul( frame );
-
-/* Get the index of the pixel Frame in the FrameSet. */
- pixel = astGetCurrent( ret );
-
-/* Produce the Frame describing the primary axis descriptions, and add it
- into the FrameSet. */
- AddFrame( this, ret, pixel, store->naxis, store, ' ', method, class, status );
-
-/* Get the index of the primary physical co-ordinate Frame in the FrameSet. */
- physical = astGetCurrent( ret );
-
-/* Loop, producing secondary axis Frames for each of the co-ordinate
- versions stored in the FitsStore. */
- for( s = 'A'; s <= GetMaxS( &(store->crval), status ) && astOK; s++ ){
-
-/* Only use this co-ordinate version character if any of the required
- keywords (for any axis) are stored in the FitsStore. */
- use = 0;
- for( i = 0; i < store->naxis; i++ ){
- if( GetItem( &(store->crval), i, 0, s, NULL, method, class, status ) != AST__BAD ||
- GetItem( &(store->crpix), 0, i, s, NULL, method, class, status ) != AST__BAD ||
- GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status ) != NULL ){
- use = 1;
- break;
- }
- }
-
-/* If this co-ordinate version has been used, add a Frame to the returned
- FrameSet holding this co-ordinate version. */
- if( use ) AddFrame( this, ret, pixel, store->naxis, store, s, method, class, status );
- }
-
-/* Ensure the pixel Frame is the Base Frame and the primary physical
- Frame is the Current Frame. */
- astSetBase( ret, pixel );
- astSetCurrent( ret, physical );
-
-/* Remove any unneeded Frames that hold a FITS representation of offset
- coordinates. */
- TidyOffsets( ret, status );
-
-/* If an error has occurred, free the returned FrameSet and return a null
- pointer. */
- if( !astOK ) ret = astAnnul( ret );
- }
-
-/* Return the answer. */
- return (AstObject *) ret;
-}
-
-static FitsStore *FsetToStore( AstFitsChan *this, AstFrameSet *fset, int naxis,
- double *dim, int encoding, const char *class,
- const char *method, int *status ){
-
-/*
-* Name:
-* FsetToStore
-
-* Purpose:
-* Fill a FitsStore structure with a description of the supplied
-* FrameSet.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* FitsStore *FsetToStore( AstFitsChan *this, AstFrameSet *fset, int naxis,
-* double *dim, int encoding, const char *class,
-* const char *method, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function creates a new FitsStore containing WCS information
-* read from the supplied FitsChan using the specified encoding. An
-* error is reported and a null pointer returned if the FitsChan does
-* not contain usable WCS information with the specified encoding.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* fset
-* Pointer to the FrameSet.
-* naxis
-* The number of axes in the Base Frame of the supplied FrameSet.
-* dim
-* Pointer to an array of pixel axis dimensions. Individual elements
-* will be AST__BAD if dimensions are not known.
-* encoding
-* The encoding being used.
-* 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 pointer to a new FitsStore, or NULL if an error has occurred. The
-* FitsStore should be released using FreeStore function when it is no
-* longer needed.
-
-* Notes:
-* - A NULL pointer will be returned if this function is invoked
-* with the AST error status set, or if it should fail for any
-* reason.
-* - The Base Frame in the FrameSet is used as the pixel Frame, and
-* the Current Frame is used to create the primary axis descriptions.
-* Attempts are made to create secondary axis descriptions for any
-* other Frames in the FrameSet (up to a total of 26).
-*/
-
-/* Local Variables: */
- AstFrame *frame; /* A Frame */
- const char *id; /* Frame Ident string */
- int nfrm; /* Number of Frames in FrameSet */
- char *sid; /* Pointer to array of version letters */
- int frms[ 'Z' + 1 ]; /* Array of Frame indices */
- FitsStore *ret; /* Returned FitsStore */
- char s; /* Next available co-ordinate version character */
- char s0; /* Co-ordinate version character */
- int ibase; /* Base Frame index */
- int icurr; /* Current Frame index */
- int ifrm; /* Next Frame index */
- int isoff; /* Is the Frame an offset SkyFrame? */
- int primok; /* Primary Frame stored succesfully? */
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Allocate memory for the new FitsStore, and store NULL pointers in it. */
- ret = (FitsStore *) astMalloc( sizeof(FitsStore) );
- if( astOK ) {
- ret->cname = NULL;
- ret->ctype = NULL;
- ret->ctype_com = NULL;
- ret->cunit = NULL;
- ret->ps = NULL;
- ret->radesys = NULL;
- ret->wcsname = NULL;
- ret->wcsaxes = NULL;
- ret->pc = NULL;
- ret->cdelt = NULL;
- ret->crpix = NULL;
- ret->crval = NULL;
- ret->equinox = NULL;
- ret->latpole = NULL;
- ret->lonpole = NULL;
- ret->dut1 = NULL;
- ret->mjdobs = NULL;
- ret->mjdavg = NULL;
- ret->pv = NULL;
- ret->specsys = NULL;
- ret->ssyssrc = NULL;
- ret->obsgeox = NULL;
- ret->obsgeoy = NULL;
- ret->obsgeoz = NULL;
- ret->restfrq = NULL;
- ret->restwav = NULL;
- ret->zsource = NULL;
- ret->velosys = NULL;
- ret->asip = NULL;
- ret->bsip = NULL;
- ret->apsip = NULL;
- ret->bpsip = NULL;
- ret->imagfreq = NULL;
- ret->axref = NULL;
- ret->naxis = naxis;
- ret->timesys = NULL;
- ret->tables = astKeyMap( " ", status );
- ret->skyref = NULL;
- ret->skyrefp = NULL;
- ret->skyrefis = NULL;
-
-/* Obtain the index of the Base Frame (i.e. the pixel frame ). */
- ibase = astGetBase( fset );
-
-/* Obtain the index of the Current Frame (i.e. the Frame to use as the
- primary physical coordinate frame). */
- icurr = astGetCurrent( fset );
-
-/* Does the current Frame contain a SkyFrame that describes offset
- coordinates? */
- isoff = IsSkyOff( fset, icurr, status );
-
-/* Add a description of the primary axes to the FitsStore, based on the
- Current Frame in the FrameSet. */
- primok = AddVersion( this, fset, ibase, icurr, ret, dim, ' ',
- encoding, isoff, method, class, status );
-
-/* Do not add any alternate axis descriptions if the primary axis
- descriptions could not be produced. */
- if( primok && astOK ) {
-
-/* Get the number of Frames in the FrameSet. */
- nfrm = astGetNframe( fset );
-
-/* We now need to allocate a version letter to each Frame. Allocate
- memory to hold the version letter assigned to each Frame. */
- sid = (char *) astMalloc( ( nfrm + 1 )*sizeof( char ) );
-
-/* The frms array has an entry for each of the 26 possible version
- letters (starting at A and ending at Z). Each entry holds the index of
- the Frame which has been assigned that version character. Initialise
- this array to indicate that no version letters have yet been assigned. */
- for( s = 'A'; s <= 'Z'; s++ ) {
- frms[ (int) s ] = 0;
- }
-
-/* Loop round all frames (excluding the current and base and IWC Frames which
- do not need version letters). If the Frame has an Ident attribute consisting
- of a single upper case letter, use it as its version letter unless that
- letter has already been given to an earlier frame. IWC Frames are not
- written out - identify them by giving them a "sid" value of 1 (an
- illegal FITS axis description character). */
- for( ifrm = 1; ifrm <= nfrm; ifrm++ ){
- sid[ ifrm ] = 0;
- if( ifrm != icurr && ifrm != ibase ) {
- frame = astGetFrame( fset, ifrm );
- if( astChrMatchN( astGetDomain( frame ), "IWC", 3 ) ) {
- sid[ ifrm ] = 1;
- } else {
- id = astGetIdent( frame );
- if( strlen( id ) == 1 && isupper( id[ 0 ] ) ) {
- if( frms[ (int) id[ 0 ] ] == 0 ) {
- frms[ (int) id[ 0 ] ] = ifrm;
- sid[ ifrm ] = id[ 0 ];
- }
- }
- }
- (void) astAnnul( frame );
- }
- }
-
-/* Now go round all the Frames again, looking for Frames which did not
- get a version letter assigned to it on the previous loop. Assign them
- letters now, selected them from the letters not already assigned
- (lowest to highest). */
- s = 'A' - 1;
- for( ifrm = 1; ifrm <= nfrm; ifrm++ ){
- if( ifrm != icurr && ifrm != ibase && sid[ ifrm ] != 1 ) {
- if( sid[ ifrm ] == 0 ){
- while( frms[ (int) ++s ] != 0 );
- if( s <= 'Z' ) {
- sid[ ifrm ] = s;
- frms[ (int) s ] = ifrm;
- }
- }
- }
- }
-
-/* If the primary headers describe offset coordinates, create an alternate
- axis description for the correspondsing absolute coordinate system. */
- if( isoff && ++s <= 'Z' ) {
- (void) AddVersion( this, fset, ibase, icurr, ret, dim,
- s, encoding, -1, method, class, status );
- }
-
-/* Now go through all the other Frames in the FrameSet, attempting to
- create alternate axis descriptions for each one. */
- for( ifrm = 1; ifrm <= nfrm; ifrm++ ){
- s0 = sid[ ifrm ];
- if( s0 != 0 && s0 != 1 ) {
-
-/* Does it contain an offset sky frame? */
- isoff = IsSkyOff( fset, ifrm, status );
-
-/* Write out the Frame - offset if it is offset, absolute otherwise. */
- (void) AddVersion( this, fset, ibase, ifrm, ret, dim,
- s0, encoding, isoff, method, class, status );
-
-/* If the Frame is offset, create an extra alternate axis description for
- the correspondsing absolute coordinate system. */
- if( isoff && ++s <= 'Z' ) {
- (void) AddVersion( this, fset, ibase, ifrm, ret, dim,
- s, encoding, -1, method, class, status );
- }
- }
- }
-
-/* Free memory holding version letters */
- sid = (char *) astFree( (void *) sid );
- }
-
-/* If an error has occurred, or if the primary Frame could not be cerated,
- free the returned FitsStore, and return a null pointer. */
- if( !astOK || !primok ) ret = FreeStore( ret, status );
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static int GetClean( AstFitsChan *this, int *status ) {
-
-/*
-* Name:
-* GetClean
-
-* Purpose:
-* Return the value of the Clean attribute.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int GetClean( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns the value of the Clean attribute. Since this
-* attribute controls the behaviour of the FitsChan in the event of an
-* error condition, it is is necessary to ignore any inherited error
-* condition when getting the attribute value. This is why the
-* astMAKE_GET macro is not used.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The Clean value to use.
-*/
-
-/* Return if no FitsChan pointer was supplied. */
- if ( !this ) return 0;
-
-/* Return the attribute value, supplying a default value of 0 (false). */
- return ( this->clean == -1 ) ? 0 : (this->clean ? 1 : 0 );
-}
-
-static int GetObjSize( AstObject *this_object, int *status ) {
-/*
-* Name:
-* GetObjSize
-
-* Purpose:
-* Return the in-memory size of an Object.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetObjSize( AstObject *this, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the astGetObjSize protected
-* method inherited from the parent class).
-
-* Description:
-* This function returns the in-memory size of the supplied FitsChan,
-* in bytes.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* 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: */
- AstFitsChan *this; /* Pointer to FitsChan structure */
- FitsCard *card; /* Pointer to next FitsCard */
- int result; /* Result value to return */
-
-/* Initialise. */
- result = 0;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Obtain a pointers to the FitsChan structure. */
- this = (AstFitsChan *) this_object;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* 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 );
- result += astTSizeOf( this->warnings );
- result += astGetObjSize( this->keyseq );
- result += astGetObjSize( this->keywords );
- result += astGetObjSize( this->tables );
- card = (FitsCard *) ( this->head );
- while( card ) {
- result += astTSizeOf( card );
- result += card->size;
- result += astTSizeOf( card->comment );
- card = GetLink( card, NEXT, "astGetObjSize", "FitsChan", status );
- if( (void *) card == this->head ) break;
- }
-
-/* If an error occurred, clear the result value. */
- if ( !astOK ) result = 0;
-
-/* Return the result, */
- return result;
-}
-
-static int GetCDMatrix( AstFitsChan *this, int *status ){
-
-/*
-* Name:
-* GetCDMatrix
-
-* Purpose:
-* Get the value of the CDMatrix attribute.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int GetCDMatrix( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* If the CDMatrix attribute has been set, then its value is returned.
-* Otherwise, the supplied FitsChan is searched for keywords of the
-* form CDi_j. If any are found a non-zero value is returned. Otherwise
-* a zero value is returned.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The attribute value to use.
-
-* Notes:
-* - A value of zero is returned if an error has already occurred
-* or if an error occurs for any reason within this function.
-*/
-
-/* Local Variables... */
- int ret; /* Returned value */
- int icard; /* Index of current card on entry */
-
-/* Check the global status. */
- if( !astOK ) return 0;
-
-/* If a value has been supplied for the CDMatrix attribute, use it. */
- if( astTestCDMatrix( this ) ) {
- ret = this->cdmatrix;
-
-/* Otherwise, check for the existence of CDi_j keywords... */
- } else {
-
-/* Save the current card index, and rewind the FitsChan. */
- icard = astGetCard( this );
- astClearCard( this );
-
-/* If the FitsChan contains any keywords with the format "CDi_j" then return
- 1. Otherwise return zero. */
- ret = astKeyFields( this, "CD%1d_%1d", 0, NULL, NULL ) ? 1 : 0;
-
-/* Reinstate the original current card index. */
- astSetCard( this, icard );
- }
-
-/* Return the result. */
- return astOK ? ret : 0;
-}
-
-static int GetEncoding( AstFitsChan *this, int *status ){
-
-/*
-* Name:
-* GetEncoding
-
-* Purpose:
-* Get the value of the Encoding attribute.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetEncoding( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* If the Encoding attribute has been set, then its value is returned.
-* Otherwise, an attempt is made to determine the encoding scheme by
-* looking for selected keywords within the FitsChan. Checks are made
-* for the following keywords in the order specified, and the
-* corresponding encoding is adopted when the first one is found ( where
-
-* i, j and m are integers and s is a single upper case character):
-*
-* 1) Any keywords starting with "BEGAST" = Native encoding
-* 2) DELTAV and VELO-xxx (or VLSR) keywords = FITS-CLASS.
-* 3) Any AIPS spectral CTYPE values:
-
-* Any of CDi_j, PROJP, LONPOLE, LATPOLE = FITS-AIPS++ encoding:
-* None of the above = FITS-AIPS encoding.
-* 4) Any keywords matching PCiiijjj = FITS-PC encoding
-* 5) Any keywords matching CDiiijjj = FITS-IRAF encoding
-* 6) Any keywords matching CDi_j, AND at least one of RADECSYS, PROJPi
-* or CmVALi = FITS-IRAF encoding
-* 7) Any keywords RADECSYS, PROJPi or CmVALi, and no CDi_j or PCi_j
-* keywords, = FITS-PC encoding
-* 8) Any keywords matching CROTAi = FITS-AIPS encoding
-* 9) Keywords matching CRVALi = FITS-WCS encoding
-* 10) The PLTRAH keyword = DSS encoding
-* 11) If none of the above keywords are found, Native encoding is assumed.
-*
-* For cases 2) to 9), a check is also made that the header contains
-* at least one of each keyword CTYPE, CRPIX and CRVAL. If not, then
-* the checking process continues to the next case. This goes some way
-* towards ensuring that the critical keywords used to determine the
-* encoding are part of a genuine WCS description and have not just been
-* left in the header by accident.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The encoding scheme identifier.
-
-* Notes:
-* - The function returns UNKNOWN_ENCODING if an error has already occurred
-* or if an error occurs for any reason within this function.
-*/
-
-/* Local Variables... */
- int hascd; /* Any CDi_j keywords found? */
- int haspc; /* Any PCi_j keywords found? */
- int haswcs; /* Any CRVAL, CTYPE and CRPIX found? */
- int icard; /* Index of current card on entry */
- int ret; /* Returned value */
-
-/* Check the global status. */
- if( !astOK ) return UNKNOWN_ENCODING;
-
-/* If a value has been supplied for the Encoding attribute, use it. */
- if( astTestEncoding( this ) ) {
- ret = this->encoding;
-
-/* Otherwise, check for the existence of certain critcal keywords... */
- } else {
-
-/* See if the header contains some CTYPE, CRPIX and CRVAL keywords. */
- haswcs = astKeyFields( this, "CTYPE%d", 0, NULL, NULL ) &&
- astKeyFields( this, "CRPIX%d", 0, NULL, NULL ) &&
- astKeyFields( this, "CRVAL%d", 0, NULL, NULL );
-
-/* See if there are any CDi_j keywords. */
- hascd = astKeyFields( this, "CD%1d_%1d", 0, NULL, NULL );
-
-/* See if there are any PCi_j keywords. */
- haspc = astKeyFields( this, "PC%1d_%1d", 0, NULL, NULL );
-
-/* Save the current card index, and rewind the FitsChan. */
- icard = astGetCard( this );
- astClearCard( this );
-
-/* If the FitsChan contains any keywords starting with "BEGAST", then return
- "Native" encoding. */
- if( astKeyFields( this, "BEGAST%2f", 0, NULL, NULL ) ){
- ret = NATIVE_ENCODING;
-
-/* Otherwise, look for a FITS-CLASS signature... */
- } else if( haswcs && LooksLikeClass( this, "astGetEncoding", "AstFitsChan", status ) ){
- ret = FITSCLASS_ENCODING;
-
-/* Otherwise, if the FitsChan contains any CTYPE keywords which have the
- peculiar form used by AIPS, then use "FITS-AIPS" or "FITS-AIPS++" encoding. */
- } else if( haswcs && HasAIPSSpecAxis( this, "astGetEncoding", "AstFitsChan", status ) ){
- if( hascd ||
- astKeyFields( this, "PROJP%d", 0, NULL, NULL ) ||
- astKeyFields( this, "LONPOLE", 0, NULL, NULL ) ||
- astKeyFields( this, "LATPOLE", 0, NULL, NULL ) ) {
- ret = FITSAIPSPP_ENCODING;
- } else {
- ret = FITSAIPS_ENCODING;
- }
-
-/* Otherwise, if the FitsChan contains the "PLTRAH" keywords, use "DSS"
- encoding. */
- } else if( astKeyFields( this, "PLTRAH", 0, NULL, NULL ) ){
- ret = DSS_ENCODING;
-
-/* Otherwise, if the FitsChan contains any keywords with the format
- "PCiiijjj" then return "FITS-PC" encoding. */
- } else if( haswcs && astKeyFields( this, "PC%3d%3d", 0, NULL, NULL ) ){
- ret = FITSPC_ENCODING;
-
-/* Otherwise, if the FitsChan contains any keywords with the format
- "CDiiijjj" then return "FITS-IRAF" encoding. */
- } else if( haswcs && astKeyFields( this, "CD%3d%3d", 0, NULL, NULL ) ){
- ret = FITSIRAF_ENCODING;
-
-/* Otherwise, if the FitsChan contains any keywords with the format
- "CDi_j" AND there is a RADECSYS. PROJPi or CmVALi keyword, then return
- "FITS-IRAF" encoding. If "CDi_j" is present but none of the others
- are, return "FITS-WCS" encoding. */
- } else if( haswcs && hascd ) {
- if( ( astKeyFields( this, "RADECSYS", 0, NULL, NULL ) &&
- !astKeyFields( this, "RADESYS", 0, NULL, NULL ) ) ||
- ( astKeyFields( this, "PROJP%d", 0, NULL, NULL ) &&
- !astKeyFields( this, "PV%d_%d", 0, NULL, NULL ) ) ||
- ( astKeyFields( this, "C%1dVAL%d", 0, NULL, NULL )) ){
- ret = FITSIRAF_ENCODING;
- } else {
- ret = FITSWCS_ENCODING;
- }
-
-/* Otherwise, if the FitsChan contains any keywords with the format
- RADECSYS. PROJPi or CmVALi keyword, then return "FITS-PC" encoding,
- so long as there are no FITS-WCS equivalent keywords. */
- } else if( haswcs && !haspc && !hascd && (
- ( astKeyFields( this, "RADECSYS", 0, NULL, NULL ) &&
- !astKeyFields( this, "RADESYS", 0, NULL, NULL ) ) ||
- ( astKeyFields( this, "PROJP%d", 0, NULL, NULL ) &&
- !astKeyFields( this, "PV%d_%d", 0, NULL, NULL ) ) ||
- astKeyFields( this, "C%1dVAL%d", 0, NULL, NULL ) ) ) {
- ret = FITSPC_ENCODING;
-
-/* Otherwise, if the FitsChan contains any keywords with the format
- "CROTAi" then return "FITS-AIPS" encoding. */
- } else if( haswcs && astKeyFields( this, "CROTA%d", 0, NULL, NULL ) ){
- ret = FITSAIPS_ENCODING;
-
-/* Otherwise, if the FitsChan contains any keywords with the format
- "CRVALi" then return "FITS-WCS" encoding. */
- } else if( haswcs && astKeyFields( this, "CRVAL%d", 0, NULL, NULL ) ){
- ret = FITSWCS_ENCODING;
-
-/* If none of these conditions is met, assume Native encoding. */
- } else {
- ret = NATIVE_ENCODING;
- }
-
-/* Reinstate the original current card index. */
- astSetCard( this, icard );
- }
-
-/* Return the encoding scheme. */
- return astOK ? ret : UNKNOWN_ENCODING;
-}
-
-static void GetFiducialNSC( AstWcsMap *map, double *phi, double *theta, int *status ){
-/*
-* Name:
-* GetFiducialNSC
-
-* Purpose:
-* Return the Native Spherical Coordinates at the fiducial point of a
-* WcsMap projection.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void GetFiducialNSC( AstWcsMap *map, double *phi, double *theta, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns the native spherical coords corresponding at
-* the fiducial point of a WcsMap.
-*
-* The values of parameters 1 and 2 on the longitude axis of the WcsMap
-* are usually used as the native spherical coordinates of the
-* fiducial point. The default values for these parameters are equal
-* to the native spherical coordinates of the projection reference point.
-* The exception is that a TPN projection always uses the default
-* values, since the projection parameters are used to store polynomial
-* coefficients.
-
-* Parameters:
-* map
-* Pointer to the WcsMap.
-* phi
-* Address of a location at which to return the native spherical
-* longitude at the fiducial point (radians).
-* theta
-* Address of a location at which to return the native spherical
-* latitude at the fiducial point (radians).
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- int axlon; /* Index of longitude axis */
-
-/* Initialise */
- *phi = AST__BAD;
- *theta = AST__BAD;
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* If this is not a TPN projection get he value of the required
- projection parameters (the default values for these are equal to the
- fixed native shperical coordinates at the projection reference point). */
- if( astGetWcsType( map ) != AST__TPN ) {
- axlon = astGetWcsAxis( map, 0 );
- if( astGetPV( map, axlon, 0 ) != 0.0 ) {
- *phi = AST__DD2R*astGetPV( map, axlon, 1 );
- *theta = AST__DD2R*astGetPV( map, axlon, 2 );
- } else {
- *phi = astGetNatLon( map );
- *theta = astGetNatLat( map );
- }
-
-/* If this is a TPN projection, the returned values are always the fixed
- native shperical coordinates at the projection reference point). */
- } else {
- *phi = astGetNatLon( map );
- *theta = astGetNatLat( map );
- }
-}
-
-static void GetFiducialPPC( AstWcsMap *map, double *x0, double *y0, int *status ){
-/*
-* Name:
-* GetFiducialPPC
-
-* Purpose:
-* Return the IWC at the fiducial point of a WcsMap projection.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void GetFiducialPPC( AstWcsMap *map, double *x0, double *y0, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns the projection plane coords corresponding to
-* the native spherical coords of the fiducial point of a FITS-WCS
-* header. Note, projection plane coordinates (PPC) are equal to
-* Intermediate World Coordinates (IWC) except for cases where the
-* fiducial point does not correspond to the projection reference point.
-* In these cases, IWC and PPC will be connected by a translation
-* which ensures that the fiducial point corresponds to the origin of
-* IWC.
-*
-* The values of parameters 1 and 2 on the longitude axis of
-* the WcsMap are used as the native spherical coordinates of the
-* fiducial point. The default values for these parameters are equal
-* to the native spherical coordinates of the projection reference point.
-
-* Parameters:
-* map
-* Pointer to the WcsMap.
-* x0
-* Address of a location at which to return the PPC X axis value at
-* the fiducial point (radians).
-* y0
-* Address of a location at which to return the PPC Y axis value at
-* the fiducial point (radians).
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- AstPointSet *pset1; /* Pointer to the native spherical PointSet */
- AstPointSet *pset2; /* Pointer to the intermediate world PointSet */
- double **ptr1; /* Pointer to pset1 data */
- double **ptr2; /* Pointer to pset2 data */
- int axlat; /* Index of latitude axis */
- int axlon; /* Index of longitude axis */
- int i; /* Loop count */
- int naxes; /* Number of axes */
-
-/* Initialise */
- *x0 = AST__BAD;
- *y0 = AST__BAD;
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* Save number of axes in the WcsMap. */
- naxes = astGetNin( map );
-
-/* Allocate resources. */
- pset1 = astPointSet( 1, naxes, "", status );
- ptr1 = astGetPoints( pset1 );
- pset2 = astPointSet( 1, naxes, "", status );
- ptr2 = astGetPoints( pset2 );
-
-/* Check pointers can be used safely. */
- if( astOK ) {
-
-/* Get the indices of the longitude and latitude axes in WcsMap. */
- axlon = astGetWcsAxis( map, 0 );
- axlat = astGetWcsAxis( map, 1 );
-
-/* Use zero on all non-celestial axes. */
- for( i = 0; i < naxes; i++ ) ptr1[ i ][ 0 ] = 0.0;
-
-/* Get the native spherical coords at the fiducial point. */
- GetFiducialNSC( map, ptr1[ axlon ], ptr1[ axlat ], status );
-
-/* Use the inverse WcsMap to convert the native longitude and latitude of
- the fiducial point into PPC (x,y). */
- (void) astTransform( map, pset1, 0, pset2 );
-
-/* Return the calculated PPC coords. */
- *x0 = ptr2[ axlon ][ 0 ];
- *y0 = ptr2[ axlat ][ 0 ];
- }
-
-/* Free resources. */
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
-}
-
-static int GetFiducialWCS( AstWcsMap *wcsmap, AstMapping *map2, int colon,
- int colat, double *fidlon, double *fidlat, int *status ){
-/*
-* Name:
-* GetFiducialWCS
-
-* Purpose:
-* Decide on the celestial coordinates of the fiducial point.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetFiducialWCS( AstWcsMap wcsmap, AstMapping map2, int colon,
-* int colat, double *fidlon, double *fidlat, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns the celestial longitude and latitude values
-* to use for the fiducial point. These are the values stored in FITS
-* keywords CRVALi.
-
-* Parameters:
-* wcsmap
-* The WcsMap which converts Projection Plane Coordinates into
-* native spherical coordinates. The number of outputs from this
-* Mapping should match the number of inputs to "map2".
-* map2
-* The Mapping which converts native spherical coordinates into WCS
-* coordinates.
-* colon
-* The index of the celestial longitude output from "map2".
-* colat
-* The index of the celestial latitude output from "map2".
-* fidlon
-* Pointer to a location at which to return the celestial longitude
-* value at the fiducial point. The value is returned in radians.
-* fidlat
-* Pointer to a location at which to return the celestial latitude
-* value at the fiducial point. The value is returned in radians.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero if the fiducial point longitude or latitude could not be
-* determined. One otherwise.
-*/
-
-/* Local Variables: */
- AstPointSet *pset1; /* Pointer to the native spherical PointSet */
- AstPointSet *pset2; /* Pointer to the WCS PointSet */
- double **ptr1; /* Pointer to pset1 data */
- double **ptr2; /* Pointer to pset2 data */
- int axlat; /* Index of latitude axis */
- int axlon; /* Index of longitude axis */
- int iax; /* Axis index */
- int naxin; /* Number of IWC axes */
- int naxout; /* Number of WCS axes */
- int ret; /* The returned FrameSet */
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Allocate resources. */
- naxin = astGetNin( map2 );
- naxout = astGetNout( map2 );
- pset1 = astPointSet( 1, naxin, "", status );
- ptr1 = astGetPoints( pset1 );
- pset2 = astPointSet( 1, naxout, "", status );
- ptr2 = astGetPoints( pset2 );
- if( astOK ) {
-
-/* Get the indices of the latitude and longitude outputs in the WcsMap.
- These are not necessarily the same as "colat" and "colon" because "map2"
- may contain a PermMap. */
- axlon = astGetWcsAxis( wcsmap, 0 );
- axlat = astGetWcsAxis( wcsmap, 1 );
-
-/* Use zero on all non-celestial axes. */
- for( iax = 0; iax < naxin; iax++ ) ptr1[ iax ][ 0 ] = 0.0;
-
-/* Get the native spherical coords at the fiducial point. */
- GetFiducialNSC( wcsmap, ptr1[ axlon ], ptr1[ axlat ], status );
-
-/* The fiducial point in the celestial coordinate system is found by
- transforming the fiducial point in native spherical co-ordinates
- into absolute physical coordinates using map2. */
- (void) astTransform( map2, pset1, 1, pset2 );
-
-/* Store the returned WCS values. */
- *fidlon = ptr2[ colon ][ 0 ];
- *fidlat = ptr2[ colat ][ 0 ];
-
-/* Indicate if we have been succesfull. */
- if( astOK && *fidlon != AST__BAD && *fidlat != AST__BAD ) ret = 1;
- }
-
-/* Free resources. */
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
-
-/* Return the result. */
- return ret;
-}
-
-static const char *GetFitsSor( const char *string, int *status ) {
-/*
-* Name:
-* GetFitsSor
-
-* Purpose:
-* Get the string used to represent an AST spectral standard of rest.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* const char *GetFitsSor( const char *string, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns a pointer to a static string which is the
-* FITS equivalent to a given SpecFrame StdOfRest value.
-
-* Parameters:
-* string
-* Pointer to a constant null-terminated string containing the
-* SpecFrame StdOfRest value.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to a static null-terminated string containing the FITS
-* equivalent to the supplied string. NULL is returned if the supplied
-* string has no FITS equivalent.
-
-* Notes:
-* - A NULL pointer value will be returned if this function is
-* invoked wth the global error status set, or if it should fail
-* for any reason.
-*/
-
-/* Local Variables: */
- const char *result; /* Pointer value to return */
-
-/* Check the global error status. */
- if ( !astOK ) return NULL;
-
-/* Compare the supplied string with SpecFrame value for which there is a
- known FITS equivalent. */
- if( !strcmp( string, "Topocentric" ) ){
- result = "TOPOCENT";
- } else if( !strcmp( string, "Geocentric" )){
- result = "GEOCENTR";
- } else if( !strcmp( string, "Barycentric" )){
- result = "BARYCENT";
- } else if( !strcmp( string, "Heliocentric" )){
- result = "HELIOCEN";
- } else if( !strcmp( string, "LSRK" )){
- result = "LSRK";
- } else if( !strcmp( string, "LSRD" )){
- result = "LSRD";
- } else if( !strcmp( string, "Galactic" )){
- result = "GALACTOC";
- } else if( !strcmp( string, "Local_group" )){
- result = "LOCALGRP";
- } else if( !strcmp( string, "Source" )){
- result = "SOURCE";
- } else {
- result = NULL;
- }
-
-/* Return the answer. */
- return result;
-}
-
-static double GetItem( double ****item, int i, int jm, char s, char *name,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* GetItem
-
-* Purpose:
-* Retrieve a value for a axis keyword value from a FitStore structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* double GetItem( double ****item, int i, int jm, char s, char *name,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The requested keyword value is retrieved from the specified array,
-* at a position indicated by the axis and co-ordinate version.
-* AST__BAD is returned if the array does not contain the requested
-* value.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->crval) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (i), and the pointer locates an
-* array of axis keyword values. These arrays of keyword values have
-* one element for every pixel axis (j) or projection parameter (m).
-* i
-* The zero based intermediate axis index in the range 0 to 98. Set
-* this to zero for keywords (e.g. CRPIX) which are not indexed by
-* intermediate axis number.
-* jm
-* The zero based pixel axis index (in the range 0 to 98) or parameter
-* index (in the range 0 to WCSLIB_MXPAR-1). Set this to zero for
-* keywords (e.g. CRVAL) which are not indexed by either pixel axis or
-* parameter number.
-* s
-* The co-ordinate version character (A to Z, or space), case
-* insensitive
-* name
-* A string holding a name for the item of information. A NULL
-* pointer may be supplied, in which case it is ignored. If a
-* non-NULL pointer is supplied, an error is reported if the item
-* of information has not been stored, and the supplied name is
-* used to identify the information within the error message.
-* 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:
-* The required keyword value, or AST__BAD if no value has previously
-* been stored for the keyword (or if an error has occurred).
-*/
-
-/* Local Variables: */
- double ret; /* Returned keyword value */
- int si; /* Integer co-ordinate version index */
-
-/* Initialise */
- ret = AST__BAD;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Convert the character co-ordinate version into an integer index, and
- check it is within range. The primary axis description (s=' ') is
- given index zero. 'A' is 1, 'B' is 2, etc. */
- if( s == ' ' ) {
- si = 0;
- } else if( islower(s) ){
- si = (int) ( s - 'a' ) + 1;
- } else {
- si = (int) ( s - 'A' ) + 1;
- }
- if( si < 0 || si > 26 ) {
- astError( AST__INTER, "GetItem(fitschan): AST internal error; "
- "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s );
-
-/* Check the intermediate axis index is within range. */
- } else if( i < 0 || i > 98 ) {
- astError( AST__INTER, "GetItem(fitschan): AST internal error; "
- "intermediate axis index %d is invalid.", status, i );
-
-/* Check the pixel axis or parameter index is within range. */
- } else if( jm < 0 || jm > 99 ) {
- astError( AST__INTER, "GetItem(fitschan): AST internal error; "
- "pixel axis or parameter index %d is invalid.", status, jm );
-
-/* Otherwise, if the array holding the required keyword is not null,
- proceed... */
- } else if( *item ){
-
-/* Find the number of coordinate versions in the supplied array.
- Only proceed if it encompasses the requested co-ordinate
- version. */
- if( astSizeOf( (void *) *item )/sizeof(double **) > si ){
-
-/* Find the number of intermediate axes in the supplied array.
- Only proceed if it encompasses the requested intermediate axis. */
- if( astSizeOf( (void *) (*item)[si] )/sizeof(double *) > i ){
-
-/* Find the number of pixel axes or parameters in the supplied array.
- Only proceed if it encompasses the requested index. */
- if( astSizeOf( (void *) (*item)[si][i] )/sizeof(double) > jm ){
-
-/* Return the required keyword value. */
- ret = (*item)[si][i][jm];
- }
- }
- }
- }
-
-/* If required, report an error if the requested item of information has
- not been stored. */
- if( ret == AST__BAD && name && astOK ){
- astError( AST__NOFTS, "%s(%s): No value can be found for %s.", status,
- method, class, name );
- }
- return ret;
-}
-
-static int GetMaxJM( double ****item, char s, int *status ){
-/*
-* Name:
-* GetMaxJM
-
-* Purpose:
-* Return the largest pixel axis or parameter index stored for an
-* numerical axis keyword value in a FitStore structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetMaxJM( double ****item, char s, int *status)
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The number of pixel axis numbers or projection parameters stored for
-* a specified axis keyword is found and returned.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->crpix) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (i), and the pointer locates an
-* array of axis keyword values. These arrays of keyword values have
-* one element for every pixel axis (j) or projection parameter (m).
-* s
-* The co-ordinate version character (A to Z, or space), case
-* insensitive
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The maximum pixel axis number or projection parameter index (zero
-* based).
-*/
-
-/* Local Variables: */
- int jm; /* Number of parameters/pixel axes */
- int i; /* Intermediate axis index */
- int ret; /* Returned axis index */
- int si; /* Integer co-ordinate version index */
-
-/* Initialise */
- ret = -1;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* If the array holding the required keyword is not null, proceed... */
- if( *item ){
-
-/* Convert the character co-ordinate version into an integer index, and
- check it is within range. The primary axis description (s=' ') is
- given index zero. 'A' is 1, 'B' is 2, etc. */
- if( s == ' ' ) {
- si = 0;
- } else if( islower(s) ){
- si = (int) ( s - 'a' ) + 1;
- } else {
- si = (int) ( s - 'A' ) + 1;
- }
- if( si < 0 || si > 26 ) {
- astError( AST__INTER, "GetMaxJM(fitschan): AST internal error; "
- "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s );
- return ret;
- }
-
-/* Find the number of coordinate versions in the supplied array.
- Only proceed if it encompasses the requested co-ordinate
- version. */
- if( astSizeOf( (void *) *item )/sizeof(double **) > si ){
-
-/* Check that the pointer to the array of intermediate axis values is not null. */
- if( (*item)[si] ){
-
-/* Loop round each used element in this array. */
- for( i = 0; i < astSizeOf( (void *) (*item)[si] )/sizeof(double *);
- i++ ){
- if( (*item)[si][i] ){
-
-/* Get the size of the pixel axis/projection parameter array for the
- current intermediate axis, and subtract 1 to get the largest index. */
- jm = astSizeOf( (void *) (*item)[si][i] )/sizeof(double) - 1;
-
-/* Ignore any trailing unused (AST__BAD) values. */
- while( jm >= 0 && (*item)[si][i][jm] == AST__BAD ) jm--;
-
-/* Update the returned value if the current value is larger. */
- if( jm > ret ) ret = jm;
- }
- }
- }
- }
- }
- return ret;
-}
-
-static int GetMaxJMC( char *****item, char s, int *status ){
-/*
-* Name:
-* GetMaxJMC
-
-* Purpose:
-* Return the largest pixel axis or parameter index stored for an
-* character-valued axis keyword value in a FitStore structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetMaxJMC( char *****item, char s, int *status)
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The number of pixel axis numbers or projection parameters stored for
-* a specified axis keyword is found and returned.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->ctype) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (i), and the pointer locates an
-* array of axis keyword string pointers. These arrays of keyword
-* string pointers have one element for every pixel axis (j) or
-* projection parameter (m).
-* s
-* The co-ordinate version character (A to Z, or space), case
-* insensitive
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The maximum pixel axis number or projection parameter index (zero
-* based).
-*/
-
-/* Local Variables: */
- int jm; /* Number of parameters/pixel axes */
- int i; /* Intermediate axis index */
- int ret; /* Returned axis index */
- int si; /* Integer co-ordinate version index */
-
-/* Initialise */
- ret = -1;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* If the array holding the required keyword is not null, proceed... */
- if( *item ){
-
-/* Convert the character co-ordinate version into an integer index, and
- check it is within range. The primary axis description (s=' ') is
- given index zero. 'A' is 1, 'B' is 2, etc. */
- if( s == ' ' ) {
- si = 0;
- } else if( islower(s) ){
- si = (int) ( s - 'a' ) + 1;
- } else {
- si = (int) ( s - 'A' ) + 1;
- }
- if( si < 0 || si > 26 ) {
- astError( AST__INTER, "GetMaxJMC(fitschan): AST internal error; "
- "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s );
- return ret;
- }
-
-/* Find the number of coordinate versions in the supplied array.
- Only proceed if it encompasses the requested co-ordinate
- version. */
- if( astSizeOf( (void *) *item )/sizeof(char ***) > si ){
-
-/* Check that the pointer to the array of intermediate axis values is not null. */
- if( (*item)[si] ){
-
-/* Loop round each used element in this array. */
- for( i = 0; i < astSizeOf( (void *) (*item)[si] )/sizeof(char **);
- i++ ){
- if( (*item)[si][i] ){
-
-/* Get the size of the pixel axis/projection parameter array for the
- current intermediate axis, and subtract 1 to get the largest index. */
- jm = astSizeOf( (void *) (*item)[si][i] )/sizeof(char *) - 1;
-
-/* Ignore any trailing unused (NULL) values. */
- while( jm >= 0 && (*item)[si][i][jm] == NULL ) jm--;
-
-/* Update the returned value if the current value is larger. */
- if( jm > ret ) ret = jm;
- }
- }
- }
- }
- }
- return ret;
-}
-
-static int GetMaxI( double ****item, char s, int *status ){
-/*
-* Name:
-* GetMaxI
-
-* Purpose:
-* Return the largest WCS axis index stored for an axis keyword value in
-* a FitStore structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetMaxJM( double ****item, char s)
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The number of Wcs axis numbers stored for a specified axis keyword is
-* found and returned.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->crval) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (i), and the pointer locates an
-* array of axis keyword values. These arrays of keyword values have
-* one element for every pixel axis (j) or projection parameter (m).
-* s
-* The co-ordinate version character (A to Z, or space), case
-* insensitive
-
-* Returned Value:
-* The maximum WCS axis index (zero based).
-*/
-
-/* Local Variables: */
- int ret; /* Returned axis index */
- int si; /* Integer co-ordinate version index */
-
-/* Initialise */
- ret = -1;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* If the array holding the required keyword is not null, proceed... */
- if( *item ){
-
-/* Convert the character co-ordinate version into an integer index, and
- check it is within range. The primary axis description (s=' ') is
- given index zero. 'A' is 1, 'B' is 2, etc. */
- if( s == ' ' ) {
- si = 0;
- } else if( islower(s) ){
- si = (int) ( s - 'a' ) + 1;
- } else {
- si = (int) ( s - 'A' ) + 1;
- }
- if( si < 0 || si > 26 ) {
- astError( AST__INTER, "GetMaxI(fitschan): AST internal error; "
- "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s );
- return ret;
- }
-
-/* Find the number of coordinate versions in the supplied array.
- Only proceed if it encompasses the requested co-ordinate
- version. */
- if( astSizeOf( (void *) *item )/sizeof(double **) > si ){
-
-/* Check that the pointer to the array of intermediate axis values is not null. */
- if( (*item)[si] ){
-
-/* Get the size of the intermediate axis array and subtract 1 to get the largest
- index. */
- ret = astSizeOf( (void *) (*item)[si] )/sizeof(double *) - 1;
-
-/* Ignore any trailing unused (NULL) values. */
- while( ret >= 0 && (*item)[si][ret] == NULL ) ret--;
- }
- }
- }
- return ret;
-}
-
-static char GetMaxS( double ****item, int *status ){
-/*
-* Name:
-* GetMaxS
-
-* Purpose:
-* Return the largest (i.e. closest to Z) coordinate version character
-* stored for a axis keyword value in a FitStore structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* char GetMaxS( double ****item, int *status)
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The largest (i.e. closest to Z) coordinate version character
-* stored for a axis keyword value in a FitStore structure is found
-* and returned.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->crval) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (i), and the pointer locates an
-* array of axis keyword values. These arrays of keyword values have
-* one element for every pixel axis (j) or projection parameter (m).
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The highest coordinate version character.
-*/
-
-/* Local Variables: */
- char ret; /* Returned axis index */
- int si; /* Integer index into alphabet */
-
-/* Initialise */
- ret = ' ';
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* If the array holding the required keyword is not null, proceed... */
- if( *item ){
-
-/* Find the length of this array, and subtract 1 to get the largest index
- in the array. */
- si = astSizeOf( (void *) *item )/sizeof(double **) - 1;
-
-/* Ignore any trailing null (i.e. unused) values. */
- while( si >= 0 && !(*item)[si] ) si--;
-
-/* Store the corresponding character */
- if( si == 0 ) {
- ret = ' ';
- } else {
- ret = 'A' + si - 1;
- }
- }
- return ret;
-}
-
-static char *GetItemC( char *****item, int i, int jm, char s, char *name,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* GetItemC
-
-* Purpose:
-* Retrieve a string value for a axis keyword value from a FitStore
-* structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* char *GetItemC( char *****item, int i, int jm, char s, char *name,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The requested keyword string value is retrieved from the specified
-* array, at a position indicated by the axis and co-ordinate version.
-* NULL is returned if the array does not contain the requested
-* value.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->ctype) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (i), and the pointer locates an
-* array of axis keyword string pointers. These arrays of keyword
-* string pointers have one element for every pixel axis (j) or
-* projection parameter (m).
-* i
-* The zero based intermediate axis index in the range 0 to 98. Set
-* this to zero for keywords (e.g. CRPIX) which are not indexed by
-* intermediate axis number.
-* jm
-* The zero based pixel axis index (in the range 0 to 98) or parameter
-* index (in the range 0 to WCSLIB__MXPAR-1). Set this to zero for
-* keywords (e.g. CTYPE) which are not indexed by either pixel axis or
-* parameter number.
-* s
-* The co-ordinate version character (A to Z, or space), case
-* insensitive
-* name
-* A string holding a name for the item of information. A NULL
-* pointer may be supplied, in which case it is ignored. If a
-* non-NULL pointer is supplied, an error is reported if the item
-* of information has not been stored, and the supplied name is
-* used to identify the information within the error message.
-* 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 pointer to the required keyword string value, or NULL if no value
-* has previously been stored for the keyword (or if an error has
-* occurred).
-*/
-
-/* Local Variables: */
- char *ret; /* Returned keyword value */
- int si; /* Integer co-ordinate version index */
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Convert the character co-ordinate version into an integer index, and
- check it is within range. The primary axis description (s=' ') is
- given index zero. 'A' is 1, 'B' is 2, etc. */
- if( s == ' ' ) {
- si = 0;
- } else if( islower(s) ){
- si = (int) ( s - 'a' ) + 1;
- } else {
- si = (int) ( s - 'A' ) + 1;
- }
- if( si < 0 || si > 26 ) {
- astError( AST__INTER, "GetItemC(fitschan): AST internal error; "
- "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s );
-
-/* Check the intermediate axis index is within range. */
- } else if( i < 0 || i > 98 ) {
- astError( AST__INTER, "GetItemC(fitschan): AST internal error; "
- "intermediate axis index %d is invalid.", status, i );
-
-/* Check the pixel axis or parameter index is within range. */
- } else if( jm < 0 || jm > 99 ) {
- astError( AST__INTER, "GetItem(fitschan): AST internal error; "
- "pixel axis or parameter index %d is invalid.", status, jm );
-
-/* Otherwise, if the array holding the required keyword is not null,
- proceed... */
- } else if( *item ){
-
-/* Find the number of coordinate versions in the supplied array.
- Only proceed if it encompasses the requested co-ordinate
- version. */
- if( astSizeOf( (void *) *item )/sizeof(char ***) > si ){
-
-/* Find the number of intermediate axes in the supplied array.
- Only proceed if it encompasses the requested intermediate axis. */
- if( astSizeOf( (void *) (*item)[si] )/sizeof(char **) > i ){
-
-/* Find the number of pixel axes or parameters in the supplied array.
- Only proceed if it encompasses the requested index. */
- if( astSizeOf( (void *) (*item)[si][i] )/sizeof(char *) > jm ){
-
-/* Return the required keyword value. */
- ret = (*item)[si][i][jm];
- }
- }
- }
- }
-
-/* If required, report an error if the requested item of information has
- not been stored. */
- if( !ret && name && astOK ){
- astError( AST__NOFTS, "%s(%s): No value can be found for %s.", status,
- method, class, name );
- }
- return ret;
-}
-
-static AstFitsTable *GetNamedTable( AstFitsChan *this, const char *extname,
- int extver, int extlevel, int report,
- const char *method, int *status ){
-
-/*
-* Name:
-* GetNamedTable
-
-* Purpose:
-* Return a FitsTable holding the contents of a named FITS binary table.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* AstFitsTable *GetNamedTable( AstFitsChan *this, const char *extname,
-* int extver, int extlevel, int report,
-* const char *method, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* If a table source function has been registered with FitsChan (using
-* astTableSource), invoke it to read the required table from the external
-* FITS file. If the extension is available in the FITS file, this will
-* put a FitsTable into the "tables" KeyMap in the FitsChan structure,
-* using the FITS extension name as the key - this will replace any
-* FitsTable already present in the KeyMap with the same key. Finally,
-* return a pointer to the FitsTable stored in the KeyMap - if any.
-*
-* This strategy allows the astPutTables or astPutTable method to be used
-* as an alternative to registering a table source function with the
-* FitsChan. Note, any table read using the source function is used
-* in preference to any table stored in the FitsChan by an earlier call
-* to astPutTables/astPutTable.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* extname
-* The key associated with the required table - should be the name
-* of the FITS extension containing the binary table.
-* extver
-* The FITS "EXTVER" value for the required table.
-* extlevel
-* The FITS "EXTLEVEL" value for the required table.
-* report
-* If non-zero, report an error if the named table is not available.
-* method
-* Pointer to a string holding the name of the calling method.
-* This is only for use in constructing error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to the FitsTable, or NULL if the table is not avalable.
-*/
-
-/* Local Variables: */
- AstFitsTable *ret;
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Fitrst attempt to read the required table from the external FITS file.
- Only proceed if table source function and wrapper have been supplied
- using astTableSource. */
- if( this->tabsource && this->tabsource_wrap ){
-
-/* Invoke the table source function asking it to place the required FITS
- table in the FitsChan. This is an externally supplied function which may
- not be thread-safe, so lock a mutex first. Note, a cloned FitsChan pointer
- is sent to the table source function since the table source function will
- annul the supplied FitsChan pointer. Also store the channel data
- pointer in a global variable so that it can be accessed in the source
- function using macro astChannelData. */
- astStoreChannelData( this );
- LOCK_MUTEX2;
- ( *this->tabsource_wrap )( this->tabsource, astClone( this ), extname,
- extver, extlevel, status );
- UNLOCK_MUTEX2;
- }
-
-/* Now get a pointer to the required FitsTable, stored as an entry in the
- "tables" KeyMap. Report an error if required. */
- if( ! (this->tables) || !astMapGet0A( this->tables, extname, &ret ) ){
- if( report && astOK ) {
- astError( AST__NOTAB, "%s(%s): Failed to read FITS binary table "
- "from extension '%s' (extver=%d, extlevel=%d).", status,
- method, astGetClass( this ), extname, extver, extlevel );
- }
- }
-
-/* Return the result. */
- return ret;
-}
-
-static AstKeyMap *GetTables( AstFitsChan *this, int *status ) {
-
-/*
-*++
-* Name:
-c astGetTables
-f AST_GETTABLES
-
-* Purpose:
-* Retrieve any FitsTables currently in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-c AstKeyMap *astGetTables( AstFitsChan *this )
-f RESULT = AST_GETTABLES( THIS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* If the supplied FitsChan currently contains any tables, then this
-* function returns a pointer to a KeyMap. Each entry in the KeyMap
-* is a pointer to a FitsTable holding the data for a FITS binary
-* table. The key used to access each entry is the FITS extension
-* name in which the table should be stored.
-*
-* Tables can be present in a FitsChan as a result either of using the
-c astPutTable (or astPutTables)
-f AST_PUTTABLE (or AST_PUTTABLES)
-* method to store existing tables in the FitsChan, or of using the
-c astWrite
-f AST_WRITE
-* method to write a FrameSet to the FitsChan. For the later case, if
-* the FitsChan "TabOK" attribute is positive and the FrameSet requires
-* a look-up table to describe one or more axes, then the "-TAB"
-* algorithm code described in FITS-WCS paper III is used and the table
-* values are stored in the FitsChan in the form of a FitsTable object
-* (see the documentation for the "TabOK" attribute).
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astGetTables()
-f AST_GETTABLES = INTEGER
-* A pointer to a deep copy of the KeyMap holding the tables currently
-* in the FitsChan, or
-c NULL
-f AST__NULL
-* if the FitsChan does not contain any tables. The returned
-* pointer should be annulled using
-c astAnnul
-f AST_ANNUL
-* when no longer needed.
-
-* Notes:
-* - A null Object pointer (AST__NULL) will be returned if this
-c function is invoked with the AST error status set, or if it
-f function is invoked with STATUS set to an error value, or if it
-* should fail for any reason.
-*--
-*/
-
-/* Local Variables: */
- AstKeyMap *result; /* Pointer value to return */
-
-/* Initialise. */
- result = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* If the FitsChan contains any tables, return a pointer to a copy of
- the KeyMap containing them. Otherwise, return a NULL pointer. */
- if( this->tables && astMapSize( this->tables ) > 0 ) {
- result = astCopy( this->tables );
- }
-
-/* Return the result. */
- return result;
-}
-
-static int GetUsedPolyTan( AstFitsChan *this, AstFitsChan *out, int latax,
- int lonax, char s, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* GetUsedPolyTan
-
-* Purpose:
-* Get the value to use for the PolyTan attribute.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetUsedPolyTan( AstFitsChan *this, AstFitsChan *out, int latax,
-* int lonax, char s, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* If the PolyTan attribute is zero or positive, then its value is
-* returned. If it is negative, the supplied FitsChan is searched for
-* keywords of the form PVi_m. If any are found on the latitude axis,
-* or if any are found on the longitude axis with "m" > 4, +1 is
-* returned (meaning "use the distorted TAN conventio"). Otherwise 0
-* is returned (meaning "use the standard TAN convention").
-*
-* If all the PVi_m values for m > 0 on either axis are zero, a warning is
-* issued and zero is returned.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* out
-* Pointer to a secondary FitsChan. If the PV values in "this" are
-* found to be unusable, they will be marked as used in both "this"
-* and "out".
-* latax
-* The one-based index of the latitude axis within the FITS header.
-* lonax
-* The one-based index of the longitude axis within the FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The attribute value to use.
-
-* Notes:
-* - A value of zero is returned if an error has already occurred
-* or if an error occurs for any reason within this function.
-*/
-
-/* Local Variables... */
- char template[ 20 ];
- double pval;
- int lbnd_lat;
- int lbnd_lon;
- int m;
- int nfound1;
- int nfound2;
- int ok;
- int ret;
- int ubnd_lat;
- int ubnd_lon;
-
-/* Check the global status. */
- if( !astOK ) return 0;
-
-/* Get the value of the PolyTan attribute. */
- ret = astGetPolyTan( this );
-
-/* If it is negative, we examine the FitsChan to see which convention to
- use. */
- if( ret < 0 ) {
- ret = 0;
-
-/* Search the FitsChan for latitude PV cards. */
- if( s != ' ' ) {
- sprintf( template, "PV%d_%%d%c", latax, s );
- } else {
- sprintf( template, "PV%d_%%d", latax );
- }
- nfound1 = astKeyFields( this, template, 1, &ubnd_lat, &lbnd_lat );
-
-/* Search the FitsChan for longitude PV cards. */
- if( s != ' ' ) {
- sprintf( template, "PV%d_%%d%c", lonax, s );
- } else {
- sprintf( template, "PV%d_%%d", lonax );
- }
- nfound2 = astKeyFields( this, template, 1, &ubnd_lon, &lbnd_lon );
-
-/* If any were found with "m" value greater than 4, assume the distorted
- TAN convention is in use. Otherwise assume the stdanrd TAN convention is
- in use. */
- if( nfound1 || ( nfound2 && ubnd_lon > 4 ) ) ret = 1;
-
-/* If the distorted TAN convention is to be used, check that at least one
- of the PVi_m values is non-zero on each axis. We ignore the PVi_0
- (constant) terms in this check. */
- if( ret > 0 ) {
-
-/* Do the latitude axis first, skipping the first (constant) term. Assume
- that all latitude pV values are zero until we find one that is not. */
- ok = 0;
- for( m = 1; m <= ubnd_lat && !ok; m++ ) {
-
-/* Form the PVi_m keyword name. */
- if( s != ' ' ) {
- sprintf( template, "PV%d_%d%c", latax, m, s );
- } else {
- sprintf( template, "PV%d_%d", latax, m );
- }
-
-/* Get it's value. */
- if( ! GetValue( this, template, AST__FLOAT, &pval, 0, 0,
- method, class, status ) ) {
-
-/* If the PVi_m header is not present in the FitsChan, use a default value. */
- pval = ( m == 1 ) ? 1.0 : 0.0;
- }
-
-/* If the PVi_m header has a non-zero value, we can leave the loop. */
- if( pval != 0.0 ) ok = 1;
- }
-
-/* If all the latitude PVi_m values are zero, issue a warning and return
- zero, indicating that a simple undistorted TAN projection should be used. */
- if( !ok ) {
- Warn( this, "badpv", "This FITS header describes a distorted TAN "
- "projection, but all the distortion coefficients (the "
- "PVi_m headers) on the latitude axis are zero.", method,
- class, status );
- ret = 0;
-
-
-/* Also, delete the PV keywords so that no attempt is made to use them. */
- for( m = 1; m <= ubnd_lat; m++ ) {
- if( s != ' ' ) {
- sprintf( template, "PV%d_%d%c", latax, m, s );
- } else {
- sprintf( template, "PV%d_%d", latax, m );
- }
- astClearCard( this );
- if( FindKeyCard( this, template, method, class, status ) ) {
- DeleteCard( this, method, class, status );
- }
- }
-
-/* Otherwise, do the same check for the longitude axis. */
- } else {
- ok = 0;
- for( m = 1; m <= ubnd_lon && !ok; m++ ) {
-
- if( s != ' ' ) {
- sprintf( template, "PV%d_%d%c", lonax, m, s );
- } else {
- sprintf( template, "PV%d_%d", lonax, m );
- }
-
- if( ! GetValue( this, template, AST__FLOAT, &pval, 0, 0,
- method, class, status ) ) {
-
- pval = ( m == 1 ) ? 1.0 : 0.0;
- }
-
- if( pval != 0.0 ) ok = 1;
- }
-
- if( !ok ) {
- Warn( this, "badpv", "This FITS header describes a distorted TAN "
- "projection, but all the distortion coefficients (the "
- "PVi_m headers) on the longitude axis are zero.", method,
- class, status );
- ret = 0;
-
- for( m = 1; m <= ubnd_lon; m++ ) {
- if( s != ' ' ) {
- sprintf( template, "PV%d_%d%c", lonax, m, s );
- } else {
- sprintf( template, "PV%d_%d", lonax, m );
- }
- astClearCard( this );
- if( FindKeyCard( this, template, method, class, status ) ) {
- DeleteCard( this, method, class, status );
- }
- }
- }
- }
- }
- }
-
-/* Return the result. */
- return astOK ? ret : 0;
-}
-
-static int GoodWarns( const char *value, int *status ){
-/*
-* Name:
-* GoodWarns
-
-* Purpose:
-* Checks a string to ensure it is a legal list of warning conditions.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GoodWarns( const char *value, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function checks the supplied string to ensure it contains a space
-* separated list of zero or more recognised warning conditions. An
-* error is reported if it does not.
-
-* Parameters:
-* value
-* The string to check.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero is returned if the supplied string is not a legal list of
-* conditions, or if an error has already occurred. One is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- char *b; /* Pointer to next buffer element */
- const char *c ; /* Pointer to next character */
- char buf[100]; /* Buffer for condition name */
- int inword; /* Are we in a word? */
- int n; /* Number of conditions supplied */
- int ret; /* Returned value */
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Report an error and return if the pointer is null. */
- if( !value ){
- astError( AST__ATTIN, "astSetWarnings(fitschan): Null pointer "
- "supplied for the Warnings attribute." , status);
- return ret;
- }
-
-/* Initialise things */
- inword = 0;
- buf[ 0 ] = ' ';
- b = buf + 1;
- n = 0;
- ret = 1;
-
-/* Loop round each character in the supplied string. */
- for( c = value ; c < value + strlen( value ) + 1; c++ ){
-
-/* Have we found the first space or null following a word? */
- if( ( !(*c) || isspace( *c ) ) && inword ){
-
-/* Add a space to the end of the buffer and terminate it. */
- *(b++) = ' ';
- *b = 0;
-
-/* Check the word is legal by searching for it in the string of all
- conditions, which should be lower case and have spaces at start and end.
- The word in the buffer is delimited by spaces and so it will not match
- a substring within a condition. If it is legal increment the number of
- conditions found. */
- if( strstr( ALLWARNINGS, buf ) ){
- n++;
-
-/* Otherwise, report an error and break. */
- } else {
- ret = 0;
- *(--b) = 0;
- astError( AST__ATTIN, "astSetWarnings(fitschan): Unknown "
- "condition '%s' specified when setting the Warnings "
- "attribute.", status, buf + 1 );
- break;
- }
-
-/* Reset the pointer to the next character in the buffer, retaining the
- initial space in the buffer. */
- b = buf + 1;
-
-/* Indicate we are no longer in a word. */
- inword = 0;
-
-/* Have we found the first non-space, non-null character following a space? */
- } else if( *c && !isspace( *c ) && !inword ){
-
-/* Note we are now in a word. */
- inword = 1;
- }
-
-/* If we are in a word, copy the lowercase character to the buffer. */
- if( inword ) *(b++) = tolower( *c );
- }
- return ret;
-}
-
-static AstMapping *GrismSpecWcs( char *algcode, FitsStore *store, int i,
- char s, AstSpecFrame *specfrm,
- const char *method, const char *class, int *status ) {
-/*
-* Name:
-* GrismSpecWcs
-
-* Purpose:
-* Create a Mapping describing a FITS-WCS grism-dispersion algorithm
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *GrismSpecWcs( char *algcode, FitsStore *store, int i, char s,
-* AstSpecFrame *specfrm, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function uses the contents of the supplied FitsStore to create
-* a Mapping which goes from Intermediate World Coordinate (known as "w"
-* in the context of FITS-WCS paper III) to the spectral system
-* described by the supplied SpecFrame.
-*
-* The returned Mapping implements the grism "GRA" and "GRI" algorithms
-* described in FITS-WCS paper III.
-
-* Parameters:
-* algcode
-* Pointer to a string holding the code for the required algorithm
-* ("-GRA" or "-GRI").
-* store
-* Pointer to the FitsStore structure holding the values to use for
-* the WCS keywords.
-* i
-* The zero-based index of the spectral axis within the FITS header
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* specfrm
-* Pointer to the SpecFrame. This specifies the "S" system - the
-* system in which the CRVAL kewyords (etc) are specified.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to a Mapping, or NULL if an error occurs.
-*/
-
-/* Local Variables: */
- AstFrameSet *fs;
- AstMapping *gmap;
- AstMapping *map1;
- AstMapping *map2;
- AstMapping *map2a;
- AstMapping *map2b;
- AstMapping *ret;
- AstMapping *smap;
- AstSpecFrame *wfrm;
- double crv;
- double dg;
- double gcrv;
- double pv;
- double wcrv;
-
-/* Check the global status. */
- ret = NULL;
- if( !astOK ) return ret;
-
-/* The returned Mapping will be a CmpMap including a GrismMap. This
- GrismMap will produced wavelength as output. We also need the Mapping
- from wavelength to the system represented by the supplied SpecFrame.
- To get this, we first create a copy of the supplied SpecFrame (in order
- to inherit the standard of rest, epoch, etc), and set its System to
- wavlength in vacuum (for "-GRI") or air (for "-GRA"), and then use
- astConvert to get the Mapping from the SpecFrame system to relevant
- form of wavelength. */
- wfrm = astCopy( specfrm );
- astSetSystem( wfrm, strcmp( algcode, "-GRI" )?AST__AIRWAVE:AST__WAVELEN );
- astSetUnit( wfrm, 0, "m" );
- fs = astConvert( specfrm, wfrm, "" );
- if( fs ) {
- smap = astGetMapping( fs, AST__BASE, AST__CURRENT );
- fs = astAnnul( fs );
-
-/* Get the CRVAL value for the spectral axis (this will be in the S system). */
- crv = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( crv == AST__BAD ) crv = 0.0;
-
-/* Convert it to the wavelength system (vacuum or air) in metres. */
- astTran1( smap, 1, &crv, 1, &wcrv );
-
-/* Create a GrismMap, and then use the projection parameters stored in
- the FitsStore to set its attributes (convert degrees values to radians
- and supply the defaults specified in FITS-WCS paper III). The FITS
- paper specifies units in which these parameters should be stored in a
- FITS header - distances are in metres and angles in degrees. */
- gmap = (AstMapping *) astGrismMap( "", status );
- pv = GetItem( &(store->pv), i, 0, s, NULL, method, class, status );
- astSetGrismG( gmap, ( pv != AST__BAD )?pv:0.0 );
- pv = GetItem( &(store->pv), i, 1, s, NULL, method, class, status );
- astSetGrismM( gmap, ( pv != AST__BAD )?(int) ( pv + 0.5 ):0);
- pv = GetItem( &(store->pv), i, 2, s, NULL, method, class, status );
- astSetGrismAlpha( gmap, ( pv != AST__BAD )?pv*AST__DD2R:0.0 );
- pv = GetItem( &(store->pv), i, 3, s, NULL, method, class, status );
- astSetGrismNR( gmap, ( pv != AST__BAD )?pv:1.0 );
- pv = GetItem( &(store->pv), i, 4, s, NULL, method, class, status );
- astSetGrismNRP( gmap, ( pv != AST__BAD )?pv:0.0 );
- pv = GetItem( &(store->pv), i, 5, s, NULL, method, class, status );
- astSetGrismEps( gmap, ( pv != AST__BAD )?pv*AST__DD2R:0.0 );
- pv = GetItem( &(store->pv), i, 6, s, NULL, method, class, status );
- astSetGrismTheta( gmap, ( pv != AST__BAD )?pv*AST__DD2R:0.0 );
-
-/* Store the reference wavelength found above as an attribute of the
- GrismMap. */
- astSetGrismWaveR( gmap, wcrv );
-
-/* Invert the GrismMap to get the (Wavelength -> grism parameter) Mapping, and
- then combine it with the (S -> Wavelength) Mapping to get the (S -> grism
- parameter) Mapping. */
- astInvert( gmap );
- map1 = (AstMapping *) astCmpMap( smap, gmap, 1, "", status );
-
-/* Convert the reference point value from wavelength to grism parameter. */
- astTran1( gmap, 1, &wcrv, 1, &gcrv );
-
-/* Find the rate of change of grism parameter with respect to the S
- system at the reference point, dg/dS. */
- dg = astRate( map1, &crv, 0, 0 );
- if( dg != AST__BAD && dg != 0.0 ) {
-
-/* FITS-WCS paper II requires headers to be constructed so that dS/dw = 1.0
- at the reference point. Therefore dg/dw = dg/dS. Create a WinMap which
- scales and shifts the "w" value to get the grism parameter value. */
- map2a = (AstMapping *) astZoomMap( 1, dg, "", status );
- map2b = (AstMapping *) astShiftMap( 1, &gcrv, "", status );
- map2 = (AstMapping *) astCmpMap( map2a, map2b, 1, "", status );
- map2a = astAnnul( map2a );
- map2b = astAnnul( map2b );
-
-/* The Mapping to be returned is the concatenation of the above Mapping
- (from w to g) with the Mapping from g to S. */
- astInvert( map1 );
- ret = (AstMapping *) astCmpMap( map2, map1, 1, "", status );
- map2 = astAnnul( map2 );
- }
- map1 = astAnnul( map1 );
- smap = astAnnul( smap );
- gmap = astAnnul( gmap );
- }
- wfrm = astAnnul( wfrm );
-
-/* Return the result */
- return ret;
-}
-
-static int KeyFields( AstFitsChan *this, const char *filter, int maxfld,
- int *ubnd, int *lbnd, int *status ){
-
-/*
-*+
-* Name:
-* astKeyFields
-
-* Purpose:
-* Find the ranges taken by integer fields within the keyword names
-* in a FitsChan.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int astKeyFields( AstFitsChan *this, const char *filter, int maxfld,
-* int *ubnd, int *lbnd )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function returns the number of cards within a FitsChan which
-* refer to keywords which match the supplied filter template. If the
-* filter contains any integer field specifiers (e.g. "%d", "%3d", etc),
-* it also returns the upper and lower bounds found for the integer
-* fields.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* filter
-* The filter string.
-* maxfld
-* The size of the "ubnd" and "lbnd" arrays.
-* ubnd
-* A pointer to an integer array in which to return the
-* upper bound found for each integer field in the filter.
-* They are stored in the order in which they occur in the filter.
-* If the filter contains too many fields to fit in the supplied
-* array, the excess trailing fields are ignored.
-* lbnd
-* A pointer to an integer array in which to return the
-* lower bound found for each integer field in the filter.
-
-* Returned Value:
-* astKeyFields()
-* The total number of cards matching the supplied filter in the
-* FitsChan.
-
-* Filter Syntax:
-* - The criteria for a keyword name to match a filter template are
-* as follows:
-* - All characters in the template other than "%" (and the field width
-* and type specifiers which follow a "%") must be matched by an
-* identical character in the test string.
- - If a "%" occurs in the template, then the next character in the
-* template should be a single digit specifying a field width. If it is
-* zero, then the test string may contain zero or more matching characters.
-* Otherwise, the test string must contain exactly the specified number
-* of matching characters (i.e. 1 to 9). The field width digit may be
-* omitted, in which case the test string must contain one or more matching
-* characters. The next character in the template specifies the type of
-* matching characters and must be one of "d", "c" or "f". Decimal digits
-* are matched by "d", all upper (but not lower) case alphabetical
-* characters are matched by "c", and all characters which may legally be
-* found within a FITS keyword name are matched by "f".
-
-* Examples:
-* - The filter "CRVAL1" accepts the single keyword CRVAL1.
-* - The filter "CRVAL%1d" accepts the single keyword CRVAL0, CRVAL1,
-* CRVAL2, up to CRVAL9.
-* - The filter "CRVAL%d" accepts any keyword consisting of the string
-* "CRVAL" followed by any integer value.
-* - The filter "CR%0s1" accepts any keyword starting with the string "CR"
-* and ending with the character "1" (including CR1).
-
-* Notes:
-* - The entire FitsChan is searched, irrespective of the setting of
-* the Card attribute.
-* - If "maxfld" is supplied as zero, "ubnd" and "lbnd" are ignored,
-* but the number of matching cards is still returned as the function value.
-* - If no matching cards are found in the FitsChan, or if there are no
-* integer fields in the filter, then the lower and upper bounds are
-* returned as zero and -1 (i.e. reversed).
-* - If an error has already occured, or if this function should fail
-* for any reason, a value of zero is returned for the function value,
-* and the lower and upper bounds are set to zero and -1.
-*-
-*/
-
-/* Local Variables: */
- const char *class; /* Object class */
- const char *method; /* Method name */
- int *fields; /* Pointer to array of field values */
- int i; /* Field index */
- int icard; /* Index of current card on entry */
- int nmatch; /* No. of matching cards */
- int nf; /* No. of integer fields in the filter */
- int nfld; /* No. of integer fields in current keyword name */
-
-/* Initialise the returned values. */
- nmatch = 0;
- for( i = 0; i < maxfld; i++ ){
- lbnd[ i ] = 0;
- ubnd[ i ] = -1;
- }
- nf = 0;
-
-/* Check the global error status. */
- if ( !astOK || !filter ) return nf;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Store the method name and object class for use in error messages. */
- method = "astKeyFields";
- class = astGetClass( this );
-
-/* Count the number of integer fields in the filter string. */
- nf = CountFields( filter, 'd', method, class, status );
-
-/* If this is larger than the supplied arrays, use the size of the arrays
- instead. */
- if( nf > maxfld ) nf = maxfld;
-
-/* Allocate memory to hold the integer field values extracted from
- each matching keyword. */
- fields = (int *) astMalloc( sizeof( int )*(size_t) nf );
-
-/* Save the current card index, and rewind the FitsChan. */
- icard = astGetCard( this );
- astClearCard( this );
-
-/* Check that the FitsChan is not empty and the pointer can be used. */
- if( !astFitsEof( this ) && astOK ){
-
-/* Initialise the returned bounds. Any excess elements in the array are left
- at the previously initialised values. */
- for( i = 0; i < nf; i++ ){
- lbnd[ i ] = INT_MAX;
- ubnd[ i ] = -INT_MAX;
- }
-
-/* Initialise the number of matching keywords. */
- nmatch = 0;
-
-/* Loop round all the cards in the FitsChan. */
- while( !astFitsEof( this ) && astOK ){
-
-/* If the current keyword name matches the filter, update the returned
- bounds and increment the number of matches. */
- if( Match( CardName( this, status ), filter, nf, fields, &nfld,
- method, class, status ) ){
- for( i = 0; i < nf; i++ ){
- if( fields[ i ] > ubnd[ i ] ) ubnd[ i ] = fields[ i ];
- if( fields[ i ] < lbnd[ i ] ) lbnd[ i ] = fields[ i ];
- }
- nmatch++;
- }
-
-/* Move on to the next card. */
- MoveCard( this, 1, method, class, status );
- }
-
-/* If bounds were not found, returned 0 and -1. */
- for( i = 0; i < nf; i++ ){
- if( lbnd[ i ] == INT_MAX ){
- lbnd[ i ] = 0;
- ubnd[ i ] = -1;
- }
- }
- }
-
-/* Reinstate the original current card index. */
- astSetCard( this, icard );
-
-/* Free the memory used to hold the integer field values extracted from
- each matching keyword. */
- fields = (int *) astFree( (void *) fields );
-
-/* If an error has occurred, returned no matches and reversed bounds. */
- if( !astOK ){
- nmatch = 0;
- for( i = 0; i < maxfld; i++ ){
- lbnd[ i ] = 0;
- ubnd[ i ] = -1;
- }
- }
-
-/* Returned the answer. */
- return nmatch;
-}
-
-static int FindFits( AstFitsChan *this, const char *name,
- char card[ AST__FITSCHAN_FITSCARDLEN + 1 ], int inc, int *status ){
-
-/*
-*++
-* Name:
-c astFindFits
-f AST_FINDFITS
-
-* Purpose:
-* Find a FITS card in a FitsChan by keyword.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c int astFindFits( AstFitsChan *this, const char *name, char card[ 81 ],
-c int inc )
-f RESULT = AST_FINDFITS( THIS, NAME, CARD, INC, STATUS )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function searches for a card in a FitsChan by keyword. The
-* search commences at the current card (identified by the Card
-* attribute) and ends when a card is found whose FITS keyword
-* matches the template supplied, or when the last card in the
-* FitsChan has been searched.
-*
-* If the search is successful (i.e. a card is found which matches
-c the template), the contents of the card are (optionally)
-f the template), the contents of the card are
-* returned and the Card attribute is adjusted to identify the card
-* found or, if required, the one following it. If the search is
-c not successful, the function returns zero and the Card attribute
-f not successful, the function returns .FALSE. and the Card attribute
-* is set to the "end-of-file".
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c name
-f NAME = CHARACTER * ( * ) (Given)
-c Pointer to a null-terminated character string containing a
-f A character string containing a
-* template for the keyword to be found. In the simplest case,
-* this should simply be the keyword name (the search is case
-* insensitive and trailing spaces are ignored). However, this
-* template may also contain "field specifiers" which are
-* capable of matching a range of characters (see the "Keyword
-* Templates" section for details). In this case, the first card
-* with a keyword which matches the template will be found. To
-* find the next FITS card regardless of its keyword, you should
-* use the template "%f".
-c card
-f CARD = CHARACTER * ( 80 ) (Returned)
-c An array of at least 81 characters (to allow room for a
-c terminating null)
-f A character variable with at least 80 characters
-* in which the FITS card which is found will be returned. If
-c the search is not successful (or a NULL pointer is given), a
-f the search is not successful, a
-* card will not be returned.
-c inc
-f INC = LOGICAL (Given)
-c If this value is zero (and the search is successful), the
-f If this value is .FALSE. (and the search is successful), the
-* FitsChan's Card attribute will be set to the index of the card
-c that was found. If it is non-zero, however, the Card
-f that was found. If it is .TRUE., however, the Card
-* attribute will be incremented to identify the card which
-* follows the one found.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astFindFits()
-f AST_FINDFITS = LOGICAL
-c One if the search was successful, otherwise zero.
-f .TRUE. if the search was successful, otherwise .FALSE..
-
-* Notes:
-* - The search always starts with the current card, as identified
-* by the Card attribute. To ensure you search the entire contents
-* of a FitsChan, you should first clear the Card attribute (using
-c astClear). This effectively "rewinds" the FitsChan.
-f AST_CLEAR). This effectively "rewinds" the FitsChan.
-* - If a search is unsuccessful, the Card attribute is set to the
-* "end-of-file" (i.e. to one more than the number of cards in the
-* FitsChan). No error occurs.
-c - A value of zero will be returned if this function is invoked
-f - A value of .FALSE. will be returned if this function is invoked
-* with the AST error status set, or if it should fail for any
-* reason.
-
-* Examples:
-c result = astFindFits( fitschan, "%f", card, 1 );
-f RESULT = AST_FINDFITS( FITSCHAN, '%f', CARD, .TRUE., STATUS )
-* Returns the current card in a FitsChan and advances the Card
-* attribute to identify the card that follows (the "%f"
-* template matches any keyword).
-c result = astFindFits( fitschan, "BITPIX", card, 1 );
-f RESULT = AST_FINDFITS( FITSCHAN, 'BITPIX', CARD, .TRUE., STATUS )
-* Searches a FitsChan for a FITS card with the "BITPIX" keyword
-* and returns that card. The Card attribute is then incremented
-* to identify the card that follows it.
-c result = astFindFits( fitschan, "COMMENT", NULL, 0 );
-f RESULT = AST_FINDFITS( FITSCHAN, 'COMMENT', CARD, .FALSE., STATUS )
-* Sets the Card attribute of a FitsChan to identify the next
-c COMMENT card (if any). The card itself is not returned.
-f COMMENT card (if any) and returns that card.
-c result = astFindFits( fitschan, "CRVAL%1d", card, 1 );
-f RESULT = AST_FINDFITS( FITSCHAN, 'CRVAL%1d', CARD, .TRUE., STATUS )
-* Searches a FitsChan for the next card with a keyword of the
-* form "CRVALi" (for example, any of the keywords "CRVAL1",
-* "CRVAL2" or "CRVAL3" would be matched). The card found (if
-* any) is returned, and the Card attribute is then incremented
-* to identify the following card (ready to search for another
-* keyword with the same form, perhaps).
-
-* Keyword Templates:
-* The templates used to match FITS keywords are normally composed
-* of literal characters, which must match the keyword exactly
-* (apart from case). However, a template may also contain "field
-* specifiers" which can match a range of possible characters. This
-* allows you to search for keywords that contain (for example)
-* numbers, where the digits comprising the number are not known in
-* advance.
-*
-* A field specifier starts with a "%" character. This is followed
-* by an optional single digit (0 to 9) specifying a field
-* width. Finally, there is a single character which specifies the
-
-* type of character to be matched, as follows:
-*
-* - "c": matches all upper case letters,
-* - "d": matches all decimal digits,
-* - "f": matches all characters which are permitted within a FITS
-* keyword (upper case letters, digits, underscores and hyphens).
-*
-* If the field width is omitted, the field specifier matches one
-* or more characters. If the field width is zero, it matches zero
-* or more characters. Otherwise, it matches exactly the number of
-
-* characters specified. In addition to this:
-*
-* - The template "%f" will match a blank FITS keyword consisting
-* of 8 spaces (as well as matching all other keywords).
-* - A template consisting of 8 spaces will match a blank keyword
-* (only).
-*
-
-* For example:
-*
-* - The template "BitPix" will match the keyword "BITPIX" only.
-* - The template "crpix%1d" will match keywords consisting of
-* "CRPIX" followed by one decimal digit.
-* - The template "P%c" will match any keyword starting with "P"
-* and followed by one or more letters.
-* - The template "E%0f" will match any keyword beginning with "E".
-* - The template "%f" will match any keyword at all (including a
-* blank one).
-*--
-*/
-
-/* Local Variables: */
- char *c; /* Pointer to next character to check */
- char *lname; /* Pointer to copy of name without trailing spaces */
- const char *class; /* Object class */
- const char *method; /* Calling method */
- int ret; /* Was a card found? */
-
-/* Check the global status, and supplied keyword name. */
- if( !astOK ) return 0;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Store the calling method and object class. */
- method = "astFindFits";
- class = astGetClass( this );
-
-/* Get a local copy of the keyword template. */
- lname = (char *) astStore( NULL, (void *) name, strlen(name) + 1 );
-
-/* Terminate it to exclude trailing spaces. */
- c = lname + strlen(lname) - 1;
- while( *c == ' ' && c >= lname ) *(c--) = 0;
-
-/* Use the private FindKeyCard function to find the card and make it the
- current card. Always use the supplied current card (if any) if the
- template is "%f" or "%0f". */
- if ( !strcmp( lname, "%f" ) || !strcmp( lname, "%0f" ) ){
- ret = astFitsEof( this ) ? 0 : 1;
- } else {
- ret = FindKeyCard( this, lname, method, class, status );
- }
-
-/* Only proceed if the card was found. */
- if( ret && astOK ){
-
-/* Format the current card if a destination string was supplied. */
- if( card ) FormatCard( this, card, method, status );
-
-/* Increment the current card pointer if required. */
- if( inc ) MoveCard( this, 1, method, class, status );
-
-/* Indicate that a card has been formatted. */
- ret = 1;
- }
-
-/* Free the memory holding the local copy of the keyword template. */
- lname = (char *) astFree( (void *) lname );
-
-/* If an errror has occurred, return zero. */
- if( !astOK ) ret = 0;
-
-/* Return the answer. */
- return ret;
-}
-
-static int FindKeyCard( AstFitsChan *this, const char *name,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* FindKeyCard
-
-* Purpose:
-* Find the next card refering to given keyword.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int FindKeyCard( AstFitsChan *this, const char *name,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Finds the next card which refers to the supplied keyword and makes
-* it the current card. The search starts with the current card and ends
-* when it reaches the last card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a string holding the keyword template (using the
-* syntax expected by the Match function).
-* method
-* Pointer to string holding name of calling method.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A value of 1 is returned if a card was found refering to the given
-* keyword. Otherwise zero is returned.
-
-* Notes:
-* - If a NULL pointer is supplied for "name" then the current card
-* is left unchanged.
-* - The current card is set to NULL (end-of-file) if no card can be
-* found for the supplied keyword.
-*/
-
-/* Local Variables: */
- int nfld; /* Number of fields in keyword template */
- int ret; /* Was a card found? */
-
-/* Check the global status, and supplied keyword name. */
- if( !astOK || !name ) return 0;
-
-/* Indicate that no card has been found yet. */
- ret = 0;
-
-/* Search forward through the list until all cards have been checked. */
- while( !astFitsEof( this ) && astOK ){
-
-/* Break out of the loop if the keyword name from the current card matches
- the supplied keyword name. */
- if( Match( CardName( this, status ), name, 0, NULL, &nfld, method, class, status ) ){
- ret = 1;
- break;
-
-/* Otherwise, move the current card on to the next card. */
- } else {
- MoveCard( this, 1, method, class, status );
- }
- }
-
-/* Return. */
- return ret;
-}
-
-static double *FitLine( AstMapping *map, double *g, double *g0, double *w0,
- double dim, double *tol, int *status ){
-/*
-* Name:
-* FitLine
-
-* Purpose:
-* Check a Mapping for linearity.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* double *FitLine( AstMapping *map, double *g, double *g0, double *w0,
-* double dim, double *tol, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function applies the supplied Mapping to a set of points along
-* a straight line in the input space. It checks to see if the transformed
-* positions also lie on a straight line (in the output space). If so,
-* it returns the vector along this line in the output space which
-* corresponds to a unit vector along the line in the input space. If
-* not, a NULL pointer is returned.
-*
-* The returned vector is found by doing a least squares fit.
-
-* Parameters:
-* map
-* A pointer to the Mapping to test. The number of outputs must be
-* greater than or equal to the number of inputs.
-* g
-* A pointer to an array holding a unit vector within the input space
-* defining the straight line to be checked. The number of elements
-* within this array should equal the number of inputs for "map".
-* g0
-* A pointer to an array holding a position within the input space
-* giving the central position of the vector "g". The number of elements
-* within this array should equal the number of inputs for "map".
-* w0
-* A pointer to an array holding a vector within the output space
-* which corresponds to "g0". The number of elements within this array
-* should equal the number of outputs for "map".
-* dim
-* The length of the pixel axis, or AST__BAD if unknown.
-* tol
-* Pointer to an array holding the tolerance for equality on each
-* output axis.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to dynamically allocated memory holding the required vector
-* in the output space. The number of elements in this vector will equal
-* the number of outputs for "map". The memory should be freed using
-* astFree when no longer needed. If the Mapping is not linear, NULL
-* is returned.
-
-* Notes:
-* - NULL is returned if an error occurs.
-*/
-
-/* Local Constants: */
-#define NPO2 50
-#define NP (2*NPO2+1)
-
-/* Local Variables: */
- AstPointSet *pset1;
- AstPointSet *pset2;
- double **ptr1;
- double **ptr2;
- double *offset;
- double *pax;
- double *ret;
- double *voffset;
- double dax;
- double denom;
- double gap;
- double sd2;
- double sd;
- double sdw;
- double sw;
- double wmax;
- double wmin;
- int i;
- int j;
- int n;
- int nin;
- int nout;
- int ok;
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status and supplied axis size. */
- if( !astOK || dim == 0.0 ) return ret;
-
-/* Get the number of inputs and outputs for the Mapping. Return if the
- number of outputs is smaller than the number of inputs. */
- nin = astGetNin( map );
- nout = astGetNout( map );
- if( nout < nin ) return ret;
-
-/* Check the supplied position is good on all axes. */
- for( j = 0; j < nout; j++ ) {
- if( w0[ j ] == AST__BAD ) return ret;
- }
-
-/* We use NP points in the fit. If a value for "dim" has been supplied,
- we use points evenly distributed over the whole axis. If not, we use
- a gap of 1.0 (corresponds to an axis length of 100 pixels).
- Choose the gap. */
- gap = ( dim != AST__BAD ) ? dim/NP : 1.0;
-
-/* Create PointSets to hold the input and output positions. */
- pset1 = astPointSet( NP, nin, "", status );
- ptr1 = astGetPoints( pset1 );
- pset2 = astPointSet( NP, nout, "", status );
- ptr2 = astGetPoints( pset2 );
-
-/* Allocate the returned array. */
- ret = astMalloc( sizeof( double )*(size_t) nout );
-
-/* Allocate workspace to hold the constant offsets of the fit. */
- offset = astMalloc( sizeof( double )*(size_t) nout );
- voffset = astMalloc( sizeof( double )*(size_t) nout );
-
-/* Indicate we have not yet got a usable returned vector. */
- ok = 0;
-
-/* Check we can use the pointers safely. */
- if( astOK ) {
-
-/* Set up the input positions: NP evenly spaced points along a line with
- unit direction vector given by "g", centred at position given by "g0". */
- for( j = 0; j < nin; j++ ) {
- pax = ptr1[ j ];
- dax = g[ j ]*gap;
- for( i = -NPO2; i <= NPO2; i++ ) *(pax++) = g0[ j ] + dax*i;
- }
-
-/* Transform these positions into the output space. */
- (void) astTransform( map, pset1, 1, pset2 );
-
-/* Loop over all output axes, finding the component of the returned vector. */
- ok = 1;
- for( j = 0; j < nout; j++ ) {
- pax = ptr2[ j ];
-
-/* Now loop over all the transformed points to form the other required
- sums. We also form the sums needed to estimate the variance in the
- calculated offset. */
- sdw = 0.0;
- sw = 0.0;
- sd = 0.0;
- sd2 = 0.0;
- n = 0;
- wmax = -DBL_MAX;
- wmin = DBL_MAX;
- for( i = -NPO2; i <= NPO2; i++, pax++ ) {
- if( *pax != AST__BAD ) {
-
-/* Increment the required sums. */
- sdw += i*(*pax);
- sw += (*pax);
- sd += i;
- sd2 += i*i;
- n++;
- if( *pax > wmax ) wmax = *pax;
- if( *pax < wmin ) wmin = *pax;
- }
- }
-
-/* If a reasonable number of good points were found, find the component of
- the returned vector (excluding a scale factor of 1/gap). */
- denom = sd2*n - sd*sd;
- if( n > NP/4 && denom != 0.0 ) {
-
-/* Find the constant scale factor to return for this axis. If the axis
- value is constant, return zero. */
- if( wmax > wmin ) {
- ret[ j ] = (sdw*n - sw*sd)/denom;
- } else {
- ret[ j ] = 0.0;
- }
-
-/* Now find the constant offset for this axis. */
- offset[ j ] = (sw*sd2 - sdw*sd)/denom;
- } else {
- ok = 0;
- break;
- }
- }
-
-/* Now check that the fit is good enough. Each axis is checked separately.
- All axes must be good. */
- if( ok ) {
- for( j = 0; j < nout; j++ ) {
-
-/* Store the axis values implied by the linear fit in the now un-needed ptr1[0]
- array. */
- pax = ptr1[ 0 ];
- for( i = -NPO2; i <= NPO2; i++, pax++ ) {
- *pax = i*ret[ j ] + offset[ j ];
- }
-
-/* Test the fit to see if we beleive that the mapping is linear. If
- it is, scale the returned value from units of "per gap" to units of
- "per pixel". Otherwise,indicate that he returned vector is unusable. */
- if( FitOK( NP, ptr2[ j ], ptr1[ 0 ], tol[ j ], status ) ) {
- ret[ j ] /= gap;
- } else {
- ok = 0;
- break;
- }
- }
- }
- }
-
-/* Annul the PointSets. */
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
-
-/* Free memory. */
- offset = astFree( offset );
- voffset = astFree( voffset );
-
-/* If an error has occurred, or if the returned vector is unusable,
- free any returned memory */
- if( !astOK || !ok ) ret = astFree( ret );
-
-/* Return the answer. */
- return ret;
-
-/* Undefine local constants: */
-#undef NP
-#undef NPO2
-}
-
-static int FitsEof( AstFitsChan *this, int *status ){
-
-/*
-*+
-* Name:
-* astFitsEof
-
-* Purpose:
-* See if the FitsChan is at "end-of-file".
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int astFitsEof( AstFitsChan *this )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* A value of zero is returned if any more cards remain to be read from the
-* FitsChan. Otherwise a value of 1 is returned. Thus, it is
-* equivalent to testing the FitsChan for an "end-of-file" condition.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* One if no more cards remain to be read, otherwise zero.
-
-* Notes:
-* - This function attempts to execute even if an error has already
-* occurred.
-*-
-*/
-
-/* Check the supplied object. */
- if( !this ) return 1;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* If no more cards remain to be read, the current card pointer in the
- FitsChan will be NULL. Return an appropriate integer value. */
- return this->card ? 0 : 1;
-}
-
-static int FitsSof( AstFitsChan *this, int *status ){
-
-/*
-*+
-* Name:
-* FitsSof
-
-* Purpose:
-* See if the FitsChan is at "start-of-file".
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int FitsSof( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A value of 1 is returned if the current card is the first card in
-* the FitsChan. Otherwise a value of zero is returned. This function
-* is much more efficient than "astGetCard(this) <= 1" .
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero if the current card is the first card.
-
-* Notes:
-* - This function attempts to execute even if an error has already
-* occurred.
-* - A non-zero value is returned if the FitsChan is empty.
-*-
-*/
-
-/* Return if no FitsChan was supplied, or if the FitsChan is empty. */
- if ( !this || !this->head ) return 1;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* If the current card is at the head of the linked list, it is the first
- card. */
- return this->card == this->head;
-}
-
-/*
-*++
-* Name:
-c astGetFits<X>
-f AST_GETFITS<X>
-
-* Purpose:
-* Get a named keyword value from a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c int astGetFits<X>( AstFitsChan *this, const char *name, <X>type *value )
-f RESULT = AST_GETFITS<X>( THIS, NAME, VALUE, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This is a family of functions which gets a value for a named keyword,
-* or the value of the current card, from a FitsChan using one of several
-* different data types. The data type of the returned value is selected
-* by replacing <X> in the function name by one of the following strings
-* representing the recognised FITS data types:
-*
-* - CF - Complex floating point values.
-* - CI - Complex integer values.
-* - F - Floating point values.
-* - I - Integer values.
-* - L - Logical (i.e. boolean) values.
-* - S - String values.
-* - CN - A "CONTINUE" value, these are treated like string values, but
-* are encoded without an equals sign.
-*
-* The data type of the "value"
-c parameter
-f argument
-
-* depends on <X> as follows:
-*
-c - CF - "double *" (a pointer to a 2 element array to hold the real and
-c imaginary parts of the complex value).
-c - CI - "int *" (a pointer to a 2 element array to hold the real and
-c imaginary parts of the complex value).
-c - F - "double *".
-c - I - "int *".
-c - L - "int *".
-c - S - "char **" (a pointer to a static "char" array is returned at the
-c location given by the "value" parameter, Note, the stored string
-c may change on subsequent invocations of astGetFitsS so a
-c permanent copy should be taken of the string if necessary).
-c - CN - Like"S".
-f - CF - DOUBLE PRECISION(2) (a 2 element array to hold the real and
-f imaginary parts of the complex value).
-f - CI - INTEGER(2) (a 2 element array to hold the real and imaginary
-f parts of the complex value).
-f - F - DOUBLE PRECISION.
-f - I - INTEGER
-f - L - LOGICAL
-f - S - CHARACTER
-f - CN - CHARACTER
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c name
-f NAME = CHARACTER * ( * ) (Given)
-c Pointer to a null-terminated character string
-f A character string
-* containing the FITS keyword name. This may be a complete FITS
-* header card, in which case the keyword to use is extracted from
-* it. No more than 80 characters are read from this string. If
-c NULL
-f a single dot '.'
-* is supplied, the value of the current card is returned.
-c value
-f VALUE = <X>type (Returned)
-c A pointer to a
-f A
-* buffer to receive the keyword value. The data type depends on <X>
-* as described above. The conents of the buffer on entry are left
-* unchanged if the keyword is not found.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astGetFits<X><X>()
-f AST_GETFITS<X> = LOGICAL
-c A value of zero
-f .FALSE.
-* is returned if the keyword was not found in the FitsChan (no error
-* is reported). Otherwise, a value of
-c one
-f .TRUE.
-* is returned.
-
-* Notes:
-* - If a name is supplied, the card following the current card is
-* checked first. If this is not the required card, then the rest of the
-* FitsChan is searched, starting with the first card added to the
-* FitsChan. Therefore cards should be accessed in the order they are
-* stored in the FitsChan (if possible) as this will minimise the time
-* spent searching for cards.
-* - If the requested card is found, it becomes the current card,
-* otherwise the current card is left pointing at the "end-of-file".
-* - If the stored keyword value is not of the requested type, it is
-* converted into the requested type.
-* - If the keyword is found in the FitsChan, but has no associated
-* value, an error is reported. If necessary, the
-c astTestFits
-f AST_TESTFITS
-* function can be used to determine if the keyword has a defined
-* value in the FitsChan prior to calling this function.
-* - An error will be reported if the keyword name does not conform
-* to FITS requirements.
-c - Zero
-* - .FALSE.
-* is returned as the function value if an error has already occurred,
-* or if this function should fail for any reason.
-* - The FITS standard says that string keyword values should be
-* padded with trailing spaces if they are shorter than 8 characters.
-* For this reason, trailing spaces are removed from the string
-* returned by
-c astGetFitsS
-f AST_GETFITSS
-* if the original string (including any trailing spaces) contains 8
-* or fewer characters. Trailing spaces are not removed from longer
-* strings.
-*--
-*/
-
-/* Define a macro which expands to the implementation of the astGetFits<X>
- routine for a given data type. */
-#define MAKE_FGET(code,ctype,ftype) \
-static int GetFits##code( AstFitsChan *this, const char *name, ctype value, int *status ){ \
-\
-/* Local Variables: */ \
- const char *class; /* Object class */ \
- const char *method; /* Calling method */ \
- char *lcom; /* Supplied keyword comment */ \
- char *lname; /* Supplied keyword name */ \
- char *lvalue; /* Supplied keyword value */ \
- char *string; /* Pointer to returned string value */ \
- char *c; /* Pointer to next character */ \
- int cl; /* Length of string value */ \
- int ret; /* The returned value */ \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return 0; \
-\
-/* Ensure the source function has been called */ \
- ReadFromSource( this, status ); \
-\
-/* Store the calling method and object class. */ \
- method = "astGetFits"#code; \
- class = astGetClass( this ); \
-\
-/* Initialise the returned value. */ \
- ret = 0; \
-\
-/* Extract the keyword name from the supplied string. */ \
- if( name ) { \
- (void) Split( this, name, &lname, &lvalue, &lcom, method, class, status ); \
- } else { \
- lname = NULL; \
- lvalue = NULL; \
- lcom = NULL; \
- } \
-\
-/* Attempt to find a card in the FitsChan refering to this keyword, \
- and make it the current card. Only proceed if a card was found. No \
- need to do the search if the value of the current card is required. */ \
- if( !lname || SearchCard( this, lname, method, class, status ) ){ \
-\
-/* Convert the stored data value to the requested type, and store it in \
- the supplied buffer. */ \
- if( !CnvValue( this, ftype, 0, value, method, status ) && astOK ) { \
- astError( AST__FTCNV, "%s(%s): Cannot convert FITS keyword " \
- "'%s' to %s.", status, method, class, \
- CardName( this, status ), type_names[ ftype ] ); \
- } \
-\
-/* If the returned value is a string containing 8 or fewer characters, \
- replace trailing spaces with null characters. */ \
- if( astOK ) { \
- if( ftype == AST__STRING ) { \
- string = *( (char **) value ); \
- if( string ) { \
- cl =strlen( string ); \
- if( cl <= 8 ) { \
- c = string + cl - 1; \
- while( *c == ' ' && c > string ) { \
- *c = 0; \
- c--; \
- } \
- } \
- } \
- } \
-\
-/* Indicate that a value is available. */ \
- ret = 1; \
- } \
-\
- } \
-\
-/* Context error message. */ \
- if( !astOK && lname && *lname ) { \
- astError( astStatus, "%s(%s): Cannot get value for FITS keyword " \
- "'%s'.", status, method, class, lname ); \
- } \
-\
-/* Release the memory used to hold keyword name, value and comment strings. */ \
- lname = (char *) astFree( (void *) lname ); \
- lvalue = (char *) astFree( (void *) lvalue ); \
- lcom = (char *) astFree( (void *) lcom ); \
-\
-/* Return the answer. */ \
- return ret; \
-\
-}
-
-/* Use the above macro to give defintions for the astGetFits<X> method
- for each FITS data type. */
-MAKE_FGET(CF,double *,AST__COMPLEXF)
-MAKE_FGET(CI,int *,AST__COMPLEXI)
-MAKE_FGET(F,double *,AST__FLOAT)
-MAKE_FGET(I,int *,AST__INT)
-MAKE_FGET(L,int *,AST__LOGICAL)
-MAKE_FGET(S,char **,AST__STRING)
-MAKE_FGET(CN,char **,AST__CONTINUE)
-#undef MAKE_FGET
-
-static int FitsGetCom( AstFitsChan *this, const char *name,
- char **comment, int *status ){
-
-/*
-*+
-* Name:
-* astFitsGetCom
-
-* Purpose:
-* Get a keyword comment from a FitsChan.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int astFitsGetCom( AstFitsChan *this, const char *name,
-* char **comment )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function gets the comment associated with the next occurrence of
-* a named keyword in a FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* A pointer to a
-* string holding the keyword name. This may be a complete FITS
-* header card, in which case the keyword to use is extracted from
-* it. No more than 80 characters are read from this string.
-* comment
-* A pointer to a location at which to return a pointer to a string
-* holding the keyword comment. Note, the stored string will change on
-* subsequent invocations of astFitsGetCom so a permanent copy
-* should be taken of the string if necessary.
-
-* Returned Value:
-* astFitsGetCom()
-* A value of zero is returned if the keyword was not found before
-* the end of the FitsChan was reached (no error is reported).
-* Otherwise, a value of one is returned.
-
-* Notes:
-* - If a NULL pointer is supplied for "name" then the comment from
-* the current card is returned.
-* - The returned value is obtained from the next card refering to
-* the required keyword, starting the search with the current card.
-* Any cards occuring before the current card are not seached. If
-* the entire contents of the FitsChan must be searched, then ensure
-* the current card is the first card in the FitsChan by clearing the Card
-* attribute. This effectively "rewinds" the FitsChan.
-* - The current card is updated to become the card following the one
-* read by this function. If the card read by this function is the
-* last one in the FitsChan, then the current card is left pointing at the
-* "end-of-file".
-* - An error will be reported if the keyword name does not conform
-* to FITS requirements.
-* - A NULL pointer is returned for the comment string if the keyword
-* has no comment.
-* - Zero is returned as the function value if an error has already
-* occurred, or if this function should fail for any reason.
-*-
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- const char *method; /* Calling method */
- const char *class; /* Object class */
- char *lcom; /* Supplied keyword comment */
- char *lname; /* Supplied keyword name */
- char *lvalue; /* Supplied keyword value */
- int ret; /* The returned value */
-
-/* Check the global error status. */
- if ( !astOK ) return 0;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Initialise the returned value. */
- ret = 0;
-
-/* Store the method name and object class. */
- method = "astFitsGetCom";
- class = astGetClass( this );
-
-/* Extract the keyword name from the supplied string (if supplied). */
- if( name ){
- (void) Split( this, name, &lname, &lvalue, &lcom, method, class, status );
- } else {
- lname = NULL;
- lcom = NULL;
- lvalue = NULL;
- }
-
-/* Find the next card in the FitsChan refering to this keyword. This will
- be the current card if no keyword name was supplied. The matching card
- is made the current card. Only proceed if a card was found. */
- if( FindKeyCard( this, lname, method, class, status ) ){
-
-/* Copy the comment into a static buffer, and return a pointer to it. */
- if( CardComm( this, status ) ){
- (void) strncpy( fitsgetcom_sval, CardComm( this, status ), AST__FITSCHAN_FITSCARDLEN );
- fitsgetcom_sval[ AST__FITSCHAN_FITSCARDLEN ] = 0;
- if( comment ) *comment = fitsgetcom_sval;
- } else {
- if( comment ) *comment = NULL;
- }
-
-/* Move on to the next card. */
- MoveCard( this, 1, method, class, status );
-
-/* Indicate that a value is available. */
- if( astOK ) ret = 1;
- }
-
-/* Release the memory used to hold keyword name, value and comment strings. */
- lname = (char *) astFree( (void *) lname );
- lvalue = (char *) astFree( (void *) lvalue );
- lcom = (char *) astFree( (void *) lcom );
-
-/* Return the answer. */
- return ret;
-}
-
-static int SetFits( AstFitsChan *this, const char *keyname, void *value,
- int type, const char *comment, int overwrite, int *status ){
-
-/*
-* Name:
-* SetFits
-
-* Purpose:
-* Store a keyword value of any type in a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int SetFits( AstFitsChan *this, const char *keyname, void *value,
-* int type, const char *comment, int overwrite, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function stores the supplied value for the supplied keyword
-* in the supplied FitsChan, assuming it is of the supplied data type.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* A pointer to a string holding the keyword name.
-* value
-* A pointer to a buffer holding the keyword value. For strings,
-* the buffer should hold the address of a pointer to the character
-* string.
-* type
-* The keyword type.
-* comment
-* A pointer to a string holding a comment to associated with the
-* keyword. If a NULL pointer or a blank string is supplied, then
-* any comment included in the string supplied for the "name" parameter
-* is used instead. If "name" contains no comment, then any existing
-* comment in the card being over-written is retained, or a NULL
-* pointer is stored if a new card is being inserted. If the data
-* value being stored for the card is the same as the card being
-* over-written, then any existing comment is retained.
-* overwrite
-* If non-zero, the new card formed from the supplied keyword name,
-* value and comment string over-writes the current card, and the
-* current card is incremented to refer to the next card. If zero, the
-* new card is inserted in front of the current card and the current
-* card is left unchanged. In either case, if the current card on
-* entry points to the "end-of-file", the new card is appended to the
-* end of the list.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A value of 0 is returned if the value could not be stored for any
-* reason. A value of 1 is returned otherwise.
-
-* Notes:
-* - Nothing is stored in the FitsChan and a value of zero is returned
-* (but no error is reported) if an AST__FLOAT value is supplied equal
-* to AST__BAD.
-*/
-
-/* Local Variables: */
- const char *cval;
- const char *ecval;
- double dval;
- double ecdval[ 2 ];
- double edval;
- int ecival[ 2 ];
- int eival;
- int ival;
- int ret;
-
-/* Check the global status, and the supplied pointer. */
- if( !astOK || !value ) return 0;
-
-/* Initialise the returned value to indicate that the supplied name was
- stored. */
- ret = 1;
-
-/* Check each data type in turn. */
- if( type == AST__FLOAT ){
- dval = *( (double *) value );
- if( dval != AST__BAD ) {
-
-/* If the data value has not changed, and the card has a coment,
- set the comment pointer NULL so that the existing comment will be
- retained. */
- if( overwrite && CnvValue( this, type, 0, &edval, "SetFits",
- status ) &&
- CardComm( this, status ) ) {
- if( astEQUAL( edval, dval ) ) comment = NULL;
- }
- astSetFitsF( this, keyname, dval, comment, overwrite );
- } else {
- ret = 0;
- }
- } else if( type == AST__STRING ){
- cval = *( (char **) value);
- if( cval ){
-
-/* If the data value has not changed, retain the original comment. */
- if( overwrite && CnvValue( this, type, 0, &ecval, "SetFits",
- status ) &&
- CardComm( this, status ) ) {
- if( Similar( ecval, cval, status ) ) comment = NULL;
- }
-
-/* Ignore comments if they are identical to the keyword value. */
- if( comment && !strcmp( cval, comment ) ) comment = NULL;
- astSetFitsS( this, keyname, cval, comment, overwrite );
- } else {
- ret = 0;
- }
- } else if( type == AST__CONTINUE ){
- cval = *( (char **) value);
- if( cval ){
- astSetFitsCN( this, keyname, cval, comment, overwrite );
- } else {
- ret = 0;
- }
- } else if( type == AST__COMMENT ){
- astSetFitsCom( this, keyname, comment, overwrite );
- } else if( type == AST__INT ){
- ival = *( (int *) value );
-
-/* If the data value has not changed, retain the original comment. */
- if( overwrite && CnvValue( this, type, 0, &eival, "SetFits",
- status ) &&
- CardComm( this, status ) ) {
- if( eival == ival ) comment = NULL;
- }
- astSetFitsI( this, keyname, ival, comment, overwrite );
- } else if( type == AST__COMPLEXF ){
- if( ( (double *) value )[0] != AST__BAD &&
- ( (double *) value )[1] != AST__BAD ) {
-
-/* If the data value has not changed, retain the original comment. */
- if( overwrite && CnvValue( this, type, 0, ecdval, "SetFits",
- status ) &&
- CardComm( this, status ) ) {
- if( astEQUAL( ecdval[ 0 ], ( (double *) value )[ 0 ] ) &&
- astEQUAL( ecdval[ 1 ], ( (double *) value )[ 1 ] ) ) comment = NULL;
- }
- astSetFitsCF( this, keyname, (double *) value, comment, overwrite );
- } else {
- ret = 0;
- }
- } else if( type == AST__COMPLEXI ){
-
-/* If the data value has not changed, retain the original comment. */
- if( overwrite && CnvValue( this, type, 0, ecival, "SetFits",
- status ) &&
- CardComm( this, status ) ) {
- if( ecival[ 0 ] == ( (int *) value )[ 0 ] &&
- ecival[ 1 ] == ( (int *) value )[ 1 ] ) comment = NULL;
- }
- astSetFitsCI( this, keyname, (int *) value, comment, overwrite );
- } else if( type == AST__LOGICAL ){
- ival = ( *( (int *) value ) != 0 );
-
-/* If the data value has not changed, retain the original comment. */
- if( overwrite && CnvValue( this, type, 0, &eival, "SetFits",
- status ) &&
- CardComm( this, status ) ) {
- if( eival == ival ) comment = NULL;
- }
- astSetFitsL( this, keyname, ival, comment, overwrite );
- } else if( type == AST__UNDEF ){
- if( overwrite && CardType( this, status ) == AST__UNDEF && CardComm( this, status ) ) {
- comment = NULL;
- }
- astSetFitsU( this, keyname, comment, overwrite );
- }
- return ret;
-}
-
-/*
-*++
-* Name:
-c astSetFits<X>
-f AST_SETFITS<X>
-
-* Purpose:
-* Store a keyword value in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c void astSetFits<X>( AstFitsChan *this, const char *name, <X>type value,
-c const char *comment, int overwrite )
-f CALL AST_SETFITS<X>( THIS, NAME, VALUE, COMMENT, OVERWRITE, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This is a family of functions which store values for named keywords
-f This is a family of routines which store values for named keywords
-* within a FitsChan at the current card position. The supplied keyword
-* value can either over-write an existing keyword value, or can be
-* inserted as a new header card into the FitsChan.
-*
-c The keyword data type is selected by replacing <X> in the function name
-f The keyword data type is selected by replacing <X> in the routine name
-* by one of the following strings representing the recognised FITS data
-
-* types:
-*
-* - CF - Complex floating point values.
-* - CI - Complex integer values.
-* - F - Floating point values.
-* - I - Integer values.
-* - L - Logical (i.e. boolean) values.
-* - S - String values.
-* - CN - A "CONTINUE" value, these are treated like string values, but
-* are encoded without an equals sign.
-*
-
-* The data type of the "value" parameter depends on <X> as follows:
-*
-c - CF - "double *" (a pointer to a 2 element array holding the real and
-c imaginary parts of the complex value).
-c - CI - "int *" (a pointer to a 2 element array holding the real and
-c imaginary parts of the complex value).
-c - F - "double".
-c - I - "int".
-c - L - "int".
-c - S - "const char *".
-c - CN - "const char *".
-*
-f - CF - DOUBLE PRECISION(2) (a 2 element array holding the real and
-f imaginary parts of the complex value).
-f - CI - INTEGER(2) (a 2 element array holding the real and imaginary
-f parts of the complex value).
-f - F - DOUBLE PRECISION.
-f - I - INTEGER
-f - L - LOGICAL
-f - S - CHARACTER
-f - CN - CHARACTER
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c name
-f NAME = CHARACTER * ( * ) (Given)
-c Pointer to a null-terminated character string
-f A character string
-* containing the FITS keyword name. This may be a complete FITS
-* header card, in which case the keyword to use is extracted from
-* it. No more than 80 characters are read from this string.
-c value
-f VALUE = <X>type (Given)
-* The keyword value to store with the named keyword. The data type
-* of this parameter depends on <X> as described above.
-c comment
-f COMMENT = CHARACTER * ( * ) (Given)
-c A pointer to a null terminated string
-f A string
-* holding a comment to associated with the keyword.
-c If a NULL pointer or
-f If
-* a blank string is supplied, then any comment included in the string
-* supplied for the
-c "name" parameter is used instead. If "name"
-f NAME parameter is used instead. If NAME
-* contains no comment, then any existing comment in the card being
-* over-written is retained. Otherwise, no comment is stored with
-* the card.
-c overwrite
-f OVERWRITE = LOGICAL (Given)
-c If non-zero,
-f If .TRUE.,
-* the new card formed from the supplied keyword name, value and comment
-* string over-writes the current card, and the current card is
-* incremented to refer to the next card (see the "Card" attribute). If
-c zero,
-f .FALSE.,
-* the new card is inserted in front of the current card and the current
-* card is left unchanged. In either case, if the current card on entry
-* points to the "end-of-file", the new card is appended to the end of
-* the list.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - The
-c function astSetFitsU
-f routine AST_SETFITSU
-* can be used to indicate that no value is associated with a keyword.
-* - The
-c function astSetFitsCM
-f routine AST_SETFITSCM
-* can be used to store a pure comment card (i.e. a card with a blank
-* keyword).
-* - To assign a new value for an existing keyword within a FitsChan,
-c first find the card describing the keyword using astFindFits, and
-c then use one of the astSetFits<X> family to over-write the old value.
-f first find the card describing the keyword using AST_FINDFITS, and
-f then use one of the AST_SETFITS<X> family to over-write the old value.
-* - If, on exit, there are no cards following the card written by
-c this function, then the current card is left pointing at the
-f this routine, then the current card is left pointing at the
-* "end-of-file".
-* - An error will be reported if the keyword name does not conform
-* to FITS requirements.
-*--
-*/
-
-/* Define a macro which expands to the implementation of the astSetFits<X>
- routine for a given data type. */
-#define MAKE_FSET(code,ctype,ftype,valexp) \
-static void SetFits##code( AstFitsChan *this, const char *name, ctype value, const char *comment, int overwrite, int *status ) { \
-\
-/* Local variables: */ \
- const char *class; /* Object class */ \
- const char *method; /* Calling method */ \
- const char *com; /* Comment to use */ \
- char *lcom; /* Supplied keyword comment */ \
- char *lname; /* Supplied keyword name */ \
- char *lvalue; /* Supplied keyword value */ \
- int free_com; /* Should com be freed before returned? */ \
-\
-/* Check the global error status. */ \
- if ( !astOK ) return; \
-\
-/* Ensure the source function has been called */ \
- ReadFromSource( this, status ); \
-\
-/* Store the object clas and calling method. */ \
- class = astGetClass( this ); \
- method = "astSetFits"#code; \
-\
-/* Extract the keyword name from the supplied string. */ \
- (void) Split( this, name, &lname, &lvalue, &lcom, method, class, status ); \
-\
-/* Initialise a pointer to the comment to be stored. If the supplied \
- comment is blank, use the comment given with "name". */ \
- com = ChrLen( comment, status ) ? comment : lcom; \
-\
-/* If the comment is still blank, use the existing comment if we are \
- over-writing, or a NULL pointer otherwise. */ \
- free_com = 0; \
- if( !ChrLen( com, status ) ) { \
- com = NULL; \
- if( overwrite ) { \
- if( CardComm( this, status ) ){ \
- com = (const char *) astStore( NULL, (void *) CardComm( this, status ), \
- strlen( CardComm( this, status ) ) + 1 ); \
- free_com = 1; \
- } \
- } \
- } \
-\
-/* Insert the new card. */ \
- InsCard( this, overwrite, lname, ftype, valexp, com, method, class, status ); \
-\
-/* Release the memory used to hold keyword name, value and comment strings. */ \
- lname = (char *) astFree( (void *) lname ); \
- lvalue = (char *) astFree( (void *) lvalue ); \
- lcom = (char *) astFree( (void *) lcom ); \
-\
-/* Release the memory holding the stored comment string, so long as it was \
- allocated within this function. */ \
- if( free_com ) com = (const char *) astFree( (void *) com ); \
-\
-}
-
-/* Use the above macro to give defintions for the astSetFits<X> method
- for each FITS data type. */
-MAKE_FSET(I,int,AST__INT,(void *)&value)
-MAKE_FSET(F,double,AST__FLOAT,(void *)&value)
-MAKE_FSET(S,const char *,AST__STRING,(void *)value)
-MAKE_FSET(CN,const char *,AST__CONTINUE,(void *)value)
-MAKE_FSET(CF,double *,AST__COMPLEXF,(void *)value)
-MAKE_FSET(CI,int *,AST__COMPLEXI,(void *)value)
-MAKE_FSET(L,int,AST__LOGICAL,(void *)&value)
-#undef MAKE_FSET
-
-static void SetFitsU( AstFitsChan *this, const char *name, const char *comment,
- int overwrite, int *status ) {
-
-/*
-*++
-* Name:
-c astSetFitsU
-f AST_SETFITSU
-
-* Purpose:
-* Store an undefined keyword value in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c void astSetFitsU( AstFitsChan *this, const char *name,
-c const char *comment, int overwrite )
-f CALL AST_SETFITSU( THIS, NAME, COMMENT, OVERWRITE, STATUS )
-
-* Description:
-* This
-c function
-f routine
-* stores an undefined value for a named keyword within
-* a FitsChan at the current card position. The new undefined value
-* can either over-write an existing keyword value, or can be inserted
-* as a new header card into the FitsChan.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c name
-f NAME = CHARACTER * ( * ) (Given)
-c Pointer to a null-terminated character string
-f A character string
-* containing the FITS keyword name. This may be a complete FITS
-* header card, in which case the keyword to use is extracted from
-* it. No more than 80 characters are read from this string.
-c comment
-f COMMENT = CHARACTER * ( * ) (Given)
-c A pointer to a null terminated string
-f A string
-* holding a comment to associated with the keyword.
-c If a NULL pointer or
-f If
-* a blank string is supplied, then any comment included in the string
-* supplied for the
-c "name" parameter is used instead. If "name"
-f NAME parameter is used instead. If NAME
-* contains no comment, then any existing comment in the card being
-* over-written is retained. Otherwise, no comment is stored with
-* the card.
-c overwrite
-f OVERWRITE = LOGICAL (Given)
-c If non-zero,
-f If .TRUE.,
-* the new card formed from the supplied keyword name and comment
-* string over-writes the current card, and the current card is
-* incremented to refer to the next card (see the "Card" attribute). If
-c zero,
-f .FALSE.,
-* the new card is inserted in front of the current card and the current
-* card is left unchanged. In either case, if the current card on entry
-* points to the "end-of-file", the new card is appended to the end of
-* the list.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - If, on exit, there are no cards following the card written by
-* this function, then the current card is left pointing at the
-* "end-of-file".
-* - An error will be reported if the keyword name does not conform
-* to FITS requirements.
-*--
-*/
-
-/* Local variables: */
- const char *class; /* Object class */
- const char *method; /* Calling method */
- const char *com; /* Comment to use */
- char *lcom; /* Supplied keyword comment */
- char *lname; /* Supplied keyword name */
- char *lvalue; /* Supplied keyword value */
- int free_com; /* Should com be freed before returned? */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Store the object clas and calling method. */
- class = astGetClass( this );
- method = "astSetFitsU";
-
-/* Extract the keyword name from the supplied string. */
- (void) Split( this, name, &lname, &lvalue, &lcom, method, class, status );
-
-/* Initialise a pointer to the comment to be stored. If the supplied
- comment is blank, use the comment given with "name". */
- com = ChrLen( comment, status ) ? comment : lcom;
-
-/* If the comment is still blank, use the existing comment if we are
- over-writing, or a NULL pointer otherwise. */
- free_com = 0;
- if( !ChrLen( com, status ) ) {
- com = NULL;
- if( overwrite ) {
- if( CardComm( this, status ) ){
- com = (const char *) astStore( NULL, (void *) CardComm( this, status ),
- strlen( CardComm( this, status ) ) + 1 );
- free_com = 1;
- }
- }
- }
-
-/* Insert the new card. */
- InsCard( this, overwrite, lname, AST__UNDEF, NULL, com, method, class,
- status );
-
-/* Release the memory used to hold keyword name, value and comment strings. */
- lname = (char *) astFree( (void *) lname );
- lvalue = (char *) astFree( (void *) lvalue );
- lcom = (char *) astFree( (void *) lcom );
-
-/* Release the memory holding the stored comment string, so long as it was
- allocated within this function. */
- if( free_com ) com = (const char *) astFree( (void *) com );
-}
-
-static void SetFitsCM( AstFitsChan *this, const char *comment,
- int overwrite, int *status ) {
-
-/*
-*++
-* Name:
-c astSetFitsCM
-f AST_SETFITSCM
-
-* Purpose:
-* Store a comment card in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c void astSetFitsCM( AstFitsChan *this, const char *comment,
-c int overwrite )
-f CALL AST_SETFITSCM( THIS, COMMENT, OVERWRITE, STATUS )
-
-* Description:
-* This
-c function
-f routine
-* stores a comment card ( i.e. a card with no keyword name or equals
-* sign) within a FitsChan at the current card position. The new card
-* can either over-write an existing card, or can be inserted as a new
-* card into the FitsChan.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c comment
-f COMMENT = CHARACTER * ( * ) (Given)
-c A pointer to a null terminated string
-f A string
-* holding the text of the comment card.
-c If a NULL pointer or
-f If
-* a blank string is supplied, then a totally blank card is produced.
-c overwrite
-f OVERWRITE = LOGICAL (Given)
-c If non-zero,
-f If .TRUE.,
-* the new card over-writes the current card, and the current card is
-* incremented to refer to the next card (see the "Card" attribute). If
-c zero,
-f .FALSE.,
-* the new card is inserted in front of the current card and the current
-* card is left unchanged. In either case, if the current card on entry
-* points to the "end-of-file", the new card is appended to the end of
-* the list.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - If, on exit, there are no cards following the card written by
-* this function, then the current card is left pointing at the
-* "end-of-file".
-*--
-*/
-
-/* Just call astSetFitsCom with a blank keyword name. */
- astSetFitsCom( this, "", comment, overwrite );
-}
-
-static void SetFitsCom( AstFitsChan *this, const char *name,
- const char *comment, int overwrite, int *status ){
-
-/*
-*+
-* Name:
-* astSetFitsCom
-
-* Purpose:
-* Store a comment for a keyword in a FitsChan.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void astSetFitsCom( AstFitsChan *this, const char *name,
-* const char *comment, int overwrite )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function replaces the comment within an existing card, or
-* stores a new comment card within a FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* A pointer to a
-* string holding the keyword name. This may be a complete FITS
-* header card, in which case the keyword to use is extracted from
-* it. No more than 80 characters are read from this string.
-* comment
-* A pointer to a
-* string holding a comment to associated with the keyword.
-* If a NULL or
-* blank string is supplied, any existing comment associated with
-* the keyword is removed.
-* overwrite
-* If non-zero, the new comment replaces the comment in the current
-* card, and the current card is then incremented to refer to the next
-* card. If zero, a new comment card is inserted in front of the current
-* card and the current card is left unchanged. In either case, if the
-* current card on entry points to the "end-of-file", the new card is
-* appended to the end of the list.
-
-* Notes:
-* - When replacing an existing comment, any existing keyword value is
-* retained only if the supplied keyword name is the same as the keyword
-* name in the current card. If the keyword names are different, then
-* the new name replaces the old name, and any existing keyword data value
-* is deleted. The card thus becomes a comment card with the supplied
-* keyword name and comment, but no data value.
-* - If, on exit, there are no cards following the card written by
-* this function, then the current card is left pointing at the
-* "end-of-file".
-* - The current card can be set explicitly before calling this function
-* either by assigning a value to the Card attribute (if the index of the
-* required card is already known), or using astFindFits (if only the
-* keyword name is known).
-* - An error will be reported if the keyword name does not conform
-* to FITS requirements.
-*-
-*/
-
-/* Local variables: */
- const char *class; /* Pointer to object class string */
- const char *method; /* Pointer to calling method string */
- const char *cname; /* The existing keyword name */
- const char *com; /* The comment to use */
- char *lcom; /* Supplied keyword comment */
- char *lname; /* Supplied keyword name */
- char *lvalue; /* Supplied keyword value */
- void *old_data; /* Pointer to the old data value */
- void *data; /* Pointer to data value to be stored */
- size_t size; /* The size of the data value */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Initialisation */
- size = 0;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Store the calling method and object class. */
- method = "astSetFitsCom";
- class = astGetClass( this );
-
-/* Extract the keyword name, etc, from the supplied string. */
- (void) Split( this, name, &lname, &lvalue, &lcom, method, class, status );
-
-/* If a blank comment has been supplied, use NULL instead. */
- com = ChrLen( comment, status )? comment : NULL;
-
-/* If we are inserting a new card, or over-writing an old card with a
- different name, create and store a comment card with the given keyword
- name and comment, but no data value. */
- cname = CardName( this, status );
- if( !overwrite || !cname || strcmp( lname, cname ) ){
- InsCard( this, overwrite, lname, AST__COMMENT, NULL, com, method, class, status );
-
-/* If we are overwriting an existing keyword comment, use the data type
- and value from the existing current card. Note, we have to take a copy
- of the old data value because InsCard over-writes by deleting the old
- card and then inserting a new one. */
- } else {
- old_data = CardData( this, &size, status );
- data = astStore( NULL, old_data, size );
- InsCard( this, 1, lname, CardType( this, status ), data, com, method, class, status );
- data = astFree( data );
- }
-
-/* Release the memory used to hold keyword name, value and comment strings. */
- lname = (char *) astFree( (void *) lname );
- lvalue = (char *) astFree( (void *) lvalue );
- lcom = (char *) astFree( (void *) lcom );
-}
-
-static void FixNew( AstFitsChan *this, int flag, int remove,
- const char *method, const char *class, int *status ){
-
-/*
-*
-* Name:
-* FixNew
-
-* Purpose:
-* Remove "new" flags from the whole FitsChan, and optionally remove
-* "new" cards.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void FixNew( AstFitsChan *this, int flag, int remove,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function searches the entire FitsChan for cards which are
-* marked as new using the supplied flag (NEW1 or NEW2). If "remove"
-* is non-zero, these cards are completely removed from the FitsChan
-* (not just marked as used). If "remove" is zero, they are retained
-* and the specified flag is cleared.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* flag
-* The flag to use; NEW1 or NEW2.
-* remove
-* Remove flagged cards from the FitsChan?
-* 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.
-
-* Notes:
-* - This function attempts to execute even if an error has occurred.
-* - If any cards are removed, the current Card is left at "end-of-file"
-* on exit. If no cards are removed, the original current card is
-* retained.
-*-
-*/
-
-/* Local Variables: */
- int *flags; /* Pointer to flags mask for the current card */
- int icard; /* Index of current card on entry */
- int ndeleted; /* Number of cards deleted by this call */
-
-/* Return if no FitsChan was supplied, or if the FitsChan is empty. */
- if ( !this || !this->head ) return;
-
-/* Save the current card index, and rewind the FitsChan. */
- icard = astGetCard( this );
- astClearCard( this );
-
-/* Indicate no cards have yet been deleted. */
- ndeleted = 0;
-
-/* Loop through the list of FitsCards in the FitsChan until the final
- card is reached. */
- while( astOK && this->card ){
-
-/* Get a pointer to the flags mask for this card. */
- flags = CardFlags( this, status );
-
-/* See if the Card has been marked with the requeste new flag. */
- if( flags && ( (*flags) & flag ) ) {
-
-/* If requested, remove the card. This will automatically move the
- current card on to the next card. */
- if( remove ){
- DeleteCard( this, method, class, status );
- ndeleted++;
-
-/* Otherwise, clear the flag. */
- } else {
- *flags = (*flags) & ~flag;
-
-/* Increment the card count and move on to the next card. */
- MoveCard( this, 1, method, class, status );
- }
-
-/* Move on to the next card if this card is not marked with the requested
- new flag. */
- } else {
- MoveCard( this, 1, method, class, status );
- }
- }
-
-/* If no cards were removed, we can safely re-instate the original
- current card. Otherwise, the current card is left at "end-of-file". */
- if( ndeleted == 0 ) astSetCard( this, icard );
-
-/* Return */
- return;
-}
-
-static void FixUsed( AstFitsChan *this, int reset, int used, int remove,
- const char *method, const char *class, int *status ){
-
-/*
-*
-* Name:
-* FixUsed
-
-* Purpose:
-* Remove "provisionally used" flags from the whole FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void FixUsed( AstFitsChan *this, int reset, int used, int remove,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function searches the entire FitsChan for cards which are
-* marked as "provisionally used". The "provisionally used" flag is
-* cleared for each such card. In addition, if "used" is non-zero then
-* each such card is flagged as having been "definitely used". If
-* "remove" is non-zero, then all "provisionally used" cards are deleted
-* from the FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* reset
-* Set all cards so that they are neither provisionally used or
-* definitely used. In this case neither the "used" nor the
-* "remove" parameter are accssed.
-* used
-* Have the provisionally used cards definitely been used?
-* remove
-* Should provisionally used cards be deleted?
-* 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.
-
-* Notes:
-* - This function attempts to execute even if an error has occurred.
-*-
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- FitsCard *card0; /* Pointer to current FitsCard */
- int *flags; /* Pointer to flags mask for the current card */
- int old_ignore_used; /* Original value of variable ignore_used */
- int old_status; /* Original inherited status value */
- int rep; /* Original error reporting flag */
-
-/* Return if no FitsChan was supplied, or if the FitsChan is empty. */
- if ( !this || !this->head ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Temporarily clear any bad status value and supress error reporting in
- this function. */
- old_status = astStatus;
- astClearStatus;
- rep = astReporting( 0 );
-
-/* Indicate that we should not skip over cards marked as having been
- read. */
- old_ignore_used = ignore_used;
- ignore_used = 0;
-
-/* Save a pointer to the current card, and the reset the current card to
- be the first card. */
- card0 = this->card;
- astClearCard( this );
-
-/* Loop through the list of FitsCards in the FitsChan until the final
- card is reached. */
- while( this->card ){
-
-/* Get a pointer to the flags mask for this card. */
- flags = CardFlags( this, status );
-
-/* Reset both used flags if required. */
- if( reset ) {
- *flags = (*flags) & ~PROVISIONALLY_USED;
- *flags = (*flags) & ~USED;
- MoveCard( this, 1, method, class, status );
-
-/* Otherwise perform the actions indicated by parameters "used" and
- "remove". */
- } else {
-
-/* See if the Card has been provisionally used. */
- if( flags && ( (*flags) & PROVISIONALLY_USED ) ) {
-
-/* Clear the provisionally used flag. */
- *flags = (*flags) & ~PROVISIONALLY_USED;
-
-/* If required, set the definitely used flag. */
- if( used ) *flags = (*flags) | USED;
-
-/* If required, delete the card. The next card is made current. If we are
- about to delete the original current card, we need to update the
- pointer to the card to be made current at the end of this function.
- If we end up back at the head of the chain, indicate that we have
- reached the end of file by setting card0 NULL. */
- if( remove ) {
- if( card0 == this->card && card0 ) {
- card0 = ( (FitsCard *) this->card )->next;
- if( (void *) card0 == this->head ) card0 = NULL;
- }
- DeleteCard( this, method, class, status );
-
-/* Otherwise, just move on to the next card. */
- } else {
- MoveCard( this, 1, method, class, status );
- }
-
-/* If this card has not bee provisionally used, move on to the next card. */
- } else {
- MoveCard( this, 1, method, class, status );
- }
- }
- }
-
-/* Re-instate the original current card. */
- this->card = card0;
-
-/* If this card is now flagged as definitely used, move forward to the
- next un-used card. */
- flags = CardFlags( this, status );
- if( flags && (*flags & USED ) ) {
- ignore_used = 1;
- MoveCard( this, 1, method, class, status );
- }
-
-/* Re-instate the original flag indicating if cards marked as having been
- read should be skipped over. */
- ignore_used = old_ignore_used;
-
-/* Re-instate the original status value and error reporting condition. */
- astReporting( rep );
- astSetStatus( old_status );
-}
-
-static void FormatCard( AstFitsChan *this, char *buf, const char *method, int *status ){
-
-/*
-*
-* Name:
-* FormatCard
-
-* Purpose:
-* Formats the current card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void FormatCard( AstFitsChan *this, char *buf, const char *method, int *status )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function write the current card into the supplied character
-* buffer as a complete FITS header card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* buf
-* A character string into which the header card is written. This
-* should be at least 81 characters long. The returned string is
-* padded with spaces upto column 80. A terminating null character
-* is added.
-* method
-* Pointer to a string holding the name of the calling method.
-* This is only for use in constructing error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - An error is reported if the requested header card does not conform to
-* FITS standards.
-*
-*/
-
-/* Local Variables: */
- const char *com; /* Pointer to comment string to use */
- int comlen; /* Length of comment string */
- int comstart; /* Column in which to start comment */
- int i; /* Loop counter for characters */
- int len; /* Output string length */
- int digits; /* No. of digits to use when formatting floating point values */
- int type; /* Card data type */
-
-/* Check the global error status, and check the current card is defined. */
- if ( !astOK || astFitsEof( this ) ) return;
-
-/* Get a pointer to the comment to use and determine its length. */
- com = CardComm( this, status );
- comlen = ChrLen( com, status );
-
-/* Copy the keyword name to the start of the output buffer, and store
- its length. */
- len = (int) strlen( strcpy( buf, CardName( this, status ) ) );
-
-/* Pad the name with spaces up to column 8. */
- while ( len < FITSNAMLEN ) buf[ len++ ] = ' ';
-
-/* If the card contains a keyword value... */
- type = CardType( this, status );
- if( type != AST__COMMENT ){
-
-/* Get the number of digits to use when formatting floating point values. */
- digits = astGetFitsDigits( this );
-
-/* Put an equals sign in column 9 (or a space if the keyword is a CONTINUE
- card), followed by a space in column 10. */
- buf[ len++ ] = ( type == AST__CONTINUE ) ? ' ' : '=';
- buf[ len++ ] = ' ';
-
-/* Format and store the keyword value, starting at column 11 and update the
- output string length. */
- len += EncodeValue( this, buf + len, FITSNAMLEN + 3, digits,
- method, status );
-
-/* If there is a comment, determine which column it should start in so that
- it ends in column 80. */
- if( com ){
- comstart = AST__FITSCHAN_FITSCARDLEN - ( comlen - 2 ) + 1;
-
-/* Adjust the starting column to 32 if possible, avoiding over-writing
- the value, or running off the end of the card unless this is
- unavoidable. */
- if ( comstart > FITSCOMCOL ) comstart = FITSCOMCOL;
- if ( comstart < len + 2 ) comstart = len + 2;
-
-/* Pad the output buffer with spaces up to the start of the comment. */
- while ( len < comstart - 1 ) buf[ len++ ] = ' ';
-
-/* Then append "/ " to introduce the comment, truncating if the card
- length forces this. */
- for ( i = 0; ( i < 2 ) && ( len < AST__FITSCHAN_FITSCARDLEN ); i++ ) {
- buf[ len++ ] = "/ "[ i ];
- }
- }
- }
-
-/* Append any comment, truncating it if the card length forces
- this. */
- if ( com ) {
- for ( i = 0; com[ i ] && ( len < AST__FITSCHAN_FITSCARDLEN ); i++ ) {
- buf[ len++ ] = com[ i ];
- }
- }
-
-/* Pad with spaces up to the end of the card. */
- while ( len < AST__FITSCHAN_FITSCARDLEN ) buf[ len++ ] = ' ';
-
-/* Terminate it. */
- buf[ AST__FITSCHAN_FITSCARDLEN ] = 0;
-}
-
-static int FullForm( const char *list, const char *test, int abbrev, int *status ){
-/*
-* Name:
-* FullForm
-
-* Purpose:
-* Identify the full form of an option string.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int FullForm( const char *list, const char *test, int abbrev, int *status )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function identifies a supplied test option within a supplied
-* list of valid options, and returns the index of the option within
-* the list. The test option may be abbreviated, and case is
-* insignificant.
-
-* Parameters:
-* list
-* A list of space separated option strings.
-* test
-* A candidate option string.
-* abbrev
-* 1 if abbreviations are to be accepted. Zero otherwise.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The index of the identified option within the supplied list, starting
-* at zero. -1 is returned if the option is not recognised, and (if
-* abbrev is 1 ) -2 if the option is ambiguous (no errors are reported
-* in these cases). If abbrev is zero, the returned index will be the
-* index of the first matching string.
-*
-
-* Notes:
-* - A value of -1 is returned if an error has already occurred, or
-* if this function should fail for any reason.
-*/
-
-/* Local Variables: */
- char *context; /* Context used by strtok_r */
- char *llist; /* Pointer to a local copy of the options list */
- char *option; /* Pointer to the start of the next option */
- int i; /* Current option index */
- int len; /* Length of supplied option */
- int nmatch; /* Number of matching options */
- int ret; /* The returned index */
-
-/* Initialise the answer to indicate that the option has not been
- identified. */
- ret = -1;
-
-/* Avoid compiler warnings. */
- context = NULL;
-
-/* Check global status. */
- if( !astOK ) return ret;
-
-/* Take a local copy of the supplied options list. This is necessary since
- "strtok" modified the string by inserting null characters. */
- llist = (char *) astStore( NULL, (void *) list, strlen(list) + 1 );
- if( astOK ){
-
-/* Save the number of characters in the supplied test option (excluding
- trailing spaces). */
- len = ChrLen( test, status );
-
-/* Compare the supplied test option against each of the known options in
- turn. Count the number of matches. */
- nmatch = 0;
-#if HAVE_STRTOK_R
- option = strtok_r( llist, " ", &context );
-#else
- option = strtok( llist, " " );
-#endif
- i = 0;
- while( option ){
-
-/* If every character in the supplied label matches the corresponding
- character in the current test label we have a match. Increment the
- number of matches and save the current item index. If abbreviation is
- not allowed ensure that the lengths of the strings are equal. */
- if( !Ustrncmp( test, option, len, status ) && ( abbrev ||
- len == ChrLen( option, status ) ) ) {
- nmatch++;
- ret = i;
- if( !abbrev ) break;
- }
-
-/* Get a pointer to the next option. */
-#if HAVE_STRTOK_R
- option = strtok_r( NULL, " ", &context );
-#else
- option = strtok( NULL, " " );
-#endif
- i++;
- }
-
-/* Return -1 if no match was found. */
- if( !nmatch ){
- ret = -1;
-
-/* Return -2 if the option was ambiguous. */
- } else if( abbrev && nmatch > 1 ){
- ret = -2;
- }
-
-/* Free the local copy of the options list. */
- llist = (char *) astFree( (void *) llist );
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static const char *GetAllWarnings( AstFitsChan *this, int *status ){
-
-/*
-*+
-* Name:
-* astGetAllWarnings
-
-* Purpose:
-* Return a list of all condition names.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* const char *GetAllWarnings( AstFitsChan *this )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function returns a space separated lits of the condition names
-* currently recognized by the Warnings attribute.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* A pointer to a static string holding the condition names.
-
-* Notes:
-* - This routine does not check the inherited status.
-*-
-*/
-
-/* Return the result. */
- return ALLWARNINGS;
-}
-const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
-
-/*
-* Name:
-* GetAttrib
-
-* Purpose:
-* Get the value of a specified attribute for a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* const char *GetAttrib( AstObject *this, const char *attrib, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected astGetAttrib
-* method inherited from the Channel class).
-
-* Description:
-* This function returns a pointer to the value of a specified
-* attribute for a FitsChan, formatted as a character string.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* 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:
-* - The returned string pointer may point at memory allocated
-* within the FitsChan, 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 FitsChan. 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 */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- const char *result; /* Pointer value to return */
- int ival; /* Integer attribute value */
-
-/* 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 FitsChan structure. */
- this = (AstFitsChan *) this_object;
-
-/* Card. */
-/* ----- */
- if ( !strcmp( attrib, "card" ) ) {
- ival = astGetCard( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* CardComm. */
-/* --------- */
- } else if ( !strcmp( attrib, "cardcomm" ) ) {
- result = astGetCardComm( this );
-
-/* CardName. */
-/* --------- */
- } else if ( !strcmp( attrib, "cardname" ) ) {
- result = astGetCardName( this );
-
-/* CardType. */
-/* --------- */
- } else if ( !strcmp( attrib, "cardtype" ) ) {
- ival = astGetCardType( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* Encoding. */
-/* --------- */
- } else if ( !strcmp( attrib, "encoding" ) ) {
- ival = astGetEncoding( this );
- if ( astOK ) {
- if( ival == NATIVE_ENCODING ){
- result = NATIVE_STRING;
- } else if( ival == FITSPC_ENCODING ){
- result = FITSPC_STRING;
- } else if( ival == FITSIRAF_ENCODING ){
- result = FITSIRAF_STRING;
- } else if( ival == FITSAIPS_ENCODING ){
- result = FITSAIPS_STRING;
- } else if( ival == FITSAIPSPP_ENCODING ){
- result = FITSAIPSPP_STRING;
- } else if( ival == FITSCLASS_ENCODING ){
- result = FITSCLASS_STRING;
- } else if( ival == FITSWCS_ENCODING ){
- result = FITSWCS_STRING;
- } else if( ival == DSS_ENCODING ){
- result = DSS_STRING;
- } else {
- result = UNKNOWN_STRING;
- }
- }
-
-/* CDMatrix */
-/* -------- */
- } else if ( !strcmp( attrib, "cdmatrix" ) ) {
- ival = astGetCDMatrix( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* DefB1950 */
-/* -------- */
- } else if ( !strcmp( attrib, "defb1950" ) ) {
- ival = astGetDefB1950( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* TabOK */
-/* ----- */
- } else if ( !strcmp( attrib, "tabok" ) ) {
- ival = astGetTabOK( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* CarLin */
-/* ------ */
- } else if ( !strcmp( attrib, "carlin" ) ) {
- ival = astGetCarLin( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* PolyTan */
-/* ------- */
- } else if ( !strcmp( attrib, "polytan" ) ) {
- ival = astGetPolyTan( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* Iwc */
-/* --- */
- } else if ( !strcmp( attrib, "iwc" ) ) {
- ival = astGetIwc( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* Clean */
-/* ----- */
- } else if ( !strcmp( attrib, "clean" ) ) {
- ival = astGetClean( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* FitsAxisOrder. */
-/* -------------- */
- } else if ( !strcmp( attrib, "fitsaxisorder" ) ) {
- result = astGetFitsAxisOrder( this );
-
-/* FitsDigits. */
-/* ----------- */
- } else if ( !strcmp( attrib, "fitsdigits" ) ) {
- ival = astGetFitsDigits( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* Ncard. */
-/* ------ */
- } else if ( !strcmp( attrib, "ncard" ) ) {
- ival = astGetNcard( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* Nkey. */
-/* ----- */
- } else if ( !strcmp( attrib, "nkey" ) ) {
- ival = astGetNkey( this );
- if ( astOK ) {
- (void) sprintf( getattrib_buff, "%d", ival );
- result = getattrib_buff;
- }
-
-/* AllWarnings */
-/* ----------- */
- } else if ( !strcmp( attrib, "allwarnings" ) ) {
- result = astGetAllWarnings( this );
-
-/* Warnings. */
-/* -------- */
- } else if ( !strcmp( attrib, "warnings" ) ) {
- result = astGetWarnings( this );
-
-/* 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 int GetCard( AstFitsChan *this, int *status ){
-
-/*
-*+
-* Name:
-* astGetCard
-
-* Purpose:
-* Get the value of the Card attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int astGetCard( AstFitsChan *this )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function returns the value of the Card attribute for the supplied
-* FitsChan. This is the index of the next card to be read from the
-* FitsChan. The index of the first card is 1. If there are no more
-* cards to be read, a value one greater than the number of cards in the
-* FitsChan is returned.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* The index of the next card to be read.
-
-* Notes:
-* - A value of zero will be returned if the current card is not defined.
-* - This function attempts to execute even if an error has occurred.
-*-
-*/
-
-/* Local Variables: */
- const char *class; /* Pointer to class string */
- const char *method; /* Pointer to method string */
- FitsCard *card0; /* Pointer to current FitsCard */
- int index; /* Index of next FitsCard */
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Return if no FitsChan was supplied, or if the FitsChan is empty. */
- if ( !this || !this->head ) return 0;
-
-/* Store the method and object class. */
- method = "astGetCard";
- class = astGetClass( this );
-
-/* Save a pointer to the current card, and the reset the current card to
- be the first card. */
- card0 = this->card;
- astClearCard( this );
-
-/* Count through the list of FitsCards in the FitsChan until the original
- current card is reached. If the current card is not found (for instance
- if it has been marked as deleted and we are currently skipping such cards),
- this->card will be left null (end-of-file). */
- index = 1;
- while( this->card != card0 && astOK && this->card ){
-
-/* Increment the card count and move on to the next card. */
- index++;
- MoveCard( this, 1, method, class, status );
- }
-
-/* Return the card index. */
- return index;
-}
-
-static const char *GetCardComm( AstFitsChan *this, int *status ){
-/*
-*+
-* Name:
-* GetCardComm
-
-* Purpose:
-* Get the value of the CardComm attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* const char *astGetCardComm( AstFitsChan *this)
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function returns the value of the CardComm attribute for the
-* supplied FitsChan. This is the comment for the current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* A pointer to a static string holding the comment. A zero-length
-* string is returned if the card has no comment.
-
-* Notes:
-* - A value of NULL will be returned if an error has already
-* occurred, or if this function should fail for any reason.
-*-
-*/
-
-/* Local Variables */
- const char *result = NULL;
-
-/* Check inherited status */
- if( !astOK ) return result;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Get the comment for the current card. */
- result = CardComm( this, status );
-
-/* Return a zero-length string if the card has no comment. */
- if( astOK && !result ) result = "";
-
-/* Return the comment. */
- return result;
-}
-
-static const char *GetCardName( AstFitsChan *this, int *status ){
-/*
-*+
-* Name:
-* GetCardName
-
-* Purpose:
-* Get the value of the CardName attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* const char *astGetCardName( AstFitsChan *this)
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function returns the value of the CardName attribute for the
-* supplied FitsChan. This is the keyword name for the current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* A pointer to a static string holding the keyword name.
-
-* Notes:
-* - A value of NULL will be returned if an error has already
-* occurred, or if this function should fail for any reason.
-*-
-*/
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Return the keyword name of the current card. */
- return CardName( this, status );
-}
-
-static int GetCardType( AstFitsChan *this, int *status ){
-/*
-*+
-* Name:
-* GetCardType
-
-* Purpose:
-* Get the value of the CardType attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int astGetCardType( AstFitsChan *this )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function returns the value of teh CardType attribute for the supplied
-* FitsChan. This is the data type of the keyword value for the current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* An integer representing the data type of the current card.
-
-* Notes:
-* - A value of AST__NOTYPE will be returned if an error has already
-* occurred, or if this function should fail for any reason.
-*-
-*/
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Return the data type of the current card. */
- return CardType( this, status );
-}
-
-static int GetFull( AstChannel *this_channel, int *status ) {
-/*
-* Name:
-* GetFull
-
-* Purpose:
-* Obtain the value of the Full attribute for a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetFull( AstChannel *this, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected astGetFull
-* method inherited from the Channel class).
-
-* Description:
-* This function return the integer value of the Full attribute for
-* a FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The Full attribute value.
-
-* Notes:
-* - This function modifies the default Full value from 0 to -1 for
-* the benefit of the FitsChan class. This prevents non-essential
-* information being written by the astWrite method unless it is
-* requested by explicitlt setting a Full value.
-* - A value of zero will be returned if this function is invoked
-* with the global error status set, or if it should fail for any
-* reason.
-*/
-
-/* Local Variables: */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- int result; /* Result value to return */
-
-/* Check the global error status. */
- if ( !astOK ) return 0;
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* If the Full attribute us set, obtain its value using the parent class
- method. */
- if ( astTestFull( this ) ) {
- result = (* parent_getfull)( this_channel, status );
-
-/* Otherwise, supply a default value of -1. */
- } else {
- result = -1;
- }
-
-/* Return the result. */
- return result;
-}
-
-static FitsCard *GetLink( FitsCard *card, int next, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* GetLink
-
-* Purpose:
-* Get a pointer to the next or previous card in the list.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* FitsCard *GetLink( FitsCard *card, int next, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns the a pointer to either the next or previous FitsCard
-* structure in the circular linked list of such structures stored in a
-* FitsChan. A check is performed to ensure that the forward and
-* backward links from the supplied card are consistent and an error
-* is reported if they are not (so long as no previous error has been
-* reported). Memory corruption can result in inconsistent links
-* which can result in infinite loops if an attempt is made to scan the
-* list.
-
-* Parameters:
-* card
-* The current card.
-* next
-* If non-zero, a pointer to the "next" card is returned. Otherwise
-* a pointer to the "previous" card is returned.
-* method
-* Pointer to string holding the name of the calling method.
-* class
-* Pointer to string holding the object class.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the required card, or NULL if an error occurs.
-
-* Notes:
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- FitsCard *ret; /* Pointer to the returned card */
-
-/* Check that the "next" link from the previous card points back to
- the current card, and that the "prev" link from the next card points
- back to the current card. */
- if( card && ( card->prev->next != card ||
- card->next->prev != card ) ){
-
-/* Report an error so long as no previous error has been reported, and
- return a NULL pointer. */
- if( astOK ){
- astError( AST__FCRPT, "%s(%s): A corrupted %s object has been "
- "supplied.", status, method, class, class );
- }
- ret = NULL;
-
-/* If the links are good, return a pointer to the required card. */
- } else {
- ret = next ? card->next : card->prev;
- }
-
-/* Return the result. */
- return ret;
-}
-
-static int GetNcard( AstFitsChan *this, int *status ){
-
-/*
-*+
-* Name:
-* astGetNcard
-
-* Purpose:
-* Get the value of the Ncard attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int astGetNcard( AstFitsChan *this )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function returns the value of the Ncard attribute for the supplied
-* FitsChan. This is the number of cards currently in the FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* The number of cards currently in the FitsChan.
-
-* Notes:
-* - A value of zero will be returned if an error has already
-* occurred, or if this function should fail for any reason.
-*-
-*/
-
-/* Local Variables: */
- const char *class; /* Pointer to class string */
- const char *method; /* Pointer to method string */
- FitsCard *card0; /* Pointer to current card on entry */
- int ncard; /* Number of cards so far */
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Return zero if an error has already occurred, or no FitsChan was supplied,
- or the FitsChan is empty. */
- if ( !astOK || !this || !this->head ) return 0;
-
-/* Store the method and object class. */
- method = "astGetNcard";
- class = astGetClass( this );
-
-/* Save a pointer to the current card, and then reset the current card to
- be the first card. */
- card0 = this->card;
- astClearCard( this );
-
-/* Count through the cards in the FitsChan until the end of file is reached. */
- ncard = 0;
- while( astOK && this->card ){
-
-/* Increment the card count and move on to the next card. */
- ncard++;
- MoveCard( this, 1, method, class, status );
- }
-
-/* Reset the current card to be the original current card. */
- this->card = card0;
-
-/* Return the result. */
- return astOK ? ncard : 0;
-}
-
-static int GetNkey( AstFitsChan *this, int *status ){
-
-/*
-*+
-* Name:
-* astGetNkey
-
-* Purpose:
-* Get the value of the Nkey attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int astGetNkey( AstFitsChan *this )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function returns the value of the Nkey attribute for the supplied
-* FitsChan. This is the number of unique keywords currently in the
-* FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* The number of unique keywords currently in the FitsChan.
-
-* Notes:
-* - A value of zero will be returned if an error has already
-* occurred, or if this function should fail for any reason.
-*-
-*/
-
-/* Local Variables: */
- AstKeyMap *km; /* KeyMap holding unique keyword names */
- FitsCard *card0; /* Pointer to current card on entry */
- const char *class; /* Pointer to class string */
- const char *method; /* Pointer to method string */
- int nkey; /* Returned Nkey value */
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Return zero if an error has already occurred, or no FitsChan was supplied,
- or the FitsChan is empty. */
- if ( !astOK || !this || !this->head ) return 0;
-
-/* Store the method and object class. */
- method = "astGetNkey";
- class = astGetClass( this );
-
-/* Create an empty KeyMap to hold the unused keyword names */
- km = astKeyMap( " ", status );
-
-/* Save a pointer to the current card, and then reset the current card to
- be the first card. */
- card0 = this->card;
- astClearCard( this );
-
-/* Loop through the cards in the FitsChan until the end of file is reached. */
- while( astOK && this->card ){
-
-/* Get the keyword name for the current card and add it to the keymap. */
- astMapPut0I( km, CardName( this, status ), 0, NULL );
-
-/* Move on to the next unused card. */
- MoveCard( this, 1, method, class, status );
- }
-
-/* Reset the current card to be the original current card. */
- this->card = card0;
-
-/* Get the number of keywords. */
- nkey = astMapSize( km );
-
-/* Annull the KeyMap . */
- km = astAnnul( km );
-
-/* Return the result. */
- return astOK ? nkey : 0;
-}
-
-static void GetNextData( AstChannel *this_channel, int skip, char **name,
- char **val, int *status ) {
-/*
-* Name:
-* GetNextData
-
-* Purpose:
-* Read the next item of data from a data source.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void GetNextData( AstChannel *this, int skip, char **name, char **val )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected
-* astGetNextData method inherited from the Channel class).
-
-* Description:
-* This function reads the next item of input data from a data
-* source associated with a FitsChan and returns the result. It
-* decodes the data item and returns name/value pairs ready for
-* use.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* skip
-* A non-zero value indicates that a new Object is to be read,
-* and that all input data up to the next "Begin" item are to be
-* skipped in order to locate it. This is useful if the data
-* source contains AST objects interspersed with other data (but
-* note that these other data cannot appear inside AST Objects,
-* only between them).
-*
-* A zero value indicates that all input data are significant
-* and the next item will therefore be read and an attempt made
-* to interpret it whatever it contains. Any other data
-* inter-mixed with AST Objects will then result in an error.
-* name
-* An address at which to store a pointer to a null-terminated
-* dynamically allocated string containing the name of the next
-* item in the input data stream. This name will be in lower
-* case with no surrounding white space. It is the callers
-* responsibilty to free the memory holding this string (using
-* astFree) when it is no longer required.
-*
-* A NULL pointer value will be returned (without error) to
-* indicate when there are no further input data items to be
-* read.
-* val
-* An address at which to store a pointer to a null-terminated
-* dynamically allocated string containing the value associated
-* with the next item in the input data stream. No case
-* conversion is performed on this string and all white space is
-* potentially significant. It is the callers responsibilty to
-* free the memory holding this string (using astFree) when it
-* is no longer required.
-*
-* The returned pointer will be NULL if an Object data item is
-* read (see the "Data Representation" section).
-
-* Data Representation:
-
-* The returned data items fall into the following categories:
-*
-* - Begin: Identified by the name string "begin", this indicates
-* the start of an Object definition. The associated value string
-* gives the class name of the Object being defined.
-*
-* - IsA: Identified by the name string "isa", this indicates the
-* end of the data associated with a particular class structure
-* within the definiton of a larger Object. The associated value
-* string gives the name of the class whose data have just been
-* read.
-*
-* - End: Identified by the name string "end", this indicates the
-* end of the data associated with a complete Object
-* definition. The associated value string gives the class name of
-* the Object whose definition is being ended.
-*
-* - Non-Object: Identified by any other name string plus a
-* non-NULL "val" pointer, this gives the value of a non-Object
-* structure component (instance variable). The name identifies
-* which instance variable it is (within the context of the class
-* whose data are being read) and the value is encoded as a string.
-*
-* - Object: Identified by any other name string plus a NULL "val"
-* pointer, this identifies the value of an Object structure
-* component (instance variable). The name identifies which
-* instance variable it is (within the context of the class whose
-* data are being read) and the value is given by subsequent data
-* items (so the next item should be a "Begin" item).
-
-* Notes:
-* - NULL pointer values will be returned if this function is
-* invoked with the global error status set, or if it should fail
-* for any reason.
-*/
-
-/* Local Constants: */
-#define BUFF_LEN 100 /* Length of formatting buffer */
-
-/* Local Variables: */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- char *keyword; /* Pointer to current keyword string */
- char *newdata; /* Pointer to stripped string value */
- char *upq; /* Pointer to unprequoted string */
- char buff[ BUFF_LEN + 1 ]; /* Buffer for formatting values */
- const char *class; /* Pointer to object class */
- const char *method; /* Pointer to method name */
- int cont; /* String ends with an ampersand? */
- int done; /* Data item found? */
- int freedata; /* Should the data pointer be freed? */
- int i; /* Loop counter for keyword characters */
- int len; /* Length of current keyword */
- int nc; /* Number of characters read by "astSscanf" */
- int nn; /* No. of characters after UnPreQuoting */
- int type; /* Data type code */
- void *data; /* Pointer to current data value */
-
-/* Initialise the returned pointer values. */
- *name = NULL;
- *val = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Store the method name and object class. */
- method = "astRead";
- class = astGetClass( this );
-
-/* Loop to consider successive cards stored in the FitsChan (starting
- at the "current" card) until a valid data item is read or "end of
- file" is reached. Also quit the loop if an error occurs. */
- done = 0;
- newdata = NULL;
- while ( !done && !astFitsEof( this ) && astOK ){
-
-/* Obtain the keyword string, data type code and data value pointer
- from the current card. */
- keyword = CardName( this, status );
- type = CardType( this, status );
- data = CardData( this, NULL, status );
-
-/* Mark all cards as having been used unless we are skipping over cards which
- may not be related to AST. */
- if( !skip ) MarkCard( this, status );
-
-/* Ignore comment cards. */
- if ( type != AST__COMMENT ) {
-
-/* Native encoding requires trailing white space to be removed from
- string values (so that null strings can be distinguished from blank
- strings). Do this now. */
- freedata = 0;
- if ( ( type == AST__STRING || type == AST__CONTINUE ) && data ){
- newdata = (char *) astStore( NULL, data, strlen( (char *) data ) + 1 );
- if( newdata ){
- newdata[ ChrLen( data, status ) ] = 0;
- data = (void *) newdata;
- freedata = 1;
- }
- }
-
-/* Obtain the keyword length and test the card to identify the type of
- AST data item (if any) that it represents. */
- len = (int) strlen( keyword );
-
-/* "Begin" item. */
-/* ------------- */
-
-/* This is identified by a string value and a keyword of the form
- "BEGASTxx", where "xx" are characters encoding a sequence
- number. */
- if ( ( type == AST__STRING ) &&
- ( nc = 0,
- ( 0 == astSscanf( keyword, "BEGAST"
- "%*1[" SEQ_CHARS "]"
- "%*1[" SEQ_CHARS "]%n", &nc ) )
- && ( nc >= len ) ) ) {
-
-/* Note we have found a data item. */
- done = 1;
-
-/* Set the returned name to "begin" and extract the associated class
- name from the string value. Store both of these in dynamically
- allocated strings. */
- *name = astString( "begin", 5 );
- *val = UnPreQuote( (const char *) data, status );
-
-/* Indicate that the current card has been used. */
- MarkCard( this, status );
-
-/* The "begin" item will be preceded by a header of COMMENT cards. Mark
- them as having been used. */
- ComBlock( this, -1, method, class, status );
-
-/* "IsA" item. */
-/* ----------- */
-
-/* This is identified by a string value and a keyword of the form
- "ISAxx", where "xx" are characters encoding a sequence
- number. Don't accept the item if we are skipping over cards looking
- for a "Begin" item. */
- } else if ( !skip &&
- ( type == AST__STRING ) &&
- ( nc = 0,
- ( 0 == astSscanf( keyword,
- "ISA"
- "%*1[" SEQ_CHARS "]"
- "%*1[" SEQ_CHARS "]%n", &nc ) )
- && ( nc >= len ) ) ) {
-
-/* Note we have found a data item. */
- done = 1;
-
-/* Set the returned name to "isa" and extract the associated class
- name from the string value. Store both of these in dynamically
- allocated strings. */
- *name = astString( "isa", 3 );
- *val = UnPreQuote( (const char *) data, status );
-
-/* "End" item. */
-/* ----------- */
-
-/* This is identified by a string value and a keyword of the form
- "ENDASTxx", where "xx" are characters encoding a sequence
- number. Don't accept the item if we are skipping over cards looking
- for a "Begin" item. */
- } else if ( !skip &&
- ( type == AST__STRING ) &&
- ( nc = 0,
- ( 0 == astSscanf( keyword,
- "ENDAST"
- "%*1[" SEQ_CHARS "]"
- "%*1[" SEQ_CHARS "]%n", &nc ) )
- && ( nc >= len ) ) ) {
-
-/* Note we have found a data item. */
- done = 1;
-
-/* Set the returned name to "end" and extract the associated class
- name from the string value. Store both of these in dynamically
- allocated strings. */
- *name = astString( "end", 3 );
- *val = UnPreQuote( (const char *) data, status );
-
-/* The "end" item eill be followed by a footer of COMMENT cards. Mark
- these cards as having been used. */
- ComBlock( this, 1, method, class, status );
-
-/* Object or data item. */
-/* -------------------- */
-
-/* These are identified by a string, int, or double value, and a
- keyword ending in two characters encoding a sequence number. Don't
- accept the item if we are skipping over cards looking for a "Begin"
- item. */
- } else if ( !skip &&
- ( ( type == AST__STRING ) ||
- ( type == AST__INT ) ||
- ( type == AST__FLOAT ) ) &&
- ( len > 2 ) &&
- strchr( SEQ_CHARS, keyword[ len - 1 ] ) &&
- strchr( SEQ_CHARS, keyword[ len - 2 ] ) ) {
-
-/* Note we have found a data item. */
- done = 1;
-
-/* Set the returned name by removing the last two characters from the
- keyword and converting to lower case. Store this in a dynamically
- allocated string. */
- *name = astString( keyword, len - 2 );
- for ( i = 0; ( *name )[ i ]; i++ ) {
- ( *name )[ i ] = tolower( ( *name )[ i ] );
- }
-
-/* Classify the data type. */
- switch ( type ) {
-
-/* If the value is a string, test if it is zero-length. If so, this
- "null" value indicates an Object data item (whose definition
- follows), so leave the returned value pointer as NULL. Otherwise,
- we have a string data item, so extract its value and store it in a
- dynamically allocated string. */
- case AST__STRING:
- if ( *( (char *) data ) ) {
-
-/* A long string value may be continued on subsequent CONTINUE cards. See
- if the current string may be continued. This is the case if the final
- non-blank character (before UnPreQuoting) is an ampersand. */
- cont = ( ((char *) data)[ ChrLen( data, status ) - 1 ] == '&' );
-
-/* If the string does not end with an ampersand, just UnPreQUote it and
- return a copy. */
- if( !cont ) {
- *val = UnPreQuote( (const char *) data, status );
-
-/* Otherwise, initialise the returned string to hold a copy of the keyword
- value. */
- } else {
- nc = strlen( (const char *) data );
- *val = astStore( NULL, (const char *) data, nc + 1 );
-
-/* Loop round reading any subsequent CONTINUE cards. Leave the loop when
- the end-of-file is hit, or an error occurs. */
- while( cont && MoveCard( this, 1, method, class, status ) &&
- astOK ){
-
-/* See if this is a CONTINUE card. If so, get its data pointer. */
- if( CardType( this, status ) == AST__CONTINUE ){
- data = CardData( this, NULL, status );
-
-/* See if the CONTINUE card ends with an ampersand (i.e. if there is
- a possibility of there being any remaining CONTINUE cards). */
- cont = ( ( (char *) data)[ ChrLen( data, status ) - 1 ] == '&' );
-
-/* UnPreQUote it. */
- upq = UnPreQuote( (const char *) data, status );
- if( !astOK ) break;
-
-/* Expand the memory for the returned string to hold the new string. */
- nn = strlen( upq );
- *val = astRealloc( *val, nc + nn );
- if( !astOK ) break;
-
-/* Copy the new string into the expanded memory, so that the first
- character of the new string over-writes the trailing ampersand
- currently in the buffer. */
- strcpy( *val + nc - 1, upq );
-
-/* Release the memory holding the UnPreQUoted string . */
- upq = astFree( upq );
-
-/* Update the current length of the returned string. */
- nc += nn - 1;
-
-/* Mark the current card as having been read. */
- MarkCard( this, status );
-
-/* Report an error if this is not a CONTINUE card. */
- } else {
- astError( AST__BADIN, "%s(%s): One or more "
- "FITS \"CONTINUE\" cards are missing "
- "after the card for keyword \"%s\".", status,
- method, class, keyword );
- }
- }
- }
- }
- break;
-
-/* If the value is an int, format it and store the result in a
- dynamically allocated string. */
- case AST__INT:
- (void) sprintf( buff, "%d", *( (int *) data ) );
- *val = astString( buff, (int) strlen( buff ) );
- break;
-
-/* If the value is a double, format it and store the result in a
- dynamically allocated string. */
- case AST__FLOAT:
- (void) sprintf( buff, "%.*g", DBL_DIG, *( (double *) data ) );
- CheckZero( buff, *( (double *) data ), 0, status );
- *val = astString( buff, (int) strlen( buff ) );
- break;
- }
-
-/* Anything else. */
-/* -------------- */
-
-/* If the input line didn't match any of the above and the "skip" flag
- is not set, then report an error.. */
- } else if ( !skip ) {
- astError( AST__BADIN,
- "%s(%s): Cannot interpret the input data given by "
- "FITS keyword \"%s\".", status, method, class, keyword );
- }
-
-/* Free any memory used to hold stripped string data. */
- if( freedata ) newdata = (char *) astFree( (void *) newdata );
- }
-
-/* Increment the current card. */
- MoveCard( this, 1, method, class, status );
- }
-
-/* If an error occurred, ensure that any allocated memory is freed and
- that NULL pointer values are returned. */
- if ( !astOK ) {
- *name = astFree( *name );
- *val = astFree( *val );
- }
-
-/* Undefine macros local to this function. */
-#undef BUFF_LEN
-}
-
-static int GetSkip( AstChannel *this_channel, int *status ) {
-/*
-* Name:
-* GetSkip
-
-* Purpose:
-* Obtain the value of the Skip attribute for a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int GetSkip( AstChannel *this, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected astGetSkip
-* method inherited from the Channel class).
-
-* Description:
-* This function return the (boolean) integer value of the Skip
-* attribute for a FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The Skip attribute value.
-
-* Notes:
-* - This function modifies the default Skip value from 0 to 1 for
-* the benefit of the FitsChan class. This default value allows the
-* astRead method to skip over unrelated FITS keywords when
-* searching for the next Object to read.
-* - A value of zero will be returned if this function is invoked
-* with the global error status set, or if it should fail for any
-* reason.
-*/
-
-/* Local Variables: */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- int result; /* Result value to return */
-
-/* Check the global error status. */
- if ( !astOK ) return 0;
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* If the Skip attribute us set, obtain its value using the parent class
- method. */
- if ( astTestSkip( this ) ) {
- result = (* parent_getskip)( this_channel, status );
-
-/* Otherwise, supply a default value of 1. */
- } else {
- result = 1;
- }
-
-/* Return the result. */
- return result;
-}
-
-static int GetValue( AstFitsChan *this, const char *keyname, int type,
- void *value, int report, int mark, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* GetValue
-
-* Purpose:
-* Obtain a FITS keyword value.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int GetValue( AstFitsChan *this, const char *keyname, int type, void *value,
-* int report, int mark, const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function gets a value for the specified keyword from the
-* supplied FitsChan, and stores it in the supplied buffer. Optionally,
-* the keyword is marked as having been read into an AST object so that
-* it is not written out when the FitsChan is deleted.
-
-* Parameters:
-* this
-* A pointer to the FitsChan containing the keyword values to be
-* read.
-* keyname
-* A pointer to a string holding the keyword name.
-* type
-* The FITS data type in which to return the keyword value. If the
-* stored value is not of the requested type, it is converted if
-* possible.
-* value
-* A pointer to a buffer of suitable size to receive the keyword
-* value. The supplied value is left unchanged if the keyword is
-* not found.
-* report
-* Should an error be reported if the keyword cannot be found, or
-* cannot be converted to the requested type?
-* mark
-* Should the card be marked as having been used?
-* method
-* A string holding the name of the calling method.
-* class
-* A string holding the object class.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero if the keyword does not exist in "this", or cannot be
-* converted to the requested type. One is returned otherwise.
-
-* Notes:
-* - An error is reported if the keyword value is undefined.
-* - A value of zero is returned if an error has already occurred,
-* or if an error occurs within this function.
-*/
-
-/* Local Variables: */
- int icard; /* Current card index */
- int ret; /* Returned value */
-
-/* Check the status */
- if( !astOK ) return 0;
-
-/* Save the current card index. */
- icard = astGetCard( this );
-
-/* Attempt to find the supplied keyword. */
- ret = SearchCard( this, keyname, method, class, status );
-
-/* If the keyword was found, convert the current card's data value and copy
- it to the supplied buffer. */
- if( ret ){
- if( CnvValue( this, type, 0, value, method, status ) ) {
-
-/* If required, mark it as having been read into an AST object. */
- if( mark ) MarkCard( this, status );
-
-/* If the value is undefined, report an error if "report" is non-zero. */
- if( type == AST__UNDEF && report && astOK ) {
- ret = 0;
- astError( AST__FUNDEF, "%s(%s): FITS keyword \"%s\" has no value.",
- status, method, class, keyname );
- }
-
-/* If the value could not be converted to the requested data, type report
- an error if reporting is enabled. */
- } else {
- ret = 0;
- if( report && astOK ){
- astError( AST__FTCNV, "%s(%s): Cannot convert FITS keyword '%s' to %s.",
- status, method, class, keyname, type_names[ type ] );
- }
- }
-
-/* If the keyword was not found, report an error if "report" is non-zero. */
- } else if( report && astOK ){
- astError( AST__BDFTS, "%s(%s): Unable to find a value for FITS "
- "keyword \"%s\".", status, method, class, keyname );
- }
-
-/* Reinstate the original current card index. */
- astSetCard( this, icard );
-
-/* If an error has occurred, return 0. */
- if( !astOK ) ret = 0;
-
-/* Return the result. */
- return ret;
-}
-
-static int GetValue2( AstFitsChan *this1, AstFitsChan *this2, const char *keyname,
- int type, void *value, int report, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* GetValue2
-
-* Purpose:
-* Obtain a FITS keyword value from one of two FitsChans.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int GetValue2( AstFitsChan *this1, AstFitsChan *this2, const char *keyname,
-* int type, void *value, int report, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function attempts to get a value for the specified keyword from
-* the first supplied FitsChan. If this fails (due to the FitsChan not
-* containing a value for the ketword) then an attempt is made to get
-* a value for the keyword from the second supplied FitsChan.
-
-* Parameters:
-* this1
-* A pointer to the first FitsChan to be used.
-* this2
-* A pointer to the second FitsChan to be used.
-* keyname
-* A pointer to a string holding the keyword name.
-* type
-* The FITS data type in which to return the keyword value. If the
-* stored value is not of the requested type, it is converted if
-* possible.
-* value
-* A pointer to a buffer of suitable size to receive the keyword
-* value. The supplied value is left unchanged if the keyword is
-* not found.
-* report
-* Should an error be reported if the keyword cannot be found, or
-* cannot be converted to the requested type?
-* method
-* A string holding the name of the calling method.
-* class
-* A string holding the object class.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero if the keyword does not exist in either FitsChan, or cannot be
-* converted to the requested type. One is returned otherwise.
-
-* Notes:
-* - A value of zero is returned if an error has already occurred,
-* or if an error occurs within this function.
-* - If the card is found in the first FitsChan, it is not marked as
-* having been used. If the card is found in the second FitsChan, it is
-* marked as having been used.
-*/
-
-/* Local Variables: */
- int ret; /* Returned value */
-
-/* Check the status */
- if( !astOK ) return 0;
-
-/* Try the first FitsChan. If this fails try the second. Do not report
- an error if the keyword is not found in the first FitsChan (this will
- be done, if required, once the second FitsChan has been searched). */
- ret = GetValue( this1, keyname, type, value, 0, 0, method, class, status );
- if( ! ret ) {
- ret = GetValue( this2, keyname, type, value, report, 1, method, class, status );
- }
-
-/* If an error has occurred, return 0. */
- if( !astOK ) ret = 0;
-
-/* Return the result. */
- return ret;
-}
-
-static int HasAIPSSpecAxis( AstFitsChan *this, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* HasAIPSSpecAxis
-
-* Purpose:
-* Does the FitsChan contain an AIPS spectral CTYPE keyword?
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* int HasAIPSSpecAxis( AstFitsChan *this, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function returns a non-zero value if the FitsCHan contains a
-* CTYPE value which conforms to the non-standard system used by AIPS.
-
-* Parameters:
-* this
-* A pointer to the FitsChan to be used.
-* 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:
-* Non-zero if an AIPS spectral CTYPE keyword was found.
-*/
-
-/* Local Variables: */
- char *assys; /* AIPS standard of rest type */
- char *astype; /* AIPS spectral type */
- char *cval; /* Pointer to character string */
- int j; /* Current axis index */
- int jhi; /* Highest axis index with a CTYPE */
- int jlo; /* Lowest axis index with a CTYPE */
- int ret; /* Returned value */
-
-/* Initialise */
- ret = 0;
-
-/* Check the status */
- if( !astOK ) return ret;
-
-/* If the FitsChan contains any CTYPE values, convert the bounds from
- one-based to zero-based, and loop round them all. */
- if( astKeyFields( this, "CTYPE%1d", 1, &jhi, &jlo ) ) {
- jlo--;
- jhi--;
- for( j = jlo; j <= jhi; j++ ) {
-
-/* Get the next CTYPE value. If found, see if it is an AIPS spectral
- CTYPE value. */
- if( GetValue( this, FormatKey( "CTYPE", j + 1, -1, ' ', status ),
- AST__STRING, (void *) &cval, 0, 0, method,
- class, status ) ){
- if( IsAIPSSpectral( cval, &astype, &assys, status ) ) {
- ret = 1;
- break;
- }
- }
- }
- }
-
-/* If an error has occurred, return 0. */
- if( !astOK ) ret = 0;
-
-/* Return the result. */
- return ret;
-}
-
-static int HasCard( AstFitsChan *this, const char *name,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* HasCard
-
-* Purpose:
-* Check if the FitsChan contains a specified keyword.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int HasCard( AstFitsChan *this, const char *name,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns a non-zero value if the FitsChan contains the given keyword,
-* and zero otherwise. The current card is unchanged.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a string holding the keyword name.
-* method
-* Pointer to string holding name of calling method.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A value of 1 is returned if a card was found refering to the given
-* keyword. Otherwise zero is returned.
-*/
-
-/* Check the supplied pointers (we can rely on astMapHasKey to check the
- inherited status). */
- if( !name || !this || !this->keywords ) return 0;
-
-/* Search the KeyMap holding the keywords currently in the FitsChan,
- returning non-zero if the keyword was found. A KeyMap is used because
- it uses a hashing algorithm to find the entries and is therefore a lot
- quicker than searching through the list of linked FitsCards. */
- return astMapHasKey( this->keywords, name );
-}
-void astInitFitsChanVtab_( AstFitsChanVtab *vtab, const char *name, int *status ) {
-
-/*
-*+
-* Name:
-* astInitFitsChanVtab
-
-* Purpose:
-* Initialise a virtual function table for a FitsChan.
-
-* Type:
-* Protected function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void astInitFitsChanVtab( AstFitsChanVtab *vtab, const char *name )
-
-* Class Membership:
-* FitsChan vtab initialiser.
-
-* Description:
-* This function initialises the component of a virtual function
-* table which is used by the FitsChan class.
-
-* Parameters:
-* vtab
-* Pointer to the virtual function table. The components used by
-* all ancestral classes will be initialised if they have not already
-* been initialised.
-* name
-* Pointer to a constant null-terminated character string which contains
-* the name of the class to which the virtual function table belongs (it
-* is this pointer value that will subsequently be returned by the Object
-* astClass function).
-*-
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstObjectVtab *object; /* Pointer to Object component of Vtab */
- AstChannelVtab *channel; /* Pointer to Channel component of Vtab */
- char buf[ 100 ]; /* Buffer large enough to store formatted INT_MAX */
-
-/* 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. */
- astInitChannelVtab( (AstChannelVtab *) vtab, name );
-
-/* Store a unique "magic" value in the virtual function table. This
- will be used (by astIsAFitsChan) 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 = &(((AstChannelVtab *) vtab)->id);
-
-/* Initialise member function pointers. */
-/* ------------------------------------ */
-
-/* Store pointers to the member functions (implemented here) that provide
- virtual methods for this class. */
- vtab->PutCards = PutCards;
- vtab->PutFits = PutFits;
- vtab->DelFits = DelFits;
- vtab->GetTables = GetTables;
- vtab->PutTables = PutTables;
- vtab->PutTable = PutTable;
- vtab->TableSource = TableSource;
- vtab->SetTableSource = SetTableSource;
- vtab->RemoveTables = RemoveTables;
- vtab->PurgeWCS = PurgeWCS;
- vtab->RetainFits = RetainFits;
- vtab->FindFits = FindFits;
- vtab->KeyFields = KeyFields;
- vtab->ReadFits = ReadFits;
- vtab->ShowFits = ShowFits;
- vtab->WriteFits = WriteFits;
- vtab->EmptyFits = EmptyFits;
- vtab->FitsEof = FitsEof;
- vtab->GetFitsCF = GetFitsCF;
- vtab->GetFitsCI = GetFitsCI;
- vtab->GetFitsF = GetFitsF;
- vtab->GetFitsI = GetFitsI;
- vtab->GetFitsL = GetFitsL;
- vtab->TestFits = TestFits;
- vtab->GetFitsS = GetFitsS;
- vtab->GetFitsCN = GetFitsCN;
- vtab->FitsGetCom = FitsGetCom;
- vtab->SetFitsCom = SetFitsCom;
- vtab->SetFitsCF = SetFitsCF;
- vtab->SetFitsCI = SetFitsCI;
- vtab->SetFitsF = SetFitsF;
- vtab->SetFitsI = SetFitsI;
- vtab->SetFitsL = SetFitsL;
- vtab->SetFitsU = SetFitsU;
- vtab->SetFitsS = SetFitsS;
- vtab->SetFitsCN = SetFitsCN;
- vtab->SetFitsCM = SetFitsCM;
- vtab->ClearCard = ClearCard;
- vtab->TestCard = TestCard;
- vtab->SetCard = SetCard;
- vtab->GetCard = GetCard;
- vtab->ClearFitsDigits = ClearFitsDigits;
- vtab->TestFitsDigits = TestFitsDigits;
- vtab->SetFitsDigits = SetFitsDigits;
- vtab->GetFitsDigits = GetFitsDigits;
- vtab->ClearFitsAxisOrder = ClearFitsAxisOrder;
- vtab->TestFitsAxisOrder = TestFitsAxisOrder;
- vtab->SetFitsAxisOrder = SetFitsAxisOrder;
- vtab->GetFitsAxisOrder = GetFitsAxisOrder;
- vtab->ClearDefB1950 = ClearDefB1950;
- vtab->TestDefB1950 = TestDefB1950;
- vtab->SetDefB1950 = SetDefB1950;
- vtab->GetDefB1950 = GetDefB1950;
- vtab->ClearTabOK = ClearTabOK;
- vtab->TestTabOK = TestTabOK;
- vtab->SetTabOK = SetTabOK;
- vtab->GetTabOK = GetTabOK;
- vtab->ClearCarLin = ClearCarLin;
- vtab->TestCarLin = TestCarLin;
- vtab->SetCarLin = SetCarLin;
- vtab->GetCarLin = GetCarLin;
- vtab->ClearPolyTan = ClearPolyTan;
- vtab->TestPolyTan = TestPolyTan;
- vtab->SetPolyTan = SetPolyTan;
- vtab->GetPolyTan = GetPolyTan;
- vtab->ClearIwc = ClearIwc;
- vtab->TestIwc = TestIwc;
- vtab->SetIwc = SetIwc;
- vtab->GetIwc = GetIwc;
- vtab->ClearWarnings = ClearWarnings;
- vtab->TestWarnings = TestWarnings;
- vtab->SetWarnings = SetWarnings;
- vtab->GetWarnings = GetWarnings;
- vtab->GetCardType = GetCardType;
- vtab->GetCardName = GetCardName;
- vtab->GetCardComm = GetCardComm;
- vtab->GetNcard = GetNcard;
- vtab->GetNkey = GetNkey;
- vtab->GetAllWarnings = GetAllWarnings;
- vtab->ClearEncoding = ClearEncoding;
- vtab->TestEncoding = TestEncoding;
- vtab->SetEncoding = SetEncoding;
- vtab->GetEncoding = GetEncoding;
- vtab->ClearClean = ClearClean;
- vtab->TestClean = TestClean;
- vtab->SetClean = SetClean;
- vtab->GetClean = GetClean;
- vtab->ClearCDMatrix = ClearCDMatrix;
- vtab->TestCDMatrix = TestCDMatrix;
- vtab->SetCDMatrix = SetCDMatrix;
- vtab->GetCDMatrix = GetCDMatrix;
-
-/* Save the inherited pointers to methods that will be extended, and
- replace them with pointers to the new member functions. */
- object = (AstObjectVtab *) vtab;
- channel = (AstChannelVtab *) vtab;
- parent_getobjsize = object->GetObjSize;
- object->GetObjSize = GetObjSize;
-#if defined(THREAD_SAFE)
- parent_managelock = object->ManageLock;
- object->ManageLock = ManageLock;
-#endif
- 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_write = channel->Write;
- channel->Write = Write;
- parent_read = channel->Read;
- channel->Read = Read;
- parent_getskip = channel->GetSkip;
- channel->GetSkip = GetSkip;
- parent_getfull = channel->GetFull;
- channel->GetFull = GetFull;
- channel->WriteBegin = WriteBegin;
- channel->WriteIsA = WriteIsA;
- channel->WriteEnd = WriteEnd;
- channel->WriteInt = WriteInt;
- channel->WriteDouble = WriteDouble;
- channel->WriteString = WriteString;
- channel->WriteObject = WriteObject;
- channel->GetNextData = GetNextData;
- parent_setsourcefile = channel->SetSourceFile;
- channel->SetSourceFile = SetSourceFile;
-
-/* Declare the class dump, copy and delete functions.*/
- astSetDump( vtab, Dump, "FitsChan", "I/O channels to FITS files" );
- astSetCopy( (AstObjectVtab *) vtab, Copy );
- astSetDelete( (AstObjectVtab *) vtab, Delete );
-
-/* Max number of characters needed to format an int. */
- LOCK_MUTEX4
- sprintf( buf, "%d", INT_MAX );
- int_dig = strlen( buf );
-
-/* Create a pair of MJD TimeFrames which will be used for converting to and
- from TDB. */
- astBeginPM;
- if( !tdbframe ) tdbframe = astTimeFrame( "system=MJD,timescale=TDB", status );
- if( !timeframe ) timeframe = astTimeFrame( "system=MJD", status );
- astEndPM;
- UNLOCK_MUTEX4
-
-/* If we have just initialised the vtab for the current class, indicate
- that the vtab is now initialised, and store a pointer to the class
- identifier in the base "object" level of the vtab. */
- if( vtab == &class_vtab ) {
- class_init = 1;
- astSetVtabClassIdentifier( vtab, &(vtab->id) );
- }
-}
-
-static void InsCard( AstFitsChan *this, int overwrite, const char *name,
- int type, void *data, const char *comment,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* InsCard
-
-* Purpose:
-* Inserts a card into a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void InsCard( AstFitsChan *this, int overwrite, const char *name,
-* int type, void *data, const char *comment,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Either appends a new card to a FitsChan, or over-writes an existing
-* card, holding the supplied keyword name, value and comment.
-
-* Parameters:
-* this
-* Pointer to the FitsChan containing the filters to apply to the
-* keyword name. If a NULL pointer is supplied, no filtering is applied.
-* overwrite
-* If non-zero, the new card over-writes the current card given by
-* the "Card" attribute, and the current card is incremented so
-* that it refers to the next card. Otherwise, the new card is
-* inserted in front of the current card and the current card is
-* left unchanged.
-* name
-* Pointer to a string holding the keyword name of the new card.
-* type
-* An integer value representing the data type of the keyword.
-* data
-* Pointer to the data associated with the keyword.
-* comment
-* Pointer to a null-terminated string holding a comment.
-* 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.
-
-* Notes:
-* - An error is reported if an attempt is made to change the data type
-* of an existing card.
-* - If a type of AST__COMMENT is supplied, then any data value (of any
-* type) associated with an existing card is left unchanged.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- int flags; /* Flags to assign to new card */
-
-/* Check the global status. */
- if( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* If the current card is to be over-written, delete the current card (the
- next card in the list, if any, will become the new current card). */
- if( overwrite ) DeleteCard( this, method, class, status );
-
-/* If requested, set both NEW flags for the new card. */
- flags = ( mark_new ) ? ( NEW1 | NEW2 ): 0;
-
-/* Insert the new card into the list, just before the current card. */
- NewCard( this, name, type, data, comment, flags, status );
-}
-
-static int IRAFFromStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* IRAFFromStore
-
-* Purpose:
-* Store WCS keywords in a FitsChan using FITS-IRAF encoding.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* int IRAFFromStore( AstFitsChan *this, FitsStore *store,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function copies the WCS information stored in the supplied
-* FitsStore into the supplied FitsChan, using FITS-IRAF encoding.
-*
-* IRAF encoding is like FITS-WCS encoding but with the following
-* restrictions:
-*
-* 1) The celestial projection must not have any projection parameters
-* which are not set to their default values. The one exception to this
-* is that SIN projections are acceptable if the associated projection
-* parameter PV<axlat>_1 is zero and PV<axlat>_2 = cot( reference point
-* latitude). This is encoded using the string "-NCP". The SFL projection
-* is encoded using the string "-GLS". Note, the original IRAF WCS
-* system only recognised a small subset of the currently available
-* projections, but some more recent IRAF-like software recognizes some
-* of the new projections included in the FITS-WCS encoding.
-*
-* 2) The celestial axes must be RA/DEC, galactic or ecliptic.
-*
-* 3) LONPOLE and LATPOLE cannot be used.
-*
-* 4) Only primary axis descriptions are written out.
-*
-* 5) RADECSYS is used in place of RADESYS.
-*
-* 6) PC/CDELT keywords are not allowed (CD must be used)
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore.
-* 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 value of 1 is returned if succesfull, and zero is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- char *comm; /* Pointer to comment string */
- char *cval; /* Pointer to string keyword value */
- char combuf[80]; /* Buffer for FITS card comment */
- char lattype[MXCTYPELEN];/* Latitude axis CTYPE */
- char lontype[MXCTYPELEN];/* Longitude axis CTYPE */
- char s; /* Co-ordinate version character */
- char sign[2]; /* Fraction's sign character */
- double cdelt; /* A CDELT value */
- double fd; /* Fraction of a day */
- double mjd99; /* MJD at start of 1999 */
- double p1, p2; /* Projection parameters */
- double val; /* General purpose value */
- int axlat; /* Index of latitude FITS WCS axis */
- int axlon; /* Index of longitude FITS WCS axis */
- int axspec; /* Index of spectral FITS WCS axis */
- int i; /* Axis index */
- int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */
- int iymdf[ 4 ]; /* Year, month, date, fractional day */
- int j; /* Axis index */
- int jj; /* SlaLib status */
- int naxis; /* No. of axes */
- int ok; /* Is FitsSTore OK for IRAF encoding? */
- int prj; /* Projection type */
- int ret; /* Returned value. */
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* First check that the values in the FitsStore conform to the
- requirements of the IRAF encoding. Assume they do to begin with. */
- ok = 1;
-
-/* Just do primary axes. */
- s = ' ';
-
-/* Look for the primary celestial and spectral axes. */
- FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status );
-
-/* If both longitude and latitude axes are present and thereis no
- spectral axis...*/
- if( axlon >= 0 && axlat >= 0 ) {
-
-/* Get the CTYPE values for both axes. */
- cval = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status );
- if( !cval ) return ret;
- strcpy( lontype, cval );
- cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status );
- if( !cval ) return ret;
- strcpy( lattype, cval );
-
-/* Extract the projection type as specified by the last 4 characters
- in the CTYPE keyword value. */
- prj = astWcsPrjType( lattype + 4 );
-
-/* Check the projection type is OK. Assume not initially. */
- ok = 0;
-
-/* FITS-IRAF cannot handle the AST-specific TPN projection. */
- if( prj == AST__TPN || prj == AST__WCSBAD ) {
- ok = 0;
-
-/* SIN projections are handled later. */
- } else if( prj != AST__SIN ){
-
-/* There must be no projection parameters. */
- if( GetMaxJM( &(store->pv), ' ', status ) == -1 ) ok = 1;
-
-/* Change the new SFL projection code to to the older equivalent GLS */
- if( prj == AST__SFL ){
- (void) strcpy( lontype + 4, "-GLS" );
- (void) strcpy( lattype + 4, "-GLS" );
- }
-
-/* SIN projections are only acceptable if the associated projection
- parameters are both zero, or if the first is zero and the second
- = cot( reference point latitude ) (the latter case is equivalent to
- the old NCP projection). */
- } else {
- p1 = GetItem( &( store->pv ), axlat, 1, s, NULL, method, class, status );
- p2 = GetItem( &( store->pv ), axlat, 2, s, NULL, method, class, status );
- if( p1 == AST__BAD ) p1 = 0.0;
- if( p2 == AST__BAD ) p2 = 0.0;
- val = GetItem( &( store->crval ), axlat, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- if( p1 == 0.0 ) {
- if( p2 == 0.0 ) {
- ok = 1;
- } else if( fabs( p2 ) >= 1.0E14 && val == 0.0 ){
- ok = 1;
- (void) strcpy( lontype + 4, "-NCP" );
- (void) strcpy( lattype + 4, "-NCP" );
- } else if( fabs( p2*tan( AST__DD2R*val ) - 1.0 )
- < 0.01 ){
- ok = 1;
- (void) strcpy( lontype + 4, "-NCP" );
- (void) strcpy( lattype + 4, "-NCP" );
- }
- }
- }
- }
-
-/* Identify the celestial coordinate system from the first 4 characters of the
- longitude CTYPE value. Only RA, galactic longitude, and ecliptic
- longitude can be stored using FITS-IRAF. */
- if( strncmp( lontype, "RA--", 4 ) &&
- strncmp( lontype, "GLON", 4 ) &&
- strncmp( lontype, "ELON", 4 ) ) ok = 0;
-
-/* If the physical Frame requires a LONPOLE or LATPOLE keyword, it cannot
- be encoded using FITS-IRAF. */
- if( GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status )
- != AST__BAD ||
- GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status )
- != AST__BAD ) ok = 0;
-
-/* If there are no celestial axes, the physical Frame can be written out
- using FITS-IRAF. */
- } else {
- ok = 1;
- }
-
-/* Save the number of axes */
- naxis = GetMaxJM( &(store->crpix), ' ', status ) + 1;
-
-/* If this is different to the value of NAXIS abort since this encoding
- does not support WCSAXES keyword. */
- if( naxis != store->naxis ) ok = 0;
-
-/* Return if the FitsStore does not conform to IRAF encoding. */
- if( !ok ) return ret;
-
-/* Get and save CRPIX for all pixel axes. These are required, so return
- if they are not available. */
- for( i = 0; i < naxis; i++ ){
- val = GetItem( &(store->crpix), 0, i, s, NULL, method, class, status );
- if( val == AST__BAD ) return ret;
- sprintf( combuf, "Reference pixel on axis %d", i + 1 );
- SetValue( this, FormatKey( "CRPIX", i + 1, -1, s, status ), &val, AST__FLOAT,
- combuf, status );
- }
-
-/* Get and save CRVAL for all intermediate axes. These are required, so return
- if they are not available. */
- for( j = 0; j < naxis; j++ ){
- val = GetItem( &(store->crval), j, 0, s, NULL, method, class, status );
- if( val == AST__BAD ) return ret;
- sprintf( combuf, "Value at ref. pixel on axis %d", j + 1 );
- SetValue( this, FormatKey( "CRVAL", j + 1, -1, s, status ), &val, AST__FLOAT,
- combuf, status );
- }
-
-/* Get and save CTYPE for all intermediate axes. These are required, so return
- if they are not available. Use the potentially modified versions saved
- above for the celestial axes. */
- for( i = 0; i < naxis; i++ ){
- if( i == axlat ) {
- cval = lattype;
- } else if( i == axlon ) {
- cval = lontype;
- } else {
- cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- if( !cval ) return ret;
- }
- if( strlen(cval) > 4 && !strcmp( cval + 4, "-TAB" ) ) return ret;
- comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status );
- if( !comm ) {
- sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 );
- comm = combuf;
- }
- SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval, AST__STRING,
- comm, status );
- }
-
-/* CD matrix (the product of the CDELT and PC matrices). */
- for( i = 0; i < naxis; i++ ){
- cdelt = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
- if( cdelt == AST__BAD ) cdelt = 1.0;
- for( j = 0; j < naxis; j++ ){
- val = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
- if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0;
- val *= cdelt;
- if( val != 0.0 ) {
- SetValue( this, FormatKey( "CD", i + 1, j + 1, s, status ), &val,
- AST__FLOAT, "Transformation matrix element", status );
- }
- }
- }
-
-/* Get and save CUNIT for all intermediate axes. These are NOT required, so
- do not return if they are not available. */
- for( i = 0; i < naxis; i++ ){
- cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status );
- if( cval ) {
- sprintf( combuf, "Units for axis %d", i + 1 );
- SetValue( this, FormatKey( "CUNIT", i + 1, -1, s, status ), &cval, AST__STRING,
- combuf, status );
- }
- }
-
-/* Get and save RADECSYS. This is NOT required, so do not return if it is
- not available. */
- cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status );
- if( cval ) SetValue( this, "RADECSYS", &cval, AST__STRING,
- "Reference frame for RA/DEC values", status );
-
-/* Reference equinox */
- val = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, "EQUINOX", &val, AST__FLOAT,
- "Epoch of reference equinox", status );
-
-/* Date of observation */
- val = GetItem( &(store->mjdobs), 0, 0, ' ', NULL, method, class, status );
- if( val != AST__BAD ) {
-
-/* The format used for the DATE-OBS keyword depends on the value of the
- keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format.
- Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */
- palCaldj( 99, 1, 1, &mjd99, &jj );
- if( val < mjd99 ) {
- palDjcal( 0, val, iymdf, &jj );
- sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ],
- iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) );
- } else {
- palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj );
- palDd2tf( 3, fd, sign, ihmsf );
- sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d",
- iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1],
- ihmsf[2], ihmsf[3] );
- }
-
-/* Now store the formatted string in the FitsChan. */
- cval = combuf;
- SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING,
- "Date of observation", status );
- }
-
-/* If we get here we have succeeded. */
- ret = 1;
-
-/* Return zero or ret depending on whether an error has occurred. */
- return astOK ? ret : 0;
-}
-
-static int IsMapLinear( AstMapping *smap, const double lbnd_in[],
- const double ubnd_in[], int coord_out, int *status ) {
-/*
-* Name:
-* IsMapLinear
-
-* Purpose:
-* See if a specified Mapping output is linearly related to the
-* Mapping inputs.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int IsMapLinear( AstMapping *smap, const double lbnd_in[],
-* const double ubnd_in[], int coord_out, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns a flag indicating if the specified output of the supplied
-* Mapping is a linear function of the Mapping inputs. A set of output
-* positions are created which are evenly spaced along the specified
-* output coordinate. The spacing is chosen so that the entire range
-* of the output coordinate is covered in 20 steps. The other output
-* coordinates are held fixed at arbitrary values (actually, values
-* at which the specified output coordinate achieves its minimum value).
-* This set of output positions is transformed into the corresponding
-* set of input coordinates using the inverse of the supplied Mapping.
-* A least squares linear fit is then made which models each input
-* coordinate as a linear function of the specified output coordinate.
-* The residual at every point in this fit must be less than some
-* small fraction of the total range of the corresponding input
-* coordinate for the Mapping to be considered linear.
-
-* Parameters:
-* smap
-* Pointer to the Mapping.
-* lbnd_in
-* Pointer to an array of double, with one element for each
-* Mapping input coordinate. This should contain the lower bound
-* of the input box in each input dimension.
-* ubnd_in
-* Pointer to an array of double, with one element for each
-* Mapping input coordinate. This should contain the upper bound
-* of the input box in each input dimension.
-* coord_out
-* The zero-based index of the Mapping output which is to be checked.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Non-zero if the specified Mapping output is linear. Zero otherwise.
-*/
-
-/* Local Constants: */
-#define NP 20
-
-/* Local Variables: */
- AstMapping *map;
- AstPointSet *pset1;
- AstPointSet *pset2;
- double **ptr1;
- double **ptr2;
- double *p;
- double *s;
- double *xl;
- double c;
- double d;
- double delta;
- double in_lbnd;
- double in_ubnd;
- double lbnd_out;
- double m;
- double p0;
- double pv;
- double sn;
- double sp;
- double sps;
- double ss2;
- double ss;
- double sv;
- double tol;
- double ubnd_out;
- int *ins;
- int boxok;
- int i;
- int j;
- int nin;
- int nout;
- int oldrep;
- int ret;
-
-/* Initialise */
- ret = 0;
-
-/* Check inherited status */
- if( !astOK ) return ret;
-
-/* Attempt to split off the required output (in case any of the other
- outputs are associated with Mappings that do not have an inverse). */
- astInvert( smap );
- ins = astMapSplit( smap, 1, &coord_out, &map );
- astInvert( smap );
-
-/* If successful, check that the output is fed by only one input. */
- if( ins ) {
- if( astGetNin( map ) == 1 ) {
-
-/* If so, invert the map so that it goes from pixel to wcs, and then
- modify the supplied arguments so that they refer to the single required
- axis. */
- astInvert( map );
- lbnd_in += coord_out;
- ubnd_in += coord_out;
- coord_out = 0;
-
-/* If the output was fed by more than one input, annul the split mapping
- and use the supplied nmapping. */
- } else {
- (void) astAnnul( map );
- map = astClone( smap );
- }
- ins = astFree( ins );
-
-/* If the supplied Mapping could not be split, use the supplied nmapping. */
- } else {
- map = astClone( smap );
- }
-
-/* Check the Mapping is defined in both directions. */
- if( astGetTranForward( map ) && astGetTranInverse( map ) ) {
-
-/* Allocate resources. */
- nin = astGetNin( map );
- nout = astGetNout( map );
- xl = astMalloc( sizeof( double )*(size_t) nin );
- pset1 = astPointSet( NP, nin, "", status );
- ptr1 = astGetPoints( pset1 );
- pset2 = astPointSet( NP, nout, "", status );
- ptr2 = astGetPoints( pset2 );
-
-/* Call astMapBox in a new error reporting context. */
- boxok = 0;
- if( astOK ) {
-
-/* Temporarily switch off error reporting so that no report is made if
- astMapBox cannot find a bounding box (which can legitimately happen with
- some non-linear Mappings). */
- oldrep = astReporting( 0 );
-
-/* Find the upper and lower bounds on the specified Mapping output. This also
- returns the input coords of a point at which the required output has its
- lowest value. */
- astMapBox( map, lbnd_in, ubnd_in, 1, coord_out, &lbnd_out, &ubnd_out,
- xl, NULL );
-
-/* If the box could not be found, clear the error status and pass on. */
- if( !astOK ) {
- astClearStatus;
-
-/* If the box was found OK, flag this and check if the bounds are equal.
- If so we cannot use them. In this case create new bounds. */
- } else {
- boxok = 1;
- if( astEQUAL( lbnd_out, ubnd_out ) ) {
- m = 0.5*( lbnd_out + ubnd_out );
- if( fabs( m ) > 1.0E-15 ) {
- lbnd_out = 0.9*m;
- ubnd_out = 1.1*m;
- } else {
- lbnd_out = -1.0;
- ubnd_out = 1.0;
- }
- }
- }
-
-/* Re-instate error reporting. */
- astReporting( oldrep );
- }
-
-/* Check pointers can be used safely and a box was obtained. */
- if( astOK && boxok ) {
-
-/* Transform the input position returned by astMapBox using the supplied
- Mapping to get the corresponding output position. Fill all unused
- elements of the PointSet with AST__BAD. */
- for( i = 0; i < nin; i++ ){
- p = ptr1[ i ];
- *(p++) = xl[ i ];
- for( j = 1; j < NP; j++ ) *(p++) = AST__BAD;
- }
- (void) astTransform( map, pset1, 1, pset2 );
-
-/* Now create a set of NP points evenly spaced in output coordinates. The
- first point is at the output position found above. Each subsequent
- point is incremented by a fixed amount along the specified output
- coordinate (the values on all other output coordinates is held fixed). */
- delta = ( ubnd_out - lbnd_out )/ ( NP - 1 );
- for( i = 0; i < nout; i++ ){
- p = ptr2[ i ];
- if( i == coord_out ) {
- for( j = 0; j < NP; j++ ) *(p++) = lbnd_out + j*delta;
- } else {
- p0 = p[ 0 ];
- for( j = 0; j < NP; j++ ) *(p++) = p0;
- }
- }
-
-/* Transform these output positions into input positions using the
- inverse Mapping. */
- (void) astTransform( map, pset2, 0, pset1 );
-
-/* Do a least squares fit to each input coordinate. Each fit gives the
- corresponding input coordinate value as a linear function of the
- specified output coordinate value. Note, linear function should never
- produce bad values so abort if a bad value is found. */
- ret = 1;
- s = ptr2[ coord_out ];
- for( i = 0; i < nin; i++ ) {
- p = ptr1[ i ];
-
-/* Form the required sums. Also find the largest and smallest input
- coordinate value achieved. */
- sp = 0.0;
- ss = 0.0;
- sps = 0.0;
- sn = 0.0;
- ss2 = 0.0;
- in_lbnd = DBL_MAX;
- in_ubnd = DBL_MIN;
- for( j = 0; j < NP; j++ ) {
- sv = s[ j ];
- pv = p[ j ];
- if( pv != AST__BAD && sv != AST__BAD ) {
- sp += pv;
- ss += sv;
- sps += pv*sv;
- sn += 1.0;
- ss2 += sv*sv;
- if( pv < in_lbnd ) in_lbnd = pv;
- if( pv > in_ubnd ) in_ubnd = pv;
- } else {
- sn = 0.0;
- break;
- }
- }
-
-/* Ignore input axes which are independant of the output axis. */
- if( !astEQUAL( in_lbnd, in_ubnd ) ) {
-
-/* Calculate the constants "input coord = m*output coord + c" */
- d = ss*ss - sn*ss2;
- if( sn > 0.0 && d != 0.0 ) {
- m = ( sp*ss - sps*sn )/d;
- c = ( sps*ss - sp*ss2 )/d;
-
-/* Subtract off the fit value form the "p" values to get the residuals of
- the fit. */
- for( j = 0; j < NP; j++ ) p[ j ] -= m*s[ j ] + c;
-
-/* We now do a least squares fit to the residuals. This second fit is done
- because the first least squares fit sometimes leaves the residuals with a
- distinct non-zero gradient. We do not need to worry about bad values
- here since we have checked above that there are no bad values. Also we
- do not need to recalculate sums which only depend on the "s" values since
- they have not changed. */
- sp = 0.0;
- sps = 0.0;
- for( j = 0; j < NP; j++ ) {
- pv = p[ j ];
- sp += pv;
- sps += pv*s[ j ];
- }
-
-/* Find the constants in "input residual = m*output coord + c" equation. */
- m = ( sp*ss - sps*sn )/d;
- c = ( sps*ss - sp*ss2 )/d;
-
-/* Subtract off the fit value form the "p residuals" values to get the
- residual redisuals of the fit. */
- for( j = 0; j < NP; j++ ) p[ j ] -= m*s[ j ] + c;
-
-/* The requirement for a linear relationship is that the absolute residual
- between the input coord produced by the above linear fit and the input
- coord produced by the actual Mapping should be less than some small
- fraction of the total range of input coord value, at every point. Test
- this. */
- tol = 1.0E-7*( in_ubnd - in_lbnd );
- for( j = 0; j < NP; j++ ) {
- if( fabs( p[ j ] ) > tol ) {
- ret = 0;
- break;
- }
- }
- } else {
- ret = 0;
- }
- }
- if( !ret ) break;
- }
- }
-
-/* Free resources. */
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
- xl = astFree( xl );
- }
- map = astAnnul( map );
-
-/* Return the answer. */
- return ret;
-}
-
-static AstMapping *IsMapTab1D( AstMapping *map, double scale, const char *unit,
- AstFrame *wcsfrm, double *dim, int iax,
- int iwcs, AstFitsTable **table, int *icolmain,
- int *icolindex, int *interp, int *status ){
-/*
-* Name:
-* IsMapTab1D
-
-* Purpose:
-* See if a specified Mapping output is related to a single Mapping input
-* via a FITS -TAB algorithm.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *IsMapTab1D( AstMapping *map, double scale, const char *unit,
-* AstFrame *wcsfrm, double *dim, int iax,
-* int iwcs, AstFitsTable **table, int *icolmain,
-* int *icolindex, int *interp, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A specified axis of the supplied Mapping is tested to see if it
-* can be represented by the -TAB alogirithm described in FITS-WCS
-* paper III. If the test is passed, a Mapping is returned from the
-* specified WCS axis to the corresponding psi axis. A FitsTable is
-* also created holding the information to be stored in the
-* corresponding FITS binary table.
-*
-* Note, when creating a -TAB header, AST uses grid coords for the psi
-* axis. See FITS-WCS paper III section 6.1.2 for a definition of the
-* psi axes.
-
-* Parameters:
-* map
-* Pointer to the Mapping from pixel coords to WCS coords.
-* scale
-* A scale factor by which to multiply the axis values stored in the
-* returned FitsTable. Note, the returned Mapping is unaffected by
-* this scaling factor.
-* unit
-* Pointer to the unit string to store with the coords column. If
-* NULL, the unit string is extracted form the supplied WCS Frame.
-* wcsfrm
-* Pointer to a Frame describing WCS coords.
-* dim
-* An array holding the array dimensions in pixels. AST__BAD should
-* be supplied for any unknown dimensions.
-* iax
-* The zero-based index of the Mapping output which is to be checked.
-* iwcs
-* The zero-based index of the corresponding FITS WCS axis.
-* table
-* Pointer to a location holding a pointer to the FitsTable describing
-* the -TAB look-up table. If "*table" is NULL on entry, a new
-* FitsTable will be created and returned, otherwise the supplied
-* FitsTable is used.
-* icolmain
-* The one-based index of the column within "*table" that holds the
-* main data array.
-* icolindex
-* The one-based index of the column within "*table" that holds the
-* index vector. Returned equal to -1 if no index is added to the
-* table (i.e. if the index is a unt index).
-* interp
-* The interpolation method (0=linear, other=nearest neighbour).
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* If the specified "map" output can be described using the -TAB
-* algorithm of FITS-WCS paper III, then a 1-input/1-output Mapping
-* from the specified WCS axis to the corresponding psi axis (which is
-* assumed to be equal to grid coords) is returned. NULL is returned
-* otherwise, of if an error occurs.
-*/
-
-/* Local Variables: */
- AstCmpMap *cm; /* CmpMap pointer */
- AstMapping **map_list; /* Mapping array pointer */
- AstMapping *postmap; /* Total Mapping after LutMap */
- AstMapping *premap; /* Total Mapping before LutMap */
- AstMapping *ret; /* Returned WCS axis Mapping */
- AstMapping *tmap; /* Temporary Mapping */
- AstPermMap *pm; /* PermMap pointer */
- char cellname[ 20 ]; /* Buffer for cell name */
- char colname[ 20 ]; /* Buffer for column name */
- double *lut; /* Pointer to table of Y values */
- double *work1; /* Pointer to work array */
- double *work2; /* Pointer to work array */
- double inc; /* X increment between table entries */
- double start; /* X value at first table entry */
- double v[ 2 ]; /* Y values at start and end of interval */
- double x[ 2 ]; /* X values at start and end of interval */
- int *ins; /* Array of "map" input indices */
- int *invert_list; /* Invert array pointer */
- int *outs; /* Array of "map" output indices */
- int dims[ 2 ]; /* Dimensions of the tab coords array */
- int iin; /* Index of Mapping input */
- int ilut; /* Index of the LutMap within the mappings list */
- int imap; /* Index of current Mapping in list */
- int iout; /* Index of Mapping output */
- int jout; /* Index of Mapping output */
- int nin; /* Number of Mapping inputs */
- int nlut; /* Number of elements in "lut" array */
- int nmap; /* Number of Mappings in the list */
- int nout; /* Number of Mapping outputs */
- int ok; /* Were columns added to the table? */
- int old_invert; /* Original value for Mapping's Invert flag */
- int outperm; /* Index of input that feeds the single output */
-
-/* Initialise */
- ret = NULL;
- *icolmain = -1;
- *icolindex = -1;
- *interp = 0;
-
-/* Check inherited status */
- if( !astOK ) return ret;
-
-/* Ensure we have aunit string. */
- if( !unit ) unit = astGetUnit( wcsfrm, iax );
-
-/* Check that the requested mapping output is fed by only one mapping
- input, identify that input, and extract the input->output mapping from
- the total mapping. Since astMapSplit splits off a specified input, we
- need to invert the Mapping first so we can split off a specified output. */
- astInvert( map );
- ins = astMapSplit( map, 1, &iax, &ret );
- astInvert( map );
-
-/* If the Mapping could not be split, try a different approach in which
- each input is checked in turn to see if it feeds the specified output. */
- if( !ins ) {
-
-/* Loop round each input of "map". */
- nin = astGetNin( map );
- for( iin = 0; iin < nin && !ins; iin++ ) {
-
-/* Attempt to find a group of outputs (of "map") that are fed by just
- this one input. */
- outs = astMapSplit( map, 1, &iin, &ret );
-
-/* If successful, "ret" will be a Mapping with one input corresponding to
- input "iin" of "map, and one or more outputs. We loop round these
- outputs to see if any of them correspond to output "iax" of "map". */
- if( outs ) {
- nout = astGetNout( ret );
- for( iout = 0; iout < nout; iout++ ) {
- if( outs[ iout ] == iax ) break;
- }
-
-/* Did input "iin" feed the output "iax" (and possibly other outputs)? */
- if( iout < nout ) {
-
-/* The "ret" Mapping is now a 1-input (pixel) N-output (WCS) Mapping in which
- output "iout" corresponds to output "iax" of Mapping. To be compatible
- with the previous approach, we want "ret" to be a 1-input (WCS) to
- 1-output (pixel) Mapping in which the input corresponds to output
- "iax" of Mapping. To get "ret" into this form, we first append a PermMap
- to "ret" that selects a single output ("iout"), and then invert the
- whole CmpMap. */
- for( jout = 0; jout < nout; jout++ ) {
- outs[ jout ] = -1;
- }
- outs[ iout ] = 0;
- outperm = iout;
-
- pm = astPermMap( nout, outs, 1, &outperm, NULL, "", status );
- cm = astCmpMap( ret, pm, 1, " ", status );
- (void) astAnnul( ret );
- pm = astAnnul( pm );
- ret = (AstMapping *) cm;
- astInvert( ret );
-
-/* The earlier approach leves ins[ 0 ] holding the index of the input to
- "map" that feeds output iax. Ensure we have this too. */
- ins = outs;
- ins[ 0 ] = iin;
-
-/* Free resources if the current input did not feed the required output. */
- } else {
- outs = astFree( outs );
- ret = astAnnul( ret );
- }
- }
- }
- }
-
-/* If the Mapping still could not be split, try again on a copy of the
- Mapping in which all PermMaps provide an alternative implementation of
- the astMapSplit method. */
- if( !ins ) {
- astInvert( map );
- tmap = astCopy( map );
- ChangePermSplit( tmap, status );
- ins = astMapSplit( tmap, 1, &iax, &ret );
- tmap = astAnnul( tmap );
- astInvert( map );
- }
-
-/* Assume the Mapping cannot be represented by -TAB */
- ok = 0;
-
-/* Check a Mapping was returned by astMapSplit. If so, it will be the
- mapping from the requested output of "map" (the WCS axis) to the
- corresponding input(s) (grid axes). Check only one "map" input feeds the
- requested output. */
- if( ins && ret && astGetNout( ret ) == 1 ) {
-
-/* Invert the Mapping so that the input is grid coord and the output is
- WCS coord. */
- astInvert( ret );
-
-/* We now search the "ret" mapping for a non-inverted LutMap, splitting ret
- up into three serial components: 1) the mappings before the LutMap, 2) the
- LutMap itself, and 3) the mappings following the LutMap. First, decompose
- the mapping into a list of series mappings. */
- map_list = NULL;
- invert_list = NULL;
- nmap = 0;
- astMapList( ret, 1, astGetInvert( ret ), &nmap, &map_list,
- &invert_list );
-
-/* Search the list for a non-inverted LutMap. */
- ilut = -1;
- for( imap = 0; imap < nmap; imap++ ) {
- if( astIsALutMap( map_list[ imap ] ) && !(invert_list[ imap ]) ) {
- ilut = imap;
- break;
- }
- }
-
-/* If a LutMap was found, combine all Mappings before the LutMap into a
- single Mapping. Remember to set the Mapping Invert flags temporarily to
- the values used within the CmpMap. */
- if( ilut >= 0 ) {
- premap = (AstMapping *) astUnitMap( 1, " ", status );
- for( imap = 0; imap < ilut; imap++ ) {
- old_invert = astGetInvert( map_list[ imap ] );
- astSetInvert( map_list[ imap ], invert_list[ imap ] );
- tmap = (AstMapping *) astCmpMap( premap, map_list[ imap ], 1,
- " ", status );
- astSetInvert( map_list[ imap ], old_invert );
- (void) astAnnul( premap );
- premap = tmap;
- }
-
-/* Also combine all Mappings after the LutMap into a single Mapping, setting
- the Mapping Invert flags temporarily to the values used within the
- CmpMap. */
- postmap = (AstMapping *) astUnitMap( 1, " ", status );
- for( imap = ilut + 1; imap < nmap; imap++ ) {
- old_invert = astGetInvert( map_list[ imap ] );
- astSetInvert( map_list[ imap ], invert_list[ imap ] );
- tmap = (AstMapping *) astCmpMap( postmap, map_list[ imap ], 1,
- " ", status );
- astSetInvert( map_list[ imap ], old_invert );
- (void) astAnnul( postmap );
- postmap = tmap;
- }
-
-/* Get the table of values, and other attributes, from the LutMap. */
- lut = astGetLutMapInfo( map_list[ ilut ], &start, &inc, &nlut );
- *interp = astGetLutInterp( map_list[ ilut ] );
-
-/* If required, create a FitsTable to hold the returned table info. */
- if( ! *table ) *table = astFitsTable( NULL, "", status );
- ok = 1;
-
-/* Define the properties of the column in the FitsTable that holds the main
- coordinate array. Points on a WCS axis are described by a single value
- (wavelength, frequency, or whatever), but the coords array has to be
- 2-dimensional, with an initial degenerate axis, as required by FITS-WCS
- paper III. */
- dims[ 0 ] = 1;
- dims[ 1 ] = nlut;
- sprintf( colname, "COORDS%d", iwcs + 1 );
- astAddColumn( *table, colname, AST__DOUBLETYPE, 2, dims, unit );
-
-/* Get the one-based index of the column just added to the table. */
- *icolmain = astGetNcolumn( *table );
-
-/* Get workspace. */
- work1 = astMalloc( nlut*sizeof( double ) );
- if( astOK ) {
-
-/* Transform the LutMap table values using the post-lutmap mapping to
- get the list of WCS values in AST units. */
- astTran1( postmap, nlut, lut, 1, work1 );
-
-/* Convert them to FITS units (e.g. celestial axis values should be
- converted from radians to degrees). */
- for( ilut = 0; ilut < nlut; ilut++ ) work1[ ilut ] *= scale;
-
-/* Store them in row 1, column COORDS, in the FitsTable. */
- sprintf( cellname, "COORDS%d(1)", iwcs + 1 );
- astMapPut1D( *table, cellname, nlut, work1, NULL );
-
-/* Create an array holding the LutMap input value at the centre of each
- table entry. Re-use the "lut" array since we no longer need it. */
- for( ilut = 0; ilut < nlut; ilut++ ) {
- lut[ ilut ] = start + ilut*inc;
- }
-
-/* Transform this array using the inverted pre-lutmap mapping to get the
- list of grid coord. */
- astTran1( premap, nlut, lut, 0, work1 );
-
-/* Test this list to see if they form a unit index (i.e. index(i) == i+1 ).
- (not the "+1" is due to the fact that "i" is zero based). */
- for( ilut = 0; ilut < nlut; ilut++ ) {
- if( fabs( work1[ ilut ] - ilut - 1.0 ) > 1.0E-6 ) break;
- }
-
-/* if it is not a unit index, we add the index to the table. */
- if( ilut < nlut ) {
-
-/* Define the properties of the column in the FitsTable that holds the
- indexing vector. */
- sprintf( colname, "INDEX%d", iwcs + 1 );
- astAddColumn( *table, colname, AST__DOUBLETYPE, 1, &nlut, " " );
-
-/* Get the one-based index of the column just added to the table. */
- *icolindex = astGetNcolumn( *table );
-
-/* Store the values in the column. */
- sprintf( cellname, "INDEX%d(1)", iwcs + 1 );
- astMapPut1D( *table, cellname, nlut, work1, NULL );
- }
- }
-
-/* Free resources. */
- work1 = astFree( work1 );
- lut = astFree( lut );
- premap = astAnnul( premap );
- postmap = astAnnul( postmap );
-
-/* If no LutMap was found in the Mapping, then we can create a FitsTable
- by sampling the full WCS Mapping at selected input (i.e. grid)
- positions. But we can only do this if we know the number of pixels
- along the WCS axis. */
- } else if( dim[ ins[ 0 ] ] != AST__BAD ) {
-
-/* Create two works array each holding a single value. The first holds
- the grid coords at which the samples are taken. The second holds the
- WCS coords at the sampled positions. These arrays are expanded as
- required within function AdaptLut. */
- work1 = astMalloc( sizeof( double ) );
- work2 = astMalloc( sizeof( double ) );
- if( astOK ) {
-
-/* Get the WCS values at the centres of the first and last pixel on
- the WCS axis. */
- x[ 0 ] = 1.0;
- x[ 1 ] = dim[ ins[ 0 ] ];
- astTran1( ret, 2, x, 1, v );
-
-/* Put the lower limit into the work arrays. */
- work1[ 0 ] = x[ 0 ];
- work2[ 0 ] = v[ 0 ];
- nlut = 1;
-
-/* Expand the arrays by sampling the WCS axis adaptively so that
- more samples occur where the WCS value is changing most rapidly.
- We require the maximum error introduced by the table to be 0.25 pixels. */
- AdaptLut( ret, 3, 0.25, x[ 0 ], x[ 1 ], v[ 0 ], v[ 1 ],
- &work1, &work2, &nlut, status );
-
-/* Create a FitsTable to hold the returned table info. */
- if( ! *table ) *table = astFitsTable( NULL, "", status );
- ok = 1;
-
-/* Define the properties of the column in the FitsTable that holds the main
- coordinate array. */
- sprintf( colname, "COORDS%d", iwcs + 1 );
- dims[ 0 ] = 1;
- dims[ 1 ] = nlut;
- astAddColumn( *table, colname, AST__DOUBLETYPE, 2, dims, unit );
- *icolmain = astGetNcolumn( *table );
-
-/* Convert the axis values to FITS units (e.g. celestial axis values should be
- converted from radians to degrees). */
- for( ilut = 0; ilut < nlut; ilut++ ) work2[ ilut ] *= scale;
-
-/* Store the scaled axis values in row 1 of the column. */
- sprintf( cellname, "COORDS%d(1)", iwcs + 1 );
- astMapPut1D( *table, cellname, nlut, work2, NULL );
-
-/* Test the index vector to see if they form a unit index (i.e. index(i) ==
- i+1 ). If not the "+1" is due to the fact that "i" is zero based). If not, store
- them as the index vector in the FitsTable. */
- for( ilut = 0; ilut < nlut; ilut++ ) {
- if( fabs( work1[ ilut ] - ilut - 1.0 ) > 1.0E-6 ) break;
- }
-
-/* If the index vector is not a unit index, define the properties of the
- column in the FitsTable that holds the indexing vector. Then store values
- in row 1 of the column. */
- if( ilut < nlut ) {
- sprintf( colname, "INDEX%d", iwcs + 1 );
- astAddColumn( *table, colname, AST__DOUBLETYPE, 1, &nlut, " " );
- *icolindex = astGetNcolumn( *table );
- sprintf( cellname, "INDEX%d(1)", iwcs + 1 );
- astMapPut1D( *table, cellname, nlut, work1, NULL );
- }
- }
-
-/* Free resources */
- work1 = astFree( work1 );
- work2 = astFree( work2 );
- }
-
-/* If columns were added to the table, invert the returned Mapping again
- so that the input is wcs coord and the output is grid coord. Otherwise,
- annul the returned Mapping. */
- if( ok ) {
- astInvert( ret );
- } else {
- ret = astAnnul( ret );
- }
-
-/* Loop to annul all the Mapping pointers in the list. */
- for ( imap = 0; imap < nmap; imap++ ) map_list[ imap ] = astAnnul( map_list[ imap ] );
-
-/* Free the dynamic arrays. */
- map_list = astFree( map_list );
- invert_list = astFree( invert_list );
- }
-
-/* Free resources. */
- ins = astFree( ins );
-
-/* If an error occurred, free the returned Mapping. */
- if( !astOK ) ret = astAnnul( ret );
-
-/* Return the result. */
- return ret;
-}
-
-static AstMapping *IsMapTab2D( AstMapping *map, double scale, const char *unit,
- AstFrame *wcsfrm, double *dim, int iax1,
- int iax2, int iwcs1, int iwcs2,
- AstFitsTable **table, int *icolmain1,
- int *icolmain2, int *icolindex1,
- int *icolindex2, int *max1, int *max2,
- int *interp1, int *interp2, int *status ){
-/*
-* Name:
-* IsMapTab2D
-
-* Purpose:
-* See if a specified pair of Mapping outputs are related to a pair of
-* Mapping inputs via a FITS -TAB algorithm.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *IsMapTab2D( AstMapping *map, double scale, const char *unit,
-* AstFrame *wcsfrm, double *dim, int iax1,
-* int iax2, int iwcs1, int iwcs2,
-* AstFitsTable **table, int *icolmain1,
-* int *icolmain2, int *icolindex1,
-* int *icolindex2, int *max1, int *max2,
-* int *interp1, int *interp2, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A specified pair of outputs axes of the supplied Mapping are tested
-* to see if they can be represented by the -TAB alogirithm described in
-* FITS-WCS paper III. If the test is passed, a Mapping is returned from
-* the specified WCS axes to the corresponding psi axes. A FitsTable is
-* also created holding the information to be stored in the corresponding
-* FITS binary table. Note, when creating a header, AST assumes a unit
-* transformaton between psi axes and grid axes (psi axes are defined
-* in FITS-WCS paper III section 6.1.2).
-
-* Parameters:
-* map
-* Pointer to the Mapping from pixel coords to WCS coords.
-* scale
-* A scale factor by which to multiply the axis values stored in the
-* returned FitsTable. Note, the returned Mapping is unaffected by
-* this scaling factor.
-* unit
-* A unit string for the axis values. If supplied, the same
-* string is stored for both axes. If NULL, the unit strings are
-* extracted from the relavent axes of the supplied WCS Frame.
-* wcsfrm
-* Pointer to a Frame describing WCS coords.
-* dim
-* An array holding the array dimensions in pixels. AST__BAD should
-* be supplied for any unknown dimensions.
-* iax1
-* The zero-based index of the first Mapping output which is to be
-* checked.
-* iax2
-* The zero-based index of the second Mapping output which is to be
-* checked.
-* iwcs1
-* The zero-based index of the FITS WCS axis corresponding to "iax1".
-* iwcs2
-* The zero-based index of the FITS WCS axis corresponding to "iax2".
-* table
-* Pointer to a location holding a pointer to the FitsTable describing
-* the -TAB look-up table. If "*table" is NULL on entry, a new
-* FitsTable will be created and returned, otherwise the supplied
-* FitsTable is used.
-* icolmain1
-* The one-based index of the column within "*table" that holds the
-* main coord array for the first Mapping output.
-* icolmain2
-* The one-based index of the column within "*table" that holds the
-* main coord array for the second Mapping output.
-* icolindex1
-* The one-based index of the column within "*table" that holds the
-* index vector for the first Mapping output. Returned equal to -1
-* if no index is added to the table (e.g. because the index is a
-* unit index).
-* icolindex2
-* The one-based index of the column within "*table" that holds the
-* index vector for the second Mapping output. Returned equal to -1
-* if no index is added to the table (e.g. because the index is a
-* unit index).
-* max1
-* The one-based index of the dimension describing the first Mapping
-* output within the main coord array specified by "icolmain1".
-* max2
-* The one-based index of the dimension describing the second Mapping
-* output within the main coord array specified by "icolmain1".
-* interp1
-* The interpolation method (0=linear, other=nearest neighbour) for
-* the first mapping output.
-* interp2
-* The interpolation method (0=linear, other=nearest neighbour) for
-* the second mapping output.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* If the specified "map" outputs can be described using the -TAB
-* algorithm of FITS-WCS paper III, then a 2-input/2-output Mapping
-* from the specified WCS axes to the corresponding psi axes (i.e.
-* grid axes) is returned. NULL is returned otherwise, of if an error
-* occurs.
-*/
-
-/* Local Variables: */
- AstMapping *ret1; /* WCS->IWC Mapping for first output */
- AstMapping *ret2; /* WCS->IWC Mapping for second output */
- AstMapping *ret; /* Returned WCS axis Mapping */
- AstMapping *tmap;
- AstPermMap *pm;
- int *pix_axes; /* Zero-based indices of corresponding pixel axes */
- int wcs_axes[ 2 ]; /* Zero-based indices of selected WCS axes */
- int inperm[ 1 ];
- int outperm[ 2 ];
-
-/* Initialise */
- ret = NULL;
-
-/* Check inherited status */
- if( !astOK ) return ret;
-
-/* First see if the two required Mapping outputs are separable, in which case
- they can be described by two 1D tables. */
- ret1 = IsMapTab1D( map, scale, unit, wcsfrm, dim, iax1, iwcs1, table, icolmain1,
- icolindex1, interp1, status );
- ret2 = IsMapTab1D( map, scale, unit, wcsfrm, dim, iax2, iwcs2, table, icolmain2,
- icolindex2, interp2, status );
-
-/* If both outputs are seperable... */
- if( ret1 && ret2 ) {
-
-/* Both axes are stored as the first dimension in the corresponding main
- coords array. */
- *max1 = 1;
- *max2 = 1;
-
-/* Get a Mapping from the required pair of WCS axes to the corresponding
- pair of grid axes. First try to split the supplied grid->wcs mapping. */
- wcs_axes[ 0 ] = iax1;
- wcs_axes[ 1 ] = iax2;
-
- astInvert( map );
- pix_axes = astMapSplit( map, 2, wcs_axes, &ret );
- astInvert( map );
-
- if( pix_axes ) {
- pix_axes = astFree( pix_axes );
- if( astGetNout( ret ) > 2 ) {
- ret = astAnnul( ret );
-
-/* If the two output WCS axes are fed by the same grid axis, we need to
- add another pixel axis to form the pair. */
- } else if( astGetNout( ret ) == 1 ) {
- inperm[ 0 ] = 0;
- outperm[ 0 ] = 0;
- outperm[ 1 ] = 0;
- pm = astPermMap( 1, inperm, 2, outperm, NULL, " ", status );
- tmap = (AstMapping *) astCmpMap( ret, pm, 1, " ", status );
- ret = astAnnul( ret );
- pm = astAnnul( pm );
- ret = tmap;
- }
- }
-
-/* If this was unsuccessful, combine the Mappings returned by IsMapTab1D.
- We only do this if the above astMapSplit call failed, since the IsMapTab1D
- mappings may well not be independent of each other, and we may end up
- sticking together in parallel two mappings that are basically the same
- except for ending with PermMapa that select different axes. Is is hard
- then to simplify such a parallel CmpMap back into the simpler form
- that uses only one of the two identical mappings, without a PermMap. */
- if( !ret ) {
- ret = (AstMapping *) astCmpMap( ret1, ret2, 0, " ", status );
- }
-
-/* Free resources. */
- ret1 = astAnnul( ret1 );
- ret2 = astAnnul( ret2 );
-
-/* If only one output is separable, remove the corresponding columns from
- the returned table. */
- } else if( ret1 ) {
- ret1 = astAnnul( ret1 );
- astRemoveColumn( *table, astColumnName( *table, *icolmain1 ) );
- if( icolindex1 >= 0 ) astRemoveColumn( *table, astColumnName( *table, *icolindex1 ) );
- } else if( ret2 ) {
- ret2 = astAnnul( ret2 );
- astRemoveColumn( *table, astColumnName( *table, *icolmain2 ) );
- if( icolindex1 >= 0 ) astRemoveColumn( *table, astColumnName( *table, *icolindex2 ) );
- }
-
-/* If the required Mapping outputs were not separable, create a single
- 2D coords array describing both outputs. */
- if( !ret ) {
-
-/* TO BE DONE... Until then non-separable Mappings will result in a
- failure to create a -TAB header. No point in doing this until AST has
- an N-dimensional LutMap class (otherwise AST could never read the
- resulting FITS header). */
- }
-
-/* If an error occurred, free the returned Mapping. */
- if( !astOK ) ret = astAnnul( ret );
-
-/* Return the result. */
- return ret;
-}
-
-static int IsAIPSSpectral( const char *ctype, char **wctype, char **wspecsys, int *status ){
-/*
-* Name:
-* IsAIPSSpectral
-
-* Purpose:
-* See if a given CTYPE value describes a FITS-AIPS spectral axis.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int IsAIPSSpectral( const char *ctype, char **wctype, char **wspecsys, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The given CTYPE value is checked to see if it conforms to the
-* requirements of a spectral axis CTYPE value as specified by
-* FITS-AIPS encoding. If so, the equivalent FITS-WCS CTYPE and
-* SPECSYS values are returned.
-
-* Parameters:
-* ctype
-* Pointer to a null terminated string holding the CTYPE value to
-* check.
-* wctype
-* The address of a location at which to return a pointer to a
-* static string holding the corresponding FITS-WCS CTYPE value. A
-* NULL pointer is returned if the supplied CTYPE string is not an
-* AIPS spectral CTYPE value.
-* wspecsys
-* The address of a location at which to return a pointer to a
-* static string holding the corresponding FITS-WCS SPECSYS value. A
-* NULL pointer is returned if the supplied CTYPE string is not an
-* AIPS spectral CTYPE value.
-* status
-* Pointer to the inherited status variable.
-
-* Retuned Value:
-* Non-zero fi the supplied CTYPE was an AIPS spectral CTYPE value.
-
-* Note:
-* - These translations are also used by the FITS-CLASS encoding.
-*/
-
-/* Local Variables: */
- int ret;
-
-/* Initialise */
- ret = 0;
- *wctype = NULL;
- *wspecsys = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* If the length of the string is not 8, then it is not an AIPS spectral axis. */
- if( strlen( ctype ) == 8 ) {
-
-/* Translate AIPS spectral CTYPE values to FITS-WCS paper III equivalents.
- These are of the form AAAA-BBB, where "AAAA" can be "FREQ", "VELO" (=VRAD!)
- or "FELO" (=VOPT-F2W), and BBB can be "LSR", "LSD", "HEL" (=*Bary*centric!)
- or "GEO". */
- if( !strncmp( ctype, "FREQ", 4 ) ){
- *wctype = "FREQ ";
- } else if( !strncmp( ctype, "VELO", 4 ) ){
- *wctype = "VRAD ";
- } else if( !strncmp( ctype, "FELO", 4 ) ){
- *wctype = "VOPT-F2W";
- } else if( !strncmp( ctype, "WAVELENG", 8 ) ){
- *wctype = "WAVE ";
- }
- if( !strcmp( ctype + 4, "-LSR" ) ){
- *wspecsys = "LSRK";
- } else if( !strcmp( ctype + 4, "LSRK" ) ){
- *wspecsys = "LSRK";
- } else if( !strcmp( ctype + 4, "-LSRK" ) ){
- *wspecsys = "LSRK";
- } else if( !strcmp( ctype + 4, "-LSD" ) ){
- *wspecsys = "LSRD";
- } else if( !strcmp( ctype + 4, "-HEL" ) ){
- *wspecsys = "BARYCENT";
- } else if( !strcmp( ctype + 4, "-EAR" ) || !strcmp( ctype + 4, "-GEO" ) ){
- *wspecsys = "GEOCENTR";
- } else if( !strcmp( ctype + 4, "-OBS" ) || !strcmp( ctype + 4, "-TOP" ) ){
- *wspecsys = "TOPOCENT";
- }
- if( *wctype && *wspecsys ) {
- ret = 1;
- } else {
- *wctype = NULL;
- *wspecsys = NULL;
- }
- }
-
-/* Return the result. */
- return ret;
-}
-
-static int IsSkyOff( AstFrameSet *fset, int iframe, int *status ){
-/*
-* Name:
-* IsSkyOff
-
-* Purpose:
-* See if a given Frame contains an offset SkyFrame.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int IsSkyOff( AstFrameSet *fset, int iframe, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns a flag indicating if the specified Frame within the
-* supplied FrameSet is, or contains, a SkyFrame that represents
-* offset coordinates. This is the case if the Frame is a SkyFrame
-* and its SkyRefIs attribute is "Pole" or "Origin", or is a CmpFrame
-* containing such a SkyFrame.
-
-* Parameters:
-* fset
-* The FrameSet.
-* iframe
-* Index of the Frame to check within "fset"
-* status
-* Pointer to the inherited status variable.
-
-* Retuned Value:
-* +1 if the Frame is an offset SkyFrame. Zero otherwise.
-
-* Notes:
-* - Zero is returned if an error has already occurred.
-*/
-
-/* Local Variables: */
- AstFrame *frm;
- const char *skyrefis;
- int oldrep;
- int result;
-
-/* Initialise. */
- result = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return result;
-
-/* Get a pointer to the required Frame in the FrameSet */
- frm = astGetFrame( fset, iframe );
-
-/* Since the current Frame may not contain a SkyFrame, we temporarily
- switch off error reporting. */
- oldrep = astReporting( 0 );
-
-/* Get the SkyRefIs attribute value. */
- skyrefis = astGetC( frm, "SkyRefIs" );
-
-/* If it is "Pole" or "Origin", return 1. */
- if( skyrefis && ( !Ustrcmp( skyrefis, "POLE", status ) ||
- !Ustrcmp( skyrefis, "ORIGIN", status ) ) ) result = 1;
-
-/* Cancel any error and switch error reporting back on again. */
- astClearStatus;
- astReporting( oldrep );
-
-/* Annul the Frame pointer. */
- frm = astAnnul( frm );
-
-/* Return the result. */
- return result;
-}
-
-static const char *IsSpectral( const char *ctype, char stype[5], char algcode[5], int *status ) {
-/*
-* Name:
-* IsSpectral
-
-* Purpose:
-* See if a given FITS-WCS CTYPE value describes a spectral axis.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* char *IsSpectral( const char *ctype, char stype[5], char algcode[5], int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The given CTYPE value is checked to see if it conforms to the
-* requirements of a spectral axis CTYPE value as specified by
-* FITS-WCS paper 3. If so, the spectral system and algorithm codes
-* are extracted from it and returned, together with the default units
-* for the spectral system.
-
-* Parameters:
-* ctype
-* Pointer to a null terminated string holding the CTYPE value to
-* check.
-* stype
-* An array in which to return the null-terminated spectral system type
-* (e.g. "FREQ", "VELO", "WAVE", etc). A null string is returned if
-* the CTYPE value does not describe a spectral axis.
-* algcode
-* An array in which to return the null-terminated algorithm code
-* (e.g. "-LOG", "", "-F2W", etc). A null string is returned if the
-* spectral axis is linear. A null string is returned if the CTYPE
-* value does not describe a spectral axis.
-* status
-* Pointer to the inherited status variable.
-
-* Retuned Value:
-* A point to a static string holding the default units associated
-* with the spectral system specified by the supplied CTYPE value.
-* NULL is returned if the CTYPE value does not describe a spectral
-* axis.
-
-* Notes:
-* - The axis is considered to be a spectral axis if the first 4
-* characters form one of the spectral system codes listed in FITS-WCS
-* paper 3. The algorithm code is not checked, except to ensure that
-* it begins with a minus sign, or is blank.
-* - A NULL pointer is returned if an error has already occurred.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS
- int ctype_len;
-
-/* Initialise */
- stype[ 0 ] = 0;
- algcode[ 0 ] = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return NULL;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(NULL);
-
-/* Initialise more stuff */
- isspectral_ret = NULL;
-
-/* If the length of the string is less than 4, then it is not a spectral
- axis. */
- ctype_len = strlen( ctype );
- if( ctype_len >= 4 ) {
-
-/* Copy the first 4 characters (the coordinate system described by the
- axis) into a null-terminated buffer. */
- strncpy( stype, ctype, 4 );
- stype[ 4 ] = 0;
- stype[ astChrLen( stype ) ] = 0;
-
-/* Copy any remaining characters (the algorithm code) into a null-terminated
- buffer. Only copy a maximum of 4 characters. */
- if( ctype_len > 4 ) {
- if( ctype_len <= 8 ) {
- strcpy( algcode, ctype + 4 );
- } else {
- strncpy( algcode, ctype + 4, 4 );
- algcode[ 4 ] = 0;
- }
- algcode[ astChrLen( algcode ) ] = 0;
- } else {
- algcode[ 0 ] = 0;
- }
-
-/* See if the first 4 characters of the CTYPE value form one of the legal
- spectral coordinate type codes listed in FITS-WCS Paper III. Also note
- the default units associated with the system. */
- if( !strcmp( stype, "FREQ" ) ) {
- isspectral_ret = "Hz";
- } else if( !strcmp( stype, "ENER" ) ) {
- isspectral_ret = "J";
- } else if( !strcmp( stype, "WAVN" ) ) {
- isspectral_ret = "/m";
- } else if( !strcmp( stype, "VRAD" ) ) {
- isspectral_ret = "m/s";
- } else if( !strcmp( stype, "WAVE" ) ) {
- isspectral_ret = "m";
- } else if( !strcmp( stype, "VOPT" ) ) {
- isspectral_ret = "m/s";
- } else if( !strcmp( stype, "ZOPT" ) ) {
- isspectral_ret = "";
- } else if( !strcmp( stype, "AWAV" ) ) {
- isspectral_ret = "m";
- } else if( !strcmp( stype, "VELO" ) ) {
- isspectral_ret = "m/s";
- } else if( !strcmp( stype, "BETA" ) ) {
- isspectral_ret = "";
- }
-
-/* Also check that the remaining part of CTYPE (the algorithm code) begins
- with a minus sign or is blank. */
- if( algcode[ 0 ] != '-' && strlen( algcode ) > 0 ) isspectral_ret = NULL;
- }
-
-/* Return null strings if the axis is not a spectral axis. */
- if( ! isspectral_ret ) {
- stype[ 0 ] = 0;
- algcode[ 0 ] = 0;
- }
-
-/* Return the result. */
- return isspectral_ret;
-}
-
-static AstMapping *LinearWcs( FitsStore *store, int i, char s,
- const char *method, const char *class, int *status ) {
-/*
-* Name:
-* LinearWcs
-
-* Purpose:
-* Create a Mapping describing a FITS-WCS linear algorithm
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *LinearWcs( FitsStore *store, int i, char s,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function uses the contents of the supplied FitsStore to create
-* a Mapping which goes from Intermediate World Coordinate (known as "w"
-* in the context of FITS-WCS paper III) to a linearly related axis.
-*
-* The returned Mapping is a ShiftMap which simply adds on the value of
-* CRVALi.
-
-* Parameters:
-* store
-* Pointer to the FitsStore structure holding the values to use for
-* the WCS keywords.
-* i
-* The zero-based index of the spectral axis within the FITS header
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to a Mapping, or NULL if an error occurs.
-*/
-
-/* Local Variables: */
- AstMapping *ret;
- double crv;
-
-/* Check the global status. */
- ret = NULL;
- if( !astOK ) return ret;
-
-/* Get the CRVAL value for the specified axis. */
- crv = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( crv == AST__BAD ) crv = 0.0;
-
-/* Create a 1D ShiftMap which adds this value onto the IWCS value. */
- if( crv != 0.0 ) {
- ret = (AstMapping *) astShiftMap( 1, &crv, "", status );
- } else {
- ret = (AstMapping *) astUnitMap( 1, "", status );
- }
- return ret;
-}
-
-static AstMapping *LogAxis( AstMapping *map, int iax, int nwcs, double *lbnd_p,
- double *ubnd_p, double crval, int *status ){
-/*
-* Name:
-* LogAxes
-
-* Purpose:
-* Test a Frame axis to see if it logarithmically spaced in pixel coords.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *LogAxis( AstMapping *map, int iax, int nwcs, double *lbnd_p,
-* double *ubnd_p, double crval )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A specified axis of the supplied Mappinhg is tested to see if it
-* corresponds to the form
-*
-* S = Sr.exp( w/Sr )
-*
-* where "w" is one of the Mapping inputs, "S" is the specified
-* Mapping output, and "Sr" is the supplied value of "crval". This
-* is the form for a FITS log axis as defined in FITS-WCS paper III.
-*
-* If the above test is passed, a Mapping is returned from "S" to "w"
-* (the inverseof the above expression).
-
-* Parameters:
-* map
-* Pointer to the Mapping. This will usually be a Mapping from
-* pixel coords to WCS coords.
-* iax
-* The index of the output of "map" which correspoinds to "S".
-* nwcs
-* The number of outputs from "map".
-* lbnd_p
-* Pointer to an array of double, with one element for each
-* Mapping input coordinate. This should contain the lower bound
-* of the input pixel box in each input dimension.
-* ubnd_p
-* Pointer to an array of double, with one element for each
-* Mapping input coordinate. This should contain the upper bound
-* of the input pixel box in each input dimension.
-* crval
-* The reference value ("Sr") to use. Must not be zero.
-
-* Returned Value:
-* If the specified axis is logarithmically spaced, a Mapping with
-* "nwcs" inputs and "nwcs" outputs is returned. This Mapping transforms
-
-* its "iax"th input using the transformation:
-*
-* w = Sr.Log( S/Sr )
-*
-* (where "S" is the Mapping is the "iax"th input and "w" is the
-* "iax"th output). Other inputs are copied to the corresponding
-* output without change. NULL is returned if the specified axis is
-* not logarithmically spaced.
-*/
-
-/* Local Variables: */
- AstMapping *result; /* Returned Mapping */
- AstMapping *tmap0; /* A temporary Mapping */
- AstMapping *tmap1; /* A temporary Mapping */
- AstMapping *tmap2; /* A temporary Mapping */
- AstMapping *tmap3; /* A temporary Mapping */
- AstMapping *tmap4; /* A temporary Mapping */
- const char *fexps[ 1 ]; /* Forward MathMap expressions */
- const char *iexps[ 1 ]; /* Inverse MathMap expressions */
-
-/* Initialise */
- result = NULL;
-
-/* Check the inherited status and crval value. */
- if( !astOK || crval == 0.0 ) return result;
-
-/* If the "log" algorithm is appropriate, the supplied axis (s) is related
- to pixel coordinate (p) by s = Sr.EXP( a*p - b ). If this is the case,
- then the log of s will be linearly related to pixel coordinates. To test
- this, we create a CmpMap which produces log(s). */
- fexps[ 0 ] = "logs=log(s)";
- iexps[ 0 ] = "s=exp(logs)";
- tmap1 = (AstMapping *) astMathMap( 1, 1, 1, fexps, 1, iexps,
- "simpfi=1,simpif=1", status );
- tmap2 = AddUnitMaps( tmap1, iax, nwcs, status );
- tmap0 = (AstMapping *) astCmpMap( map, tmap2, 1, "", status );
- tmap2 = astAnnul( tmap2 );
-
-/* See if this Mapping is linear. */
- if( IsMapLinear( tmap0, lbnd_p, ubnd_p, iax, status ) ) {
-
-/* Create the Mapping which defines the IWC axis. This is the Mapping from
- WCS to IWCS - "W = Sr.log( S/Sr )". Other axes are left unchanged by the
- Mapping. The IWC axis has the same axis index as the WCS axis. */
- tmap2 = (AstMapping *) astZoomMap( 1, 1.0/crval, "", status );
- tmap3 = (AstMapping *) astCmpMap( tmap2, tmap1, 1, "", status );
- tmap2 = astAnnul( tmap2 );
- tmap2 = (AstMapping *) astZoomMap( 1, crval, "", status );
- tmap4 = (AstMapping *) astCmpMap( tmap3, tmap2, 1, "", status );
- tmap3 = astAnnul( tmap3 );
- tmap2 = astAnnul( tmap2 );
- result = AddUnitMaps( tmap4, iax, nwcs, status );
- tmap4 = astAnnul( tmap4 );
- }
-
-/* Free resources. */
- tmap0 = astAnnul( tmap0 );
- tmap1 = astAnnul( tmap1 );
-
-/* Return the result. */
- return result;
-}
-
-static AstMapping *LogWcs( FitsStore *store, int i, char s,
- const char *method, const char *class, int *status ) {
-/*
-* Name:
-* LogWcs
-
-* Purpose:
-* Create a Mapping describing a FITS-WCS logarithmic algorithm
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *LogWcs( FitsStore *store, int i, char s,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function uses the contents of the supplied FitsStore to create
-* a Mapping which goes from Intermediate World Coordinate (known as "w"
-* in the context of FITS-WCS paper III) to a logarthmic version of w
-
-* called "S" given by:
-*
-* S = Sr.exp( w/Sr )
-*
-* where Sr is the value of S corresponding to w=0.
-
-* Parameters:
-* store
-* Pointer to the FitsStore structure holding the values to use for
-* the WCS keywords.
-* i
-* The zero-based index of the axis within the FITS header
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to a Mapping, or NULL if an error occurs.
-*/
-
-/* Local Variables: */
- AstMapping *ret;
- char forexp[ 12 + DBL_DIG*2 ];
- char invexp[ 12 + DBL_DIG*2 ];
- const char *fexps[ 1 ];
- const char *iexps[ 1 ];
- double crv;
-
-/* Check the global status. */
- ret = NULL;
- if( !astOK ) return ret;
-
-/* Get the CRVAL value for the specified axis. Use a default of zero. */
- crv = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( crv == AST__BAD ) crv = 0.0;
-
-/* Create the MathMap, if possible. */
- if( crv != 0.0 ) {
- sprintf( forexp, "s=%.*g*exp(w/%.*g)", DBL_DIG, crv, DBL_DIG, crv );
- sprintf( invexp, "w=%.*g*log(s/%.*g)", DBL_DIG, crv, DBL_DIG, crv );
- fexps[ 0 ] = forexp;
- iexps[ 0 ] = invexp;
- ret = (AstMapping *) astMathMap( 1, 1, 1, fexps, 1, iexps, "simpfi=1,simpif=1", status );
- }
-
-/* Return the result */
- return ret;
-}
-
-static int LooksLikeClass( AstFitsChan *this, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* LooksLikeClass
-
-* Purpose:
-* Does the FitsChan seem to use FITS-CLASS encoding?
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int LooksLikeClass( AstFitsChan *this, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns non-zero if the supplied FitsChan probably uses FITS-CLASS
-* encoding. This is the case if it contains a DELTAV keyword and a
-* keyword of the form VELO-xxx", where xxx is one of the accepted
-* standards of rest, or "VLSR".
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* 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:
-* Non-zero if the encoding in use lookslike FITS-CLASS.
-*/
-
-/* Local Variables... */
- int ret; /* Returned value */
-
-/* Initialise */
- ret = 0;
-
-/* Check the global status. */
- if( !astOK ) return ret;
-
-/* See if there is a "DELTAV" card, and a "VELO-xxx" or "VLSR" card. */
- if( astKeyFields( this, "DELTAV", 0, NULL, NULL ) && (
- astKeyFields( this, "VLSR", 0, NULL, NULL ) ||
- astKeyFields( this, "VELO-OBS", 0, NULL, NULL ) ||
- astKeyFields( this, "VELO-HEL", 0, NULL, NULL ) ||
- astKeyFields( this, "VELO-EAR", 0, NULL, NULL ) ||
- astKeyFields( this, "VELO-LSR", 0, NULL, NULL ) ) ) {
- ret = 1;
- }
-
-/* Return the result. */
- return ret;
-}
-
-static void MakeBanner( const char *prefix, const char *middle,
- const char *suffix,
- char banner[ AST__FITSCHAN_FITSCARDLEN -
- FITSNAMLEN + 1 ], int *status ) {
-/*
-* Name:
-* MakeBanner
-
-* Purpose:
-* Create a string containing a banner comment.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void MakeBanner( const char *prefix, const char *middle,
-* const char *suffix,
-* char banner[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ], int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function creates a string which can be written as a FITS
-* comment card to produce a banner heading (or tail) for an AST
-* Object when it is written to a FitsChan. The banner will occupy
-* the maximum permitted width for text in a FITS comment card.
-
-* Parameters:
-* prefix
-* A pointer to a constant null-terminated string containing the
-* first part of the text to appear in the banner.
-* middle
-* A pointer to a constant null-terminated string containing the
-* second part of the text to appear in the banner.
-* suffix
-* A pointer to a constant null-terminated string containing the
-* third part of the text to appear in the banner.
-* banner
-* A character array to receive the null-terminated result string.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - The text to appear in the banner is constructed by
-* concatenating the three input strings supplied.
-*/
-
-/* Local Variables: */
- char token[] = "AST"; /* Identifying token */
- int i; /* Loop counter for input characters */
- int len; /* Number of output characters */
- int ltok; /* Length of token string */
- int mxlen; /* Maximum permitted output characters */
- int start; /* Column number where text starts */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Calculate the maximum number of characters that the output banner
- can hold and the length of the token string. */
- mxlen = AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN;
- ltok = (int) strlen( token );
-
-/* Calculate the column in which to start the text, so that it is
- centred in the banner (with 4 non-text characters on each side). */
- start = ltok + 2 + ( mxlen - ltok - 1 -
- (int) ( strlen( prefix ) +
- strlen( middle ) +
- strlen( suffix ) ) - 1 - ltok ) / 2;
- if ( start < ltok + 2 ) start = ltok + 2;
-
-/* Start building the banner with the token string. */
- len = 0;
- for ( i = 0; token[ i ] && ( len < mxlen ); i++ ) {
- banner[ len++ ] = token[ i ];
- }
-
-/* Then pad with spaces up to the start of the text. */
- while ( len < start - 1 ) banner[ len++ ] = ' ';
-
-/* Insert the prefix data, truncating it if it is too long. */
- for ( i = 0; prefix[ i ] && ( len < mxlen - ltok - 1 ); i++ ) {
- banner[ len++ ] = prefix[ i ];
- }
-
-/* Insert the middle data, truncating it if it is too long. */
- for ( i = 0; middle[ i ] && ( len < mxlen - ltok - 1 ); i++ ) {
- banner[ len++ ] = middle[ i ];
- }
-
-/* Insert the suffix data, truncating it if it is too long. */
- for ( i = 0; suffix[ i ] && ( len < mxlen - ltok - 1 ); i++ ) {
- banner[ len++ ] = suffix[ i ];
- }
-
-/* Pad the end of the text with spaces. */
- while ( len < mxlen - ltok ) banner[ len++ ] = ' ';
-
-/* Finish the banner with the token string. */
- for ( i = 0; token[ i ] && ( len < mxlen ); i++ ) {
- banner[ len++ ] = token[ i ];
- }
-
-/* Terminate the output string. */
- banner[ len ] = '\0';
-}
-
-static AstMapping *MakeColumnMap( AstFitsTable *table, const char *col,
- int isindex, int interp, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* MakeColumnMap
-
-* Purpose:
-* Create a Mapping describing a look-up table supplied in a cell of a
-* FITS binary table.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *MakeColumnMap( AstFitsTable *table, const char *col,
-* int isindex, int interp, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns a Mapping representing the array of values
-* stored in row 1 of a named column of a supplied FitsTable. The
-* array of values is treated as a look-up table following the prescription
-* of FITS-WCS paper III (the "-TAB" algorithm). If the array has (N+1)
-* dimensions (where N is one or more), the returned Mapping has N
-* inputs and N outputs. The inputs correspond to FITS GRID coords
-* within the array. FITS-WCS paper III requires that the first dimension
-* in the array has a length of "N" and contains the N output values
-* at each input values.
-
-* Parameters:
-* table
-* Pointer to the Fitstable.
-* col
-* A string holding the name of the column to use.
-* isindex
-* Non-zero if the column hold an index array, zero if it holds a
-* coordinate array.
-* interp
-* The value to use for the Interp attribute of the LutMap. A value
-* of zero tells the LutMap class to use linear interpolation. Other
-* values tell the LutMap class to use nearest neighbour interpolation.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the Mapping, or NULL if an error occurs.
-*/
-
-/* Local Variables: */
- AstMapping *result;
- char *key;
- double *lut;
- int *dims;
- int ndim;
- int nel;
-
-/* Initialise */
- result = NULL;
-
-/* Check the inherited status */
- if( !astOK ) return result;
-
-/* Get the number of dimensions spanned by the value in the named column. */
- ndim = astGetColumnNdim( table, col );
-
-/* First deal with index vectors. */
- if( isindex ) {
-
-/* FITS-WCS paper II mandates that index arrays must be 1-dimensional. */
- if( ndim != 1 && astOK ) {
- astError( AST__BADTAB, "%s(%s): Column '%s' has %d dimensions but it "
- "holds an index vector and should therefore be 1-dimensional.",
- status, method, class, col, ndim );
- }
-
-/* Get the length of the index vector. */
- nel = astGetColumnLength( table, col );
-
-/* Allocate memory to hold the array values, and to hold the cell key. */
- lut = astMalloc( nel*sizeof( double ) );
- key = astMalloc( strlen( col ) + 5 );
- if( astOK ) {
-
-/* Create the key for the table cell holding the required array. FITS-WCS
- paper III mandates that tables always occur in the first row of the
- table (and that the table only has one row). Ignore trailing spaces in
- the column name. */
- sprintf( key, "%.*s(1)", (int) astChrLen( col ), col );
-
-/* Copy the array values into the above memory. */
- if( astMapGet1D( table, key, nel, &nel, lut ) ) {
-
-/* Create a 1D LutMap. FITS-WCS paper III (sec 6.1.2) mandates that the input
- corresponds to FITS grid coord (i.e. 1.0 at the centre of the first entry).
- Ensure the LutMap uses linear interpolation. */
- result = (AstMapping *) astLutMap( nel, lut, 1.0, 1.0,
- "LutInterp=%d", status, interp );
-
-/* Report an error if the table cell was empty. */
- } else if( astOK ) {
- astError( AST__BADTAB, "%s(%s): Row 1 of the binary table "
- "contains no value for column '%s'.", status, method,
- class, col );
- }
- }
-
-/* Free memory. */
- lut = astFree( lut );
- key = astFree( key );
-
-/* Now deal with coordinate arrays. */
- } else {
-
-/* Get the shape of the array. */
- dims = astMalloc( sizeof( int )*ndim );
- astColumnShape( table, col, ndim, &ndim, dims );
-
-/* For coordinate arrays, check the length of the first axis is "ndim-1", as
- required by FITS-WCS paper III. */
- if( astOK && dims[ 0 ] != ndim - 1 && !isindex ) {
- astError( AST__BADTAB, "%s(%s): The first dimension of the coordinate "
- "array has length %d (should be %d since the array has %d "
- "dimensions).", status, method, class, dims[ 0 ], ndim - 1,
- ndim );
- }
-
-/* We can currently only handle 1D look-up tables. These are stored in
- notionally two-dimensional arrays in which the first dimension is
- degenarate (i.e. spans only a single element). */
- if( ndim > 2 ) {
- if( astOK ) astError( AST__INTER, "%s(%s): AST can currently only "
- "handle 1-dimensional coordinate look-up tables "
- "(the supplied table has %d dimensions).", status,
- method, class, ndim - 1 );
-
-/* Handle 1-dimensional look-up tables. */
- } else if( astOK ){
-
-/* Allocate memory to hold the array values, and to hold the cell key. */
- lut = astMalloc( dims[ 1 ]*sizeof( double ) );
- key = astMalloc( strlen( col ) + 5 );
- if( astOK ) {
-
-/* Create the key for the table cell holding the required array. FITS-WCS
- paper III mandates that tables always occur in the first row of the
- table (and that the table only has one row). Ignore trailing spaces in
- the column name. */
- sprintf( key, "%.*s(1)", (int) astChrLen( col ), col );
-
-/* Copy the array values into the above memory. */
- if( astMapGet1D( table, key, dims[ 1 ], dims, lut ) ) {
-
-/* Create a 1D LutMap. FITS-WCS paper III (sec 6.1.2) mandates that the input
- corresponds to FITS grid coord (i.e. 1.0 at the centre of the first entry).
- Ensure the LutMap uses linear interpolation. */
- result = (AstMapping *) astLutMap( dims[ 1 ], lut, 1.0, 1.0,
- "LutInterp=%d", status,
- interp );
-
-/* Report an error if the table cell was empty. */
- } else if( astOK ) {
- astError( AST__BADTAB, "%s(%s): Row 1 of the binary table "
- "contains no value for column '%s'.", status, method,
- class, col );
- }
- }
-
-/* Free memory. */
- lut = astFree( lut );
- key = astFree( key );
- }
- dims = astFree( dims );
- }
-
-/* Issue a context message and annul the returned Mapping if an error
- has occurred. */
- if( !astOK ) {
- astError( astStatus, "%s(%s): Cannot read a look-up table for a "
- "tabular WCS axis from column '%s' of a FITS binary table.",
- status, method, class, col );
- result = astAnnul( result );
- }
-
-/* Return the result. */
- return result;
-}
-
-static AstFrameSet *MakeFitsFrameSet( AstFitsChan *this, AstFrameSet *fset,
- int ipix, int iwcs, int encoding,
- const char *method, const char *class,
- int *status ) {
-/*
-* Name:
-* MakeFitsFrameSet
-
-* Purpose:
-* Create a FrameSet which conforms to the requirements of the FITS-WCS
-* papers.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstFrameSet *MakeFitsFrameSet( AstFitsChan *this, AstFrameSet *fset,
-* int ipix, int iwcs, int encoding,
-* const char *method, const char *class,
-* int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function constructs a new FrameSet holding the pixel and WCS
-* Frames from the supplied FrameSet, but optionally extends the WCS
-* Frame to include any extra axes needed to conform to the FITS model.
-
-* Currently, this function does the following:
-*
-* - if the WCS Frame contains a 1D spectral Frame with a defined celestial
-* reference position (SpecFrame attributes RefRA and RefDec), then
-* it ensures that the WCS Frame also contains a pair of celestial
-* axes (such axes are added if they do not already exist within the
-* supplied WCS Frame). The pixel->WCS Mapping is adjusted accordingly.
-*
-* - if the WCS Frame contains a spectral axis and a pair of celestial
-* axes, then the SpecFrame attributes RefRA and RefDec are set to the
-* reference position defined by the celestial axes. The pixel->WCS
-* Mapping is adjusted accordingly.
-*
-* - NULL is returned if the WCS Frame contains more than one spectral
-* axis.
-*
-* - NULL is returned if the WCS Frame contains more than one pair of
-* celestial axes.
-*
-* - Any isolated sky axes (i.e. not contained within a SkyFrame) are
-* re-mapped from radians into degrees.
-
-* Parameters:
-* this
-* The FitsChan.
-* fset
-* The FrameSet to check.
-* ipix
-* The index of the FITS pixel Frame within "fset".
-* iwcs
-* The index of the WCS Frame within "fset".
-* encoding
-* The encoding in use.
-* 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 new FrameSet which confoms to the requirements of the FITS-WCS
-* papers. The base Frame in this FrameSet will be the FITS pixel
-* Frame, and the current Frame will be the WCS Frame. NULL is
-* returned if an error has already occurred, or if the FrameSet cannot
-* be produced for any reason.
-*/
-
-/* Local Variables: */
- AstFitsChan *fc; /* Pointer to temporary FitsChan */
- AstFrame *pframe; /* Pointer to the primary Frame */
- AstFrame *pixfrm; /* Pointer to the FITS pixel Frame */
- AstFrame *tfrm0; /* Pointer to a temporary Frame */
- AstFrame *tfrm; /* Pointer to a temporary Frame */
- AstFrame *wcsfrm; /* Pointer to the FITS WCS Frame */
- AstFrameSet *ret; /* The returned FrameSet */
- AstFrameSet *tfs; /* Pointer to a temporary FrameSet */
- AstMapping *map1; /* Pointer to pre-WcsMap Mapping */
- AstMapping *map3; /* Pointer to post-WcsMap Mapping */
- AstMapping *map; /* Pointer to the pixel->wcs Mapping */
- AstMapping *remap; /* Total Mapping from internal to external units */
- AstMapping *smap; /* Simplified Mapping */
- AstMapping *tmap0; /* Pointer to a temporary Mapping */
- AstMapping *tmap1; /* Pointer to a temporary Mapping */
- AstMapping *tmap2; /* Pointer to a temporary Mapping */
- AstMapping *tmap; /* Pointer to a temporary Mapping */
- AstMapping *umap; /* 1D Mapping from internal to external units */
- AstSpecFrame *skyfrm; /* Pointer to the SkyFrame within WCS Frame */
- AstSpecFrame *specfrm; /* Pointer to the SpecFrame within WCS Frame */
- AstWcsMap *map2; /* Pointer to WcsMap */
- char card[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* A FITS header card */
- char equinox_attr[ 13 ];/* Name of Equinox attribute for sky axes */
- char system_attr[ 12 ]; /* Name of System attribute for sky axes */
- const char *eqn; /* Pointer to original sky Equinox value */
- const char *extunit; /* External units string */
- const char *intunit; /* Internal units string */
- const char *skysys; /* Pointer to original sky System value */
- double con; /* Constant axis value */
- double reflat; /* Celestial latitude at reference point */
- double reflon; /* Celestial longitude at reference point */
- int *perm; /* Pointer to axis permutation array */
- int iax; /* Axis inex */
- int icurr; /* Index of original current Frame in returned FrameSet */
- int ilat; /* Celestial latitude index within WCS Frame */
- int ilon; /* Celestial longitude index within WCS Frame */
- int npix; /* Number of pixel axes */
- int nwcs; /* Number of WCS axes */
- int ok; /* Is the supplied FrameSet usable? */
- int paxis; /* Axis index within the primary Frame */
- int rep; /* Was error reporting switched on? */
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Get copies of the pixel Frame, the WCS Frame and the Mapping. */
- tfrm = astGetFrame( fset, ipix );
- pixfrm = astCopy( tfrm );
- tfrm = astAnnul( tfrm );
- tfrm = astGetFrame( fset, iwcs );
- wcsfrm = astCopy( tfrm );
- tfrm = astAnnul( tfrm );
- tmap = astGetMapping( fset, ipix, iwcs );
- map = astCopy( tmap );
- tmap = astAnnul( tmap );
-
-/* Store the number of pixel and WCS axes. */
- npix = astGetNaxes( pixfrm );
- nwcs = astGetNaxes( wcsfrm );
-
-/* Search the WCS Frame for SkyFrames and SpecFrames. */
- umap = NULL;
- remap = NULL;
- specfrm = NULL;
- skyfrm = NULL;
- ok = 1;
- ilat = -1;
- ilon = -1;
- for( iax = 0; iax < nwcs; iax++ ) {
-
-/* Obtain a pointer to the primary Frame containing the current WCS axis. */
- astPrimaryFrame( wcsfrm, iax, &pframe, &paxis );
-
-/* If the current axis is a SpecFrame, save a pointer to it. If we have already
- found a SpecFrame, abort. */
- if( astIsASpecFrame( pframe ) ) {
- if( specfrm ) {
- ok = 0;
- break;
- }
- specfrm = astClone( pframe );
-
-/* If the current axis is a SkyFrame, save a pointer to it, and its WCS
- index. If we have already found a different SkyFrame, abort. */
- } else if( IsASkyFrame( pframe ) ) {
- if( skyfrm ) {
- if( pframe != (AstFrame *) skyfrm ) {
- ok = 0;
- break;
- }
- } else {
- skyfrm = astClone( pframe );
- }
- if( paxis == 0 ) {
- ilon = iax;
- } else {
- ilat = iax;
- }
-
-/* If the internal and external units differ, attempt to remap the axis
- into its external units. */
- } else {
-
-/* Get the string describing the external units (the "Unit" attribute). */
- extunit = astGetUnit( pframe, paxis );
-
-/* Get the string describing the internal units (the "InternalUnit"
- attribute). */
- intunit = astGetInternalUnit( pframe, paxis );
-
-/* If they are the same, we do not need to modify this axis. */
- if( astOK && strcmp( extunit, intunit ) ){
-
-/* Otherwise, get the mapping from the internal units to the external
- units, if possible. Ignore any error reported by unitmapper. */
- rep = astReporting( 0 );
- umap = astUnitMapper( intunit, extunit, NULL, NULL );
- if( !astOK ) astClearStatus;
- astReporting( rep );
-
- if( !umap ) {
-
-/* If the above failed, ensure that the external units are the same as
- the internal units (except that internal radians are converted to
- external degrees). */
- if( !strcmp( intunit, "rad" ) ) {
- umap = (AstMapping *) astZoomMap( 1, AST__DR2D, " ", status );
- extunit = "deg";
- } else {
- extunit = intunit;
- }
-
- astSetUnit( wcsfrm, iax, extunit );
- }
- }
- }
-
-/* If no change is needed for the mapping for this axis, use a UnitMap. */
- if( !umap ) umap = (AstMapping *) astUnitMap( 1, " ", status );
-
-/* Extend the parallel CmpMap to encompass the current axis. */
- if( remap ) {
- tmap = (AstMapping *) astCmpMap( remap, umap, 0, " ", status );
- (void) astAnnul( remap );
- remap = tmap;
- } else {
- remap = astClone( umap );
- }
-
-/* Free resources. */
- umap = astAnnul( umap );
- pframe = astAnnul( pframe );
- }
-
-/* See if the pixel->wcs mapping needs to be modified to take account of
- any changes to axis units. */
- smap = astSimplify( remap );
- if( ! astIsAUnitMap( smap ) ) {
- tmap = (AstMapping *) astCmpMap( map, remap, 1, " ", status );
- map = astAnnul( map );
- remap = astAnnul( remap );
- map = tmap;
- }
-
-/* If the supplied FrameSet is usable... */
- if( ok ) {
-
-/* If we did not find a SpecFrame, return a FrameSet made from the base
- and current Frames in the supplied FrameSet. */
- if( !specfrm ) {
- ret = astFrameSet( pixfrm, "", status );
- astAddFrame( ret, AST__BASE, map, wcsfrm );
-
-/* If we have a SpecFrame, proceed. */
- } else {
-
-/* Check that both the RefRA and RefDec attributes of the SpecFrame are set.
- If not, return a FrameSet made from the base and current Frames in the
- supplied FrameSet. Also do this if the original WCS Frame contains 3
- or more axes (since it is almost always inappropriate to add extra sky
- axes in such circumestances). But if the other axes form a skyfram,
- then we need to make sure they use the right refrence point. */
- if( !astTestRefRA( specfrm ) || !astTestRefDec( specfrm ) ||
- ( nwcs > 2 && !skyfrm ) ) {
- ret = astFrameSet( pixfrm, "", status );
- astAddFrame( ret, AST__BASE, map, wcsfrm );
-
-/* If we have a celestial reference position for the spectral axis, ensure
- it is described correctly by a pair of celestial axes. */
- } else {
-
-/* If the WCS Frame does not contain any celestial axes, we add some now. */
- if( !skyfrm ) {
-
-/* The easiest way to create the required mapping from pixel to celestial
- to create a simple FITS header and read it in via a FitsChan to create a
- FrameSet. */
- fc = astFitsChan( NULL, NULL, "", status );
- astPutFits( fc, "CRPIX1 = 0", 0 );
- astPutFits( fc, "CRPIX2 = 0", 0 );
- astPutFits( fc, "CDELT1 = 0.0003", 0 );
- astPutFits( fc, "CDELT2 = 0.0003", 0 );
- astPutFits( fc, "CTYPE1 = 'RA---TAN'", 0 );
- astPutFits( fc, "CTYPE2 = 'DEC--TAN'", 0 );
- astPutFits( fc, "RADESYS = 'FK5'", 0 );
- astPutFits( fc, "EQUINOX = 2000.0", 0 );
- sprintf( card, "CRVAL1 = %.*g", DBL_DIG,
- AST__DR2D*astGetRefRA( specfrm ) );
- astPutFits( fc, card, 0 );
- sprintf( card, "CRVAL2 = %.*g", DBL_DIG,
- AST__DR2D*astGetRefDec( specfrm ) );
- astPutFits( fc, card, 0 );
- sprintf( card, "MJD-OBS = %.*g", DBL_DIG,
- TDBConv( astGetEpoch( specfrm ), AST__UTC, 1,
- "astWrite", "FitsChan", status ) );
- astPutFits( fc, card, 0 );
- astClearCard( fc );
- tfs = astRead( fc );
- if( tfs ) {
-
-/* Create the new pixel->wcs Mapping. First get the 2-input,2-output
- Mapping between pixel and sky coords from the above FrameSet. Then add
- this Mapping in parallel with the original pixel->wcs Mapping. */
- tmap0 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
- tmap1 = (AstMapping *) astCmpMap( map, tmap0, 0, "", status );
- tmap0 = astAnnul( tmap0 );
-
-/* We now have a (npix+2)-input,(nwcs+2)-output Mapping. We now add a
- PermMap in series with this which feeds the constant value 0.0 (the
- CRPIX value in the above set of FITS headers) into the 2 pixel axes
- corresponding to RA and Dec. This PermMap has npix-inputs and (npix+2)
- outputs. The total Mapping then has npix inputs and (nwcs+2) outputs. */
- perm = astMalloc( sizeof( int )*(size_t) ( npix + 2 ) );
- if( astOK ) {
- for( iax = 0; iax < npix; iax++ ) perm[ iax ] = iax;
- perm[ npix ] = -1;
- perm[ npix + 1 ] = -1;
- con = 0.0;
- tmap0 = (AstMapping *) astPermMap( npix, perm, npix + 2, perm, &con, "", status );
- tmap2 = (AstMapping *) astCmpMap( tmap0, tmap1, 1, "", status );
- tmap0 = astAnnul( tmap0 );
- tmap1 = astAnnul( tmap1 );
-
-/* We now create the new WCS Frame with the extra RA and Dec axes. This
- is just a CmpFrame made up of the original WCS Frame and the new
- SkyFrame. */
- tfrm = astGetFrame( tfs, AST__CURRENT );
- tfrm0 = (AstFrame *) astCmpFrame( wcsfrm, tfrm, "", status );
- tfrm = astAnnul( tfrm );
-
-/* Construct the returned FrameSet. */
- ret = astFrameSet( pixfrm, "", status );
- astAddFrame( ret, AST__BASE, tmap2, tfrm0 );
- tmap2 = astAnnul( tmap2 );
- tfrm0 = astAnnul( tfrm0 );
-
-/* Free remaining resources. */
- perm = astFree( perm );
- }
- tfs = astAnnul( tfs );
- }
- fc = astAnnul( fc );
-
-/* If the WCS Frame does contain celestial axes we make sure that the
- SpecFrame uses the same reference point. */
- } else {
-
-/* The returned FrameSet has no extra Frames (although some attributes
- may be changed) so just create a new FrameSet equaivalent to the supplied
- FrameSet. */
- tfs = astFrameSet( pixfrm, "", status );
- astAddFrame( tfs, AST__BASE, map, wcsfrm );
-
-/* The RefRA and RefDec attributes of the SpecFrame must be set in FK5
- J2000. Therefore we need to know the celestial reference point in
- FK5 J2000. Modify the SkyFrame within the FrameSet to represent FK5
- J2000, noting the original sky system and equinox first so that they
- can be re-instated (if set) later on. */
- sprintf( system_attr, "System(%d)", ilon + 1 );
- if( astTest( tfs, system_attr ) ) {
- skysys = astGetC( tfs, system_attr );
- } else {
- skysys = NULL;
- }
- astSetC( tfs, system_attr, "FK5" );
- sprintf( equinox_attr, "Equinox(%d)", ilon + 1 );
- if( astTest( tfs, equinox_attr ) ) {
- eqn = astGetC( tfs, equinox_attr );
- } else {
- eqn = NULL;
- }
- astSetC( tfs, equinox_attr, "J2000" );
-
-/* The reference point for the celestial axes is defined by the WcsMap
- contained within the Mapping. Split the mapping up into a list of serial
- component mappings, and locate the first WcsMap in this list. The first
- Mapping returned by this call is the result of compounding all the
- Mappings up to (but not including) the WcsMap, the second returned Mapping
- is the (inverted) WcsMap, and the third returned Mapping is anything
- following the WcsMap. Only proceed if one and only one WcsMap is found. */
- tmap0 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
- if( SplitMap( tmap0, astGetInvert( tmap0 ), ilon, ilat, &map1, &map2, &map3, status ) ){
-
-/* The reference point in the celestial coordinate system is found by
- transforming the fiducial point in native spherical co-ordinates
- into absolute physical coordinates using map3. */
- if( GetFiducialWCS( map2, map3, ilon, ilat, &reflon, &reflat, status ) ){
-
-/* Use reflon and reflat (which represent FK5 J2000 RA and Dec) to set
- the values of the SpecFrame RefRA and RefDec attributes. Format the
- values first so that we can use the FrameSet astSetC method, and so
- maintain the FrameSet integrity. Use "tfs" rather than "wcsfrm" when
- calling astFormat, as "wcsfrm" is not affected by the above change
- to the current frame of "tfs" (i.e. astAddFrame takes a deep copy of the
- supplied Frame). */
- astSetC( tfs, "RefRA", astFormat( tfs, ilon, reflon ) );
- astSetC( tfs, "RefDec", astFormat( tfs, ilat, reflat ) );
-
-/* If succesfull, return a pointer to the FrameSet. */
- if( astOK ) ret = astClone( tfs );
- }
-
-/* Release resources. */
- map1 = astAnnul( map1 );
- map2 = astAnnul( map2 );
- map3 = astAnnul( map3 );
-
-/* If no WcsMap was found, the celestial axes have no reference point and
- so we can retain the original spectral reference point, so just return
- the temporary FrameSet. */
- } else if( astOK ) {
- ret = astClone( tfs );
- }
- tmap0 = astAnnul( tmap0 );
-
-/* Re-instate the original sky system and equinox. */
- if( skysys ) astSetC( tfs, system_attr, skysys );
- if( eqn ) astSetC( tfs, equinox_attr, eqn );
-
-/* Release resources. */
- tfs = astAnnul( tfs );
- }
- }
- }
- }
-
-/* Add a new current Frame into the FrameSet which increases the chances of
- the requested encoding being usable. The index of the original current
- Frame is returned, or AST__NOFRAME if no new Frame was added. */
- icurr = AddEncodingFrame( this, ret, encoding, method, class, status );
-
-/* If a new Frame was added, remove the original current Frame. */
- if( icurr != AST__NOFRAME ) astRemoveFrame( ret, icurr );
-
-/* Free resources. */
- if( specfrm ) specfrm = astAnnul( specfrm );
- if( skyfrm ) skyfrm = astAnnul( skyfrm );
- pixfrm = astAnnul( pixfrm );
- wcsfrm = astAnnul( wcsfrm );
- map = astAnnul( map );
-
-/* Return NULL if an error has occurred. */
- if( !astOK && ret ) ret = astAnnul( ret );
-
-/* Return the result. */
- return ret;
-}
-
-static void MakeIndentedComment( int indent, char token,
- const char *comment, const char *data,
- char string[ AST__FITSCHAN_FITSCARDLEN -
- FITSNAMLEN + 1 ], int *status ) {
-/*
-* Name:
-* MakeIndentedComment
-
-* Purpose:
-* Create a comment string containing an indentation bar.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void MakeIndentedComment( int indent, char token,
-* const char *comment, const char *data,
-* char string[ AST__FITSCHAN_FITSCARDLEN -
-* FITSNAMLEN + 1 ], int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function creates a string that may be used as text in a
-* FITS comment card. The string contains a textual comment
-* preceded by a bar (a line of characters) whose length can be
-* used to indicate a level of indentation (in the absence of any
-* way of indenting FITS keywords).
-
-* Parameters:
-* indent
-* The level of indentation, in characters.
-* token
-* The character used to form the indentation bar.
-* comment
-* A pointer to a constant null-terminated string containing the text
-* of the comment to be included.
-* data
-* A pointer to a constant null-terminated string containing any
-* textual data to be appended to the comment.
-* string
-* A character array to receive the output string.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - The comment text that appears in the output string is formed by
-* concatenating the "comment" and "data" strings.
-*/
-
-/* Local Variables: */
- int i; /* Loop counter for input characters */
- int len; /* Number of output characters */
- int mxlen; /* Maximum length of output string */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Calculate the maximum number of characters that the output string
- can accommodate. */
- mxlen = AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN;
-
-/* Start the string with "indent" copies of the token character, but
- without exceeding the output string length. */
- len = 0;
- while ( ( len < indent ) && ( len < mxlen ) ) string[ len++ ] = token;
-
-/* Pad with spaces up to the start of the comment, if necessary. */
- while ( len < ( FITSCOMCOL - FITSNAMLEN - 1 ) ) {
- string[ len++ ] = ' ';
- }
-
-/* Add "/ " to introduce the comment (strictly not necessary as the
- whole card will be a comment, but it matches the other non-comment
- cards). Truncate if necessary. */
- for ( i = 0; ( i < 2 ) && ( len < mxlen ); i++ ) {
- string[ len++ ] = "/ "[ i ];
- }
-
-/* Append the comment string, truncating it if it is too long. */
- for ( i = 0; comment[ i ] && ( len < mxlen ); i++ ) {
- string[ len++ ] = comment[ i ];
- }
-
-/* Append the data string, again truncating if too long. */
- for ( i = 0; data[ i ] && ( len < mxlen ); i++ ) {
- string[ len++ ] = data[ i ];
- }
-
-/* Terminate the output string. */
- string[ len ] = '\0';
-}
-
-static void MakeIntoComment( AstFitsChan *this, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* MakeIntoComment
-
-* Purpose:
-* Convert a card into a FITS COMMENT card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void MakeIntoComment( AstFitsChan *this, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function formats the card stored just prior to the current card,
-* and re-stores it as a COMMENT card. It is used (when writing an Object
-* to a FitsChan) to output values that are not "set" and which are
-* therefore provided for information only, and should not be read back.
-* the COMMENT card has the effect of "commenting out" the value.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* method
-* Calling method.
-* class
-* Object class.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- char card[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Character buffer for FITS card data */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Move the current card backwards by one card. */
- MoveCard( this, -1, method, class, status );
-
-/* Format the new current card. */
- FormatCard( this, card, method, status );
-
-/* Write the resulting string to the FitsChan as the contents of a COMMENT
- card, overwriting the existing card. The current card is incremented
- by this call so that it refers to the same card as on entry. */
- astSetFitsCom( this, "COMMENT", card, 1 );
-}
-
-static int MakeIntWorld( AstMapping *cmap, AstFrame *fr, int *wperm, char s,
- FitsStore *store, double *dim,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* MakeIntWorld
-
-* Purpose:
-* Create FITS header values which map grid into intermediate world
-* coords.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int MakeIntWorld( AstMapping *cmap, AstFrame *fr, int *wperm, char s,
-* FitsStore *store, double *dim,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function adds values to the supplied FitsStore which describe
-* the transformation from grid (pixel) coords to intermediate world
-* coords. The values added to the FitsStore correspond to the CRPIXj,
-* PCi_j, CDELTi and WCSAXES keywords, and are determined by examining the
-* suppliedMapping, which must be linear with an optional shift of
-* origin (otherwise a value of zero is returned).
-*
-* Much of the complication in the algorithm arises from the need to
-* support cases where the supplied Mapping has more outputs than
-* inputs. In these case we add some "degenerate" axes to the grid
-* coord system, choosing their unit vectors to be orthogonal to all
-* the other grid axes. It is assumed that degenerate axes will never
-* be used to find a position other than at the axis value of 1.0.
-*
-* NOTE, appropriate values for CRVAL keywords should have been stored
-* in the FitsStore before calling this function (since this function may
-* modify them).
-
-* Parameters:
-* cmap
-* A pointer to a Mapping which transforms grid coordinates into
-* intermediate world coordinates. The number of outputs must be
-* greater than or equal to the number of inputs.
-* fr
-* Pointer to the final WCS coordinate Frame.
-* wperm
-* Pointer to an array of integers with one element for each axis of
-* the "fr" Frame. Each element holds the zero-based index of the
-* FITS-WCS axis (i.e. the value of "i" in the keyword names "CTYPEi",
-* "CDi_j", etc) which describes the Frame axis.
-* s
-* The co-ordinate version character. A space means the primary
-* axis descriptions. Otherwise the supplied character should be
-* an upper case alphabetical character ('A' to 'Z').
-* store
-* A pointer to the FitsStore into which the calculated CRPIX and
-* CDi_j values are to be put.
-* dim
-* An array holding the image dimensions in pixels. AST__BAD can be
-* supplied for any unknwon dimensions.
-* 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 value of 1 is returned if the CRPIX and CDi_j values are
-* succesfully calculated. Zero is returned otherwise.
-
-* Notes:
-* - Zero is returned if an error occurs.
-*/
-
-/* Local Variables: */
- AstFrame *pfrm;
- AstFrame *sfrm;
- AstMapping *map;
- AstPointSet *psetw;
- AstPointSet *psetg;
- double **fullmat;
- double **partmat;
- double **ptrg;
- double **ptrw;
- double *c;
- double *cdelt;
- double *cdmat;
- double *colvec;
- double *d;
- double *g;
- double *g0;
- double *m;
- double *mat;
- double *tol;
- double *w0;
- double *y;
- double cd;
- double crp;
- double crv;
- double cv;
- double det;
- double err;
- double k;
- double mxcv;
- double skydiag1;
- double skydiag0;
- double val;
- int *iw;
- int *lin;
- int *pperm;
- int *skycol;
- int i;
- int ii;
- int j;
- int jax;
- int jj;
- int nin;
- int nout;
- int nwcs;
- int paxis;
- int ret;
- int sing;
- int skycol0;
- int skycol1;
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Simplify the supplied Mapping to reduce rounding errors when
- transforming points. */
- map = astSimplify( cmap );
-
-/* Get the number of inputs and outputs for the Mapping. Return if the
- number of outputs is smaller than the number of inputs. */
- nin = astGetNin( map );
- nout = astGetNout( map );
- if( nout < nin ) return ret;
-
-/* Note the number of final World Coordinate axes (not necessarily the
- same as "nout", since some intermediate axes may be discarded by a
- later PermMap. */
- nwcs = astGetNaxes( fr );
-
-/* Allocate work space. */
- g = astMalloc( sizeof(double)*(size_t) nin );
- g0 = astMalloc( sizeof(double)*(size_t) nin );
- w0 = astMalloc( sizeof(double)*(size_t) nout );
- tol = astMalloc( sizeof(double)*(size_t) nout );
- partmat = astMalloc( sizeof(double *)*(size_t) nout );
- lin = astMalloc( sizeof(int)*(size_t) nout );
- pperm = astMalloc( sizeof(int)*(size_t) nout );
- skycol = astMalloc( sizeof(int)*(size_t) nout );
- cdmat = astMalloc( sizeof(double)*(size_t) (nout*nout) );
- cdelt = astMalloc( sizeof(double)*(size_t) nout );
-
-/* For safety, initialise all other pointers. */
- if( partmat ) for( j = 0; j < nout; j++ ) partmat[ j ] = NULL;
- fullmat = NULL;
-
-/* Create a PointSet to hold an input (grid) position for each axis, plus
- an extra one. Create two other PointSets to hold corresponding
- output (IWC) coordinates. */
- psetg = astPointSet( nin + 1, nin, "", status );
- ptrg = astGetPoints( psetg );
- psetw = astPointSet( nin + 1, nout, "", status );
- ptrw = astGetPoints( psetw );
-
-/* Check the pointers can be used safely. */
- if( astOK ) {
-
-/* Assume success. */
- ret = 1;
-
-/* The next section finds a 'root' grid position for which the
- corresponding IWC coordinates are all good. It also finds these IWC
- coordinates, together with the IWC coordinates of "nin" points which
- are a unit distance away from the root grid position along each
- grid axis. It also finds an estimate of the rounding error in each
- Mapping output.
- ================================================================= */
- ret = FindBasisVectors( map, nin, nout, dim, psetg, psetw, status );
-
-/* Save the grid root position in "g0". */
- for( j = 0; j < nin; j++ ) g0[ j ] = ptrg[ j ][ 0 ];
-
-/* Save the transformed root position in "w0". This is the grid root
- position represented as a vector within the Intermediate World
- Coordinate system. */
- for( j = 0; j < nout; j++ ) {
- w0[ j ] = ptrw[ j ][ 0 ];
-
-/* Find the tolerance for positions on the j'th IWC axis. This is one
- tenth of the largest change in the j'th IWC axis value caused by
- moving out 1 pixel along any grid axis. */
- tol[ j ] = 0.0;
- for( i = 0; i < nin; i++ ) {
- err = fabs( ptrw[ j ][ i + 1 ] - w0[ j ] );
- if( err > tol[ j ] ) tol[ j ] = err;
- }
- tol[ j ] *= 0.1;
-
-/* If the tolerance is zero (e.g. as is produced for degenerate axes),
- then use a tolerance equal to a very small fraction of hte degenerate
- axis value. If the axis value is zero use a fixed small value. */
- if( tol[ j ] == 0.0 ) tol[ j ] = w0[ j ]*DBL_EPSILON*1.0E5;
- if( tol[ j ] == 0.0 ) tol[ j ] = sqrt( DBL_MIN );
- }
-
-/* The next section finds the CD matrix.
- ===================================== */
-
-/* Initialise the CD matrix elements to "all missing". */
- for( i = 0; i < nout*nout; i++ ) cdmat[ i ] = AST__BAD;
-
-/* The elements of column "j" of the CD matrix form a vector (in Intermediate
- World Coords) which corresponds to a unit vector along grid axis "j".
- We now find these vectors for all the grid axes represented by the
- inputs to the supplied Mapping. */
- for( i = 0; i < nin && ret; i++ ) {
-
-/* Form a unit vector along the current input axis. */
- for( ii = 0; ii < nin; ii++ ) g[ ii ] = 0.0;
- g[ i ] = 1.0;
-
-/* Fit a straight line (within IWC) to the current input axis of the Mapping.
- The IWC vector corresponding to a unit vector along the current input axis
- is returned if the Mapping is linear. A NULL pointer is returned if the
- Mapping is not linear. */
- partmat[ i ] = FitLine( map, g, g0, w0, dim[ i ], tol, status );
-
-/* If unsuccesful, indicate failure and break out of the loop. */
- if( !partmat[ i ] ) {
- ret = 0;
- break;
- }
- }
-
-/* If the number of outputs for "map" is larger than the number of inputs,
- then we will still be missing some column vectors for the CDi_j matrix
- (which has to be square). We invent these such that the they are
- orthogonal to all the other column vectors. Only do this if the
- Mapping is linear. */
- if( ret ) {
- fullmat = OrthVectorSet( nout, nin, partmat, status );
- if( !fullmat ) ret = 0;
- }
-
-/* Check everything is OK. */
- if( ret ) {
-
-/* Check that the full matrix is invertable, and if not, see if there is
- any way to make it invertable. */
- MakeInvertable( fullmat, nout, dim, status );
-
-/* Set up an array holding index of the Mapping output corresponding to
- each IWC axis (the inverse of "wperm"). Also look for matching pairs of
- celestial WCS axes. For the first such pair, note the corresponding
- column indices and the diagonal element of the matrix which gives the
- scaling for the axis (taking account of the permutation of WCS axes).
- Also note if the Mapping from intermediate world coords to final world
- coords is linear for each axis (this is assumed to be the case if the
- axis is part of a simple Frame). */
- sfrm = NULL;
- skydiag0 = AST__BAD;
- skydiag1 = AST__BAD;
- skycol0 = -1;
- skycol1 = -1;
- for( i = 0; i < nout; i++ ) {
- pperm[ wperm[ i ] ] = i;
- astPrimaryFrame( fr, i, &pfrm, &paxis );
- if( IsASkyFrame( pfrm ) ) {
- skycol[ wperm[ i ] ] = paxis + 1;
- lin[ i ] = 0;
- if( !sfrm ) {
- sfrm = astClone( pfrm );
- skycol0 = wperm[ i ];
- skydiag0 = fullmat[ skycol0 ][ i ];
- } else if( sfrm == pfrm ) {
- skycol1 = wperm[ i ];
- skydiag1 = fullmat[ skycol1 ][ i ];
- }
- } else {
- skycol[ wperm[ i ] ] = 0;
- lin[ i ] = !strcmp( astGetClass( pfrm ), "Frame" );
- }
- pfrm = astAnnul( pfrm );
- }
- if( sfrm ) sfrm = astAnnul( sfrm );
-
-/* We now have the complete CDi_j matrix. Now to find the CRPIX values.
- These are the grid coords of the reference point (which corresponds to
- the origin of Intermediate World Coords). The "w0" array currently holds
- the position of the root position, as a position within IWC, and the
- "g0" array holds the corresponding position in grid coordinates. We
- also have IWC vectors which correspond to unit vectors on each grid
- axis. The CRPIX values are defined by the matrix equation
- w0 = fullmat*( g0 - crpix )
- The "g0" array only contains "nin" values. If nout>nin, then the
- missing g0 values will be assumed to be zero when we come to find the
- CRPIX values below.
- We use palDmat to solve this system of simultaneous equations to get
- crpix. The "y" array initially holds "w0" but is over-written to hold
- "g0 - crpix". */
- mat = astMalloc( sizeof( double )*(size_t)( nout*nout ) );
- y = astMalloc( sizeof( double )*(size_t) nout );
- iw = astMalloc( sizeof( int )*(size_t) nout );
- if( astOK ) {
- m = mat;
- for( i = 0; i < nout; i++ ) {
- for( j = 0; j < nout; j++ ) *(m++) = fullmat[ j ][ i ];
- y[ i ] = w0[ i ];
- }
- palDmat( nout, mat, y, &det, &sing, iw );
- }
- mat = astFree( mat );
- iw = astFree( iw );
-
-/* Loop round all axes, storing the column vector pointer. */
- for( j = 0; j < nout; j++ ) {
- colvec = fullmat[ j ];
-
-/* Get the CRPIX values from the "y" vector created above by palDmat.
- First deal with axes for which there are Mapping inputs. */
- if( j < nin ) {
- crp = g0[ j ] - y[ j ];
-
-/* If this is a grid axis which has been created to represent a "missing"
- input to the mapping, we need to add on 1.0 to the crpix value found
- above. This is because the "w0" vector corresponds to a value of zero
- on any missing axes, but the FITS grid value for any missing axes is
- 1.0. */
- } else {
- crp = 1.0 - y[ j ];
- }
-
-/* Store the CD and CRPIX values for axes which correspond to inputs
- of "map". The CD matrix elements are stored in an array and are
- converted later to the corresponding PC and CDELT values. */
- if( j < nin || crp == 0.0 ) {
- for( i = 0; i < nout; i++ ) {
- cdmat[ wperm[ i ]*nout+j ] = colvec[ i ] ;
- }
- SetItem( &(store->crpix), 0, j, s, crp, status );
-
-/* The length of the unit vector along any "degenerate" axes was fixed
- arbitrarily at 1.0 by the call to OrthVectorSet. We can probably
- choose a more appropriate vector length. The choice shouldn't make any
- difference to the transformation, but an appropriate value will look
- more natural to human readers. */
- } else {
-
-/* First, try to arrange for longitude/latitude axis pairs to have the same
- scale. Do we have a matching pair of celestial axes? */
- k = AST__BAD;
- if( skydiag0 != AST__BAD && skydiag1 != AST__BAD ) {
-
-/* Is the current column the one which corresponds to the first celestial
- axis, and does the other sky column correspond to a Mapping input? */
- if( skycol0 == j && skycol1 < nin ) {
-
-/* If so, scale this column so that its diagonal element is the negative
- of the diagonal element of the other axis. This is on the assumption that
- the scales on the two axes should be equal, and that longitude increases
- east whilst latitude increases north, and that the CD matrix does not
- introduce an axis permutation. */
- if( skydiag0 != 0.0 ) k = -skydiag1/skydiag0;
-
-/* Now see if the current column the one which corresponds to the second
- celestial axis. Do the same as above. */
- } else if( skycol1 == j && skycol0 < nin ) {
- if( skydiag1 != 0.0 ) k = -skydiag0/skydiag1;
-
-/* If neither of the above conditions was met, assume a diagonal element
- value of 1.0 degrees for latitude axes, and -1.0 degrees for longitude
- axes. */
- }
- }
-
-/* If this failed, the next choice is to arrange for diagonally opposite
- elements to be equal and opposite in value. Look for the element of the
- column which has the largest diagonally opposite element, and choose a
- scaling factor which makes this column element equal to the negative value
- of its diagonally opposite element. Be careful to take axis permutations
- into account when finding the value of the diagonal element. */
- if( k == AST__BAD ) {
- mxcv = 0.0;
- ii = pperm[ j ];
- for( i = 0; i < nout; i++ ) {
- jj = wperm[ i ];
- if( jj < nin ) {
- cv = fullmat[ jj ][ ii ];
- if( !astEQUAL( colvec[ i ], 0.0 ) && fabs( cv ) > mxcv ) {
- mxcv = fabs( cv );
- k = -cv/colvec[ i ];
- }
- }
- }
- }
-
-/* If still no scaling factor is available, use a scaling factor which
- produces a diagonal element of 1.0 degree if the corresponding row is a
- sky latitude axis, -1.0 degree of sky longitude axes, and 1.0 for other
- axes. */
- if( k == AST__BAD && colvec[ pperm[ j ] ] != 0.0 ) {
- if( skycol[ j ] ) {
- k = AST__DD2R/colvec[ pperm[ j ] ];
- if( skycol[ j ] == 1 ) k = -k;
- } else {
- k = 1.0/colvec[ pperm[ j ] ];
- }
- }
-
-/* If we still do not have a scaling, use 1.0 (no scaling). */
- if( k == AST__BAD ) k = 1.0;
-
-/* Now scale and store the column elements. */
- for( i = 0; i < nout; i++ ) {
- cdmat[ wperm[ i ]*nout+j ] = k*colvec[ i ];
- }
-
-/* Find the corresponding modified CRPIX value and store it. */
- crp = 1.0 + ( crp - 1.0 )/k;
- SetItem( &(store->crpix), 0, j, s, crp, status );
- }
-
-/* Free resources */
- if( pfrm ) pfrm = astAnnul( pfrm );
- }
-
-/* Any "degenerate" axes added in the above process for which the
- intermediate->world mapping is linear, and which depend only on one
- pixel axis, can be adjusted so that the reference point is at grid
- coord 1.0. */
- for( i = 0; i < nout; i++ ) {
- if( lin[ i ] ) {
-
-/* Check only one pixel axis contributes to this intermediate world axis
- and find which one it is. */
- jax = -1;
- for( j = 0; j < nout; j++ ) {
- if( !astEQUAL( fullmat[ j ][ i ], 0.0 ) ) {
- if( jax == -1 ) {
- jax = j;
- } else {
- jax = -1;
- break;
- }
- }
- }
-
-/* We only adjust values for "degenerate" axes. */
- if( jax >= nin ) {
-
-/* Check that this pixel axis only contributes to the single world axis
- currently being considered. */
- for( ii = 0; ii < nout; ii++ ) {
- if( ii != i ) {
- if( !astEQUAL( fullmat[ jax ][ ii ], 0.0 ) ) {
- jax = -1;
- break;
- }
- }
- }
- if( jax != -1 ) {
-
-/* Get the original CRVAL, CRPIX and CD values. Check they are defined.*/
- crv = GetItem( &(store->crval), wperm[ i ], 0, s, NULL,
- method, class, status );
- cd = cdmat[ wperm[ i ]*nout + jax ];
- crp = GetItem( &(store->crpix), 0, jax, s, NULL, method, class, status );
- if( crv != AST__BAD && crp != AST__BAD &&
- cd != AST__BAD ) {
-
-/* Modify the CRPIX to be 1.0 and modify the CRVAL value accordingly. */
- SetItem( &(store->crpix), 0, jax, s, 1.0, status );
- SetItem( &(store->crval), wperm[ i ], 0, s,
- cd*( 1.0 - crp ) + crv, status );
- }
- }
- }
- }
- }
-
-/* Finally, if there are fewer input axes than output axes, put a value for
- the WCSAXES keyword into the store. */
- if( nin < nwcs ) SetItem( &(store->wcsaxes), 0, 0, s, nwcs, status );
-
-/* Release resources. */
- y = astFree( y );
- }
-
-/* Produce and store PC and CDELT values from the above CD matrix */
- SplitMat( nout, cdmat, cdelt, status );
- c = cdmat;
- d = cdelt;
- for( i = 0; i < nout; i++ ){
- for( j = 0; j < nout; j++ ){
- val = *(c++);
- if( i == j ){
- if( astEQUAL( val, 1.0 ) ) val = AST__BAD;
- } else {
- if( astEQUAL( val, 0.0 ) ) val = AST__BAD;
- }
- if( val != AST__BAD ) SetItem( &(store->pc), i, j, s, val, status );
- }
- SetItem( &(store->cdelt), i, 0, s, *(d++), status );
- }
- }
-
-/* Annul pointsets. */
- psetg = astAnnul( psetg );
- psetw = astAnnul( psetw );
-
-/* Free other resources*/
- map = astAnnul( map );
- if( fullmat ) for( j = 0; j < nout; j++ ) fullmat[ j ] = astFree( fullmat[ j ] );
- if( partmat ) for( j = 0; j < nout; j++ ) partmat[ j ] = astFree( partmat[ j ] );
- fullmat = astFree( fullmat );
- partmat = astFree( partmat );
- cdmat = astFree( cdmat );
- cdelt = astFree( cdelt );
- g = astFree( g );
- g0 = astFree( g0 );
- w0 = astFree( w0 );
- tol = astFree( tol );
- lin = astFree( lin );
- skycol = astFree( skycol );
- pperm = astFree( pperm );
-
-/* If an error has occurred, return zero. */
- if( !astOK ) ret = 0;
-
-/* Return the answer. */
- return ret;
-}
-
-static void MakeInvertable( double **fullmat, int n, double *dim, int *status ){
-/*
-* Name:
-* MakeInvertable
-
-* Purpose:
-* Modify a supplied square CD matrix if possible to make it invertable.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void MakeInvertable( double **fullmat, int n, double *dim, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A search is made for matrix inputs that have no effect on any
-* matrix outputs. if any such matrix inputs are associated with
-* degenerate pixel axes (i.e. pixel axes that span only a single
-* pixel), then the matrix input should always have the value zero and
-* so the corresponding diagonal element of the matrix can be set to
-* 1.0 without changing and of the outputs.
-
-* Parameters:
-* fullmat
-* A pointer to an array with "n" elements corresponding to the n
-* inputs of the matrix, each element being a pointer to an array
-* with "n" elements corresponding to the n outputs of the matrix.
-* n
-* The number of inputs and outputs for the square matrix.
-* dim
-* Pointer to an array of "n" input (i.e. pixel) axis dimensions.
-* Individual elements will be AST__BAD if dimensions are not known.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- int i; /* Input index */
- int j; /* Output index */
- int unused; /* Does the current input have no effect on any output? */
-
-/* Check inherited status */
- if( !astOK ) return;
-
-/* Look for any inputs that have no effect on any of the outputs. If such
- an input is associated with a degenerate grid axis (i.e. a grid axis
- with a dimension of 1.0), then the input value will always be zero and
- so the corresponding diagonal element of the matrix can eb set to 1.0
- without affecting the output value (which will always be zero since
- zero times anything is zero). Loop over all inputs. */
- for( i = 0; i < n; i++ ) {
-
-/* Assume this input has no effect on any output. */
- unused = 1;
-
-/* Loop over all outputs. */
- for( j = 0; j < n; j++ ) {
-
-/* If the corresponding matrix term is non-zero, the the input will have
- an effect on the output, so set the unused flag false and break out of
- the output loop. */
- if( fullmat[ i ][ j ] != 0.0 ) {
- unused = 0;
- break;
- }
- }
-
-/* If the input is unused, and it is associated with a degenerate pixel
- axis, we can set the corresponding diagonal element of the matrix to
- 1.0. */
- if( unused && dim[ i ] == 1.0 ) fullmat[ i ][ i ] = 1.0;
- }
-}
-#if defined(THREAD_SAFE)
-
-static int ManageLock( AstObject *this_object, int mode, int extra,
- AstObject **fail, int *status ) {
-/*
-* Name:
-* ManageLock
-
-* Purpose:
-* Manage the thread lock on an Object.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "object.h"
-* AstObject *ManageLock( AstObject *this, int mode, int extra,
-* AstObject **fail, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the astManageLock protected
-* method inherited from the parent class).
-
-* Description:
-* This function manages the thread lock on the supplied Object. The
-* lock can be locked, unlocked or checked by this function as
-* deteremined by parameter "mode". See astLock for details of the way
-* these locks are used.
-
-* Parameters:
-* this
-* Pointer to the Object.
-* mode
-
-* An integer flag indicating what the function should do:
-*
-* AST__LOCK: Lock the Object for exclusive use by the calling
-* thread. The "extra" value indicates what should be done if the
-* Object is already locked (wait or report an error - see astLock).
-*
-* AST__UNLOCK: Unlock the Object for use by other threads.
-*
-* AST__CHECKLOCK: Check that the object is locked for use by the
-* calling thread (report an error if not).
-* extra
-* Extra mode-specific information.
-* fail
-* If a non-zero function value is returned, a pointer to the
-* Object that caused the failure is returned at "*fail". This may
-* be "this" or it may be an Object contained within "this". Note,
-* the Object's reference count is not incremented, and so the
-* returned pointer should not be annulled. A NULL pointer is
-* returned if this function returns a value of zero.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-
-* A local status value:
-* 0 - Success
-* 1 - Could not lock or unlock the object because it was already
-* locked by another thread.
-* 2 - Failed to lock a POSIX mutex
-* 3 - Failed to unlock a POSIX mutex
-* 4 - Bad "mode" value supplied.
-
-* Notes:
-* - This function attempts to execute even if an error has already
-* occurred.
-*/
-
-/* Local Variables: */
- AstFitsChan *this; /* Pointer to FitsChan structure */
- int result; /* Returned status value */
-
-/* Initialise */
- result = 0;
-
-/* Check the supplied pointer is not NUL. */
- if( ! this_object ) return result;
-
-/* Obtain a pointers to the FitsChan structure. */
- this = (AstFitsChan *) this_object;
-
-/* Invoke the ManageLock method inherited from the parent class. */
- if( !result ) result = (*parent_managelock)( this_object, mode, extra,
- fail, status );
-
-/* Invoke the astManageLock method on any Objects contained within
- the supplied Object. */
- if( !result ) result = astManageLock( this->keyseq, mode, extra, fail );
- if( !result ) result = astManageLock( this->keywords, mode, extra, fail );
- return result;
-}
-#endif
-
-static int Match( const char *test, const char *temp, int maxfld, int *fields,
- int *nfld, const char *method, const char *class, int *status ){
-/*
-* Name:
-* Match
-
-* Purpose:
-* Sees if a test keyword name matches a template.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int Match( const char *test, const char *temp, int maxfld, int *fields,
-* int *nfld, const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* All characters in the template other than "%" (and the field width
-* and type specifiers which follow a "%") must be matched by an
-* identical character (ignoring case) in the test string. If a "%" occurs
-* in the template, then the next character in the template should be a
-* single digit specifying a field width. If it is zero, then the test
-* string may contain zero or more matching characters. Otherwise,
-* the test string must contain exactly the specified number of matching
-* characters (i.e. 1 to 9). The field width digit may be omitted, in
-* which case the test string must contain one or more matching
-* characters. The next character in the template specifies the type of
-* matching characters and must be one of "d", "c" or "f". Decimal digits
-* are matched by "d", all upper (but not lower) case alphabetical
-* characters are matched by "c", and all characters which are legal within
-* a FITS keyword (i.e. upper case letters, digits, underscores and
-* hyphens) are matched by "f".
-
-* Parameters:
-* test
-* Pointer to a null terminated string holding the keyword name to
-* be tested.
-* temp
-* Pointer to a null terminated string holding the template.
-* maxfld
-* The maximum number of integer field values which should be
-* returned in "fields".
-* fields
-* A pointer to an array of at least "maxfld" integers. This is
-* returned holding the values of any integer fields specified
-* in the template. The values are extracted from the test string,
-* and stored in the order they appear in the template string.
-* nfld
-* Pointer to a location at which is returned the total number of
-* integer fields in the test string. This may be more than the
-* number returned in "fields" if "maxfld" is smaller than "*nfld".
-* 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:
-* Zero is returned if the test string does not match the template
-* string, and one is returned if it does.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- char type; /* Field type specifier */
- const char *a; /* Pointer to next test character */
- const char *b; /* Pointer to next template character */
- int extend; /* Can the width of the first field be extended? */
- int i; /* Field index */
- int match; /* Does "test" match "temp"? */
- int nfret; /* No. of fields returned */
- int tmp; /* Field value */
-
-/* Check global status. */
- if( !astOK ) return 0;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(NULL);
-
-/* On the first entry to this function, indicate that no integer fields
- have yet been returned, and save a pointer to the start of the template
- string. */
- if( !match_nentry ) {
- *nfld = 0;
- match_template = temp;
- }
-
-/* Increment the number of entries into this function. */
- match_nentry++;
-
-/* Initialise pointers to the start of each string. */
- a = test;
- b = temp;
-
-/* Initialise the returned flag to indicate that the two strings do not
- match. */
- match = 0;
-
-/* Check that the initial part of the test string can match the first
- field in the template. */
- if( MatchFront( a, b, &type, &extend, &match_na, &match_nb, method, class, match_template, status ) ){
-
-/* If it does, increment the pointers to skip over the characters
- used up in the comparison. */
- a += match_na;
- b += match_nb;
-
-/* If the ends of both strings have been reached, they match. */
- if( *a == 0 && *b == 0 ){
- match = 1;
-
-/* Otherwise, if the end of the template has been reached but there are
- still characters to be read from the test string, we could still have
- a match if all the remaining test characters match an extandable field. */
- } else if( *b == 0 && *a != 0 && extend ){
-
-/* Loop until all the matching characters have been read from the end of
- the test string. */
- while( *a != 0 && MatchChar( *a, type, method, class, match_template, status ) ) a++;
-
-/* If we reached the end of the test string, we have a match. */
- if( *a == 0 ) match = 1;
-
-/* Otherwise, we need to carry on checking the remaining fields. */
- } else {
-
-/* Call this function recursively to see if the remainder of the
- strings match. */
- if( Match( a, b, maxfld, fields, nfld, method, class, status ) ){
- match = 1;
-
-/* If the remainder of the strings do not match, we may be able to make
- them match by using up some extra test characters on the first field.
- This can only be done if the first field has an unspecified field width,
- and if the next test character if of a type which matches the first
- field in the template. */
- } else if( extend ){
-
-/* Loop until all the suitable characters have been read from the
- test string. Break out of the loop early if we find a field width
- which results in the whole string matching. */
- while( MatchChar( *a, type, method, class, match_template, status ) ){
- a++;
- if( Match( a, b, maxfld, fields, nfld, method, class, status ) ){
- match = 1;
- break;
- }
- }
- }
- }
- }
-
-/* If the strings match and the leading field is an integer, decode
- the field and store it in the supplied array (if there is room). */
- if( match && type == 'd' && a > test ){
- if( *nfld < maxfld ){
- sprintf( match_fmt, "%%%dd", (int) ( a - test ) );
- astSscanf( test, match_fmt, fields + *nfld );
- }
- (*nfld)++;
- }
-
-/* Decrement the number of entries into this function. */
- match_nentry--;
-
-/* If we are leaving this function for the last time, reverse the
- order of the returned integer fields so that they are returned
- in the same order that they occur in the template. */
- if( !match_nentry ){
- nfret = ( *nfld < maxfld ) ? (*nfld) : maxfld;
- match_pa = fields;
- match_pb = fields + nfret - 1;
- for( i = 0; i < nfret/2; i++ ){
- tmp = *match_pa;
- *(match_pa++) = *match_pb;
- *(match_pb--) = tmp;
- }
- }
-
-/* Return the result. */
- return match;
-}
-
-static int MatchChar( char test, char type, const char *method,
- const char *class, const char *template, int *status ){
-/*
-* Name:
-* MatchChar
-
-* Purpose:
-* See if a given character is of a specified type.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int MatchChar( char test, char type, const char *method,
-* const char *class, const char *template, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function checks that the supplied test character belongs
-* to the set of characters specified by the parameter "type".
-
-* Parameters:
-* test
-* The character to test.
-* type
-* The character specifying the set of acceptable characters. This
-* should be one of the field type characters accepted by function
-* Match (e.g. "d", "c" or "f").
-* 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.
-* template
-* Pointer to the start of the whole template string, for use in error
-* messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero is returned if the test character does not belongs to the
-* specified character set, and one is returned if it does.
-
-* Notes:
-* - An error is reported if the type specifier is not legal.
-* - Zero is returned if an error has already occurred, or if ths
-* function fails for any reason.
-*/
-
-/* Local Variables: */
- int ret; /* Returned flag */
-
-/* Check global status. */
- ret = 0;
- if( !astOK ) return ret;
-
-/* Check for "d" specifiers (digits). */
- if( type == 'd' ){
- ret = isdigit( (int) test );
-
-/* Check for "c" specifiers (upper case letters). */
- } else if( type == 'c' ){
- ret = isupper( (int) test );
-
-/* Check for "s" specifiers (any legal FITS keyword character). */
- } else if( type == 'f' ){
- ret = isFits( (int) test );
-
-/* Report an error for any other specifier. */
- } else if( astOK ){
- ret = 0;
- astError( AST__BDFMT, "%s(%s): Illegal field type or width "
- "specifier '%c' found in filter template '%s'.", status,
- method, class, type, template );
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static int MatchFront( const char *test, const char *temp, char *type,
- int *extend, int *ntest, int *ntemp,
- const char *method, const char *class,
- const char *template, int *status ){
-/*
-* Name:
-* MatchFront
-
-* Purpose:
-* Sees if the start of a test string matches the start of a template.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int MatchFront( const char *test, const char *temp, char *type,
-* int *extend, int *ntest, int *ntemp,
-* const char *method, const char *class,
-* const char *template )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function looks for a match between the first field in the
-* template string and the string at the start of the test string,
-* using the syntax described in function Match.
-
-* Parameters:
-* test
-* Pointer to a null terminated string holding the keyword name to
-* be tested.
-* temp
-* Pointer to a null terminated string holding the template.
-* type
-* Pointer to a location at which to return a character specifying the
-* sort of field that was matched. This will be one of the legal field
-* types accepted by Match (e.g. "d", "c" or "f"), or null (zero) if
-* the first field in the template string was a literal character (i.e.
-* did not start with a "%").
-* extend
-* Pointer to a location at which to return a flag which will be non-zero
-* if the further test characters could be matched by the first field in
-* the template. This will be the case if the template field only
-* specifies a minimum number of matching characters (i.e. if the field
-* width can be extended). For instance, "%d" can be extended, but "%1d"
-* cannot.
-* ntest
-* Pointer to a location at which to return the number of characters
-* matched in the test string. This will be the minimum number allowed
-* by the template field.
-* ntemp
-* Pointer to a location at which to return the number of characters
-* read from the template string (i.e. the number of characters in the
-* field specification).
-* 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.
-* template
-* Pointer to the start of the whole template string, for use in error
-* messages.
-
-* Returned Value:
-* Zero is returned if the test string starts with fewer than the
-* minimum number of characters matching the template string, and one
-* is returned if it does.
-
-* Notes:
-* - Zero is returned if an error has already occurred, or if this
-* function fails for any reason.
-*/
-
-/* Local Variables: */
- const char *a; /* Pointer to next test character */
- const char *b; /* Pointer to next template character */
- int i; /* Character index */
- int match; /* Does "test" match "temp"? */
-
-/* Check global status. */
- if( !astOK ) return 0;
-
-/* Initialise pointers to the start of each string. */
- a = test;
- b = temp;
-
-/* Initialise the returned value to indicate that the strings match. */
- match = 1;
-
-/* If the current character in the template is not a % sign, it must
- match the current character in the test string (except for case). */
- if( *b != '%' ){
- if( toupper( (int) *b ) != toupper( (int) *a ) ) {
- match = 0;
-
-/* If the characters match, return all the required information. */
- } else {
- *type = 0;
- *extend = 0;
- *ntest = 1;
- *ntemp = 1;
- }
-
-/* If the current character of the template is a %, we need to match
- a field. */
- } else {
- *ntemp = 3;
-
-/* The next character in the template string determines the field width.
- Get the lowest number of characters which must match in the test string,
- and set a flag indicating if this lowest limit can be extended. */
- b++;
- if( *b == '0' ){
- *ntest = 0;
- *extend = 1;
- } else if( *b == '1' ){
- *ntest = 1;
- *extend = 0;
- } else if( *b == '2' ){
- *ntest = 2;
- *extend = 0;
- } else if( *b == '3' ){
- *ntest = 3;
- *extend = 0;
- } else if( *b == '4' ){
- *ntest = 4;
- *extend = 0;
- } else if( *b == '5' ){
- *ntest = 5;
- *extend = 0;
- } else if( *b == '6' ){
- *ntest = 6;
- *extend = 0;
- } else if( *b == '7' ){
- *ntest = 7;
- *extend = 0;
- } else if( *b == '8' ){
- *ntest = 8;
- *extend = 0;
- } else if( *b == '9' ){
- *ntest = 9;
- *extend = 0;
-
-/* If no field width was given, one or more test characters are matched.
- Step back a character so that the current character will be re-used as
- the type specifier. */
- } else {
- *ntest = 1;
- *extend = 1;
- b--;
- (*ntemp)--;
- }
-
-/* The next template character gives the type of character which should
- be matched. */
- b++;
- *type = *b;
-
-/* Report an error if the template string ended within the field
- specifier. */
- if( !*b ){
- match = 0;
- astError( AST__BDFMT, "%s(%s): Incomplete field specifier found "
- "at end of filter template '%s'.", status, method, class,
- template );
-
-/* Otherwise, check that the test string starts with the minimum allowed
- number of characters matching the specified type. */
- } else {
- for( i = 0; i < *ntest; i++ ){
- if( !MatchChar( *a, *type, method, class, template, status ) ){
- match = 0;
- break;
- }
- a++;
- }
- }
- }
-
-/* Return the answer. */
- return match;
-}
-
-static void MarkCard( AstFitsChan *this, int *status ){
-
-/*
-* Name:
-* MarkCard
-
-* Purpose:
-* Mark the current card as having been read into an AST object.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void MarkCard( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The current card is marked as having been "provisionally used" in
-* the construction of an AST object. If the Object is constructed
-* succesfully, such cards are marked as having been definitely used,
-* and they are then considered to have been removed from the FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan containing the list of cards.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - The card remains the current card even though it is now marked
-* as having been read.
-*/
- int flags;
-
-/* Return if the global error status has been set, or the current card
- is not defined. */
- if( !astOK || !this->card ) return;
-
-/* Set the PROVISIONALLY_USED flag in the current card, but only if the
- PROTECTED flag is not set. */
- flags = ( (FitsCard *) this->card )->flags;
- if( !( flags & PROTECTED ) ) {
- ( (FitsCard *) this->card )->flags = flags | PROVISIONALLY_USED;
- }
-}
-
-static int MoveCard( AstFitsChan *this, int move, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* MoveCard
-
-* Purpose:
-* Move the current card a given number of cards forward or backwards.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int MoveCard( AstFitsChan *this, int move, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The current card is increment by the given number of cards, ignoring
-* cards which have been read into an AST object if the ignore_used flag
-* is set non-zero.
-
-* Parameters:
-* this
-* Pointer to the FitsChan containing the list of cards.
-* move
-* The number of cards by which to move the current card. Positive
-* values move towards the end-of-file. Negative values move
-* towards the start of the file (i.e. the list head).
-* method
-* Pointer to string holding name of calling method.
-* class
-* Pointer to string holding object class.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The number of cards actually moved. This may not always be equal to
-* the requested number (for instance, if the end or start of the
-* FitsChan is encountered first).
-
-* Notes:
-* - If the end-of-file is reached before the required number of
-* cards have been skipped, the current card is set NULL, to indicate
-* an end-of-file condition.
-* - If the start of the file is reached before the required number of
-* cards have been skipped, the current card is left pointing to the
-* first usable card.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- FitsCard *card; /* The current card */
- FitsCard *card0; /* The previous non-deleted card */
- int moved; /* The number of cards moved by so far */
-
-/* Return if the supplied object is NULL or the FitsChan is
- empty, or zero movement is requested. */
- if( !this || !this->head || !move ) return 0;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Get a pointer to the current card. */
- card = (FitsCard *) this->card;
-
-/* Initialise the number of cards moved so far. */
- moved = 0;
-
-/* First deal with positive movements (towards the end-of-file). */
- if( move > 0 ){
-
-/* Loop round moving on to the next card until the correct number of
- moves have been made, or the end-of-file is reached. */
- while( moved < move && card ){
-
-/* Get a pointer to the next card in the list, reporting an error if the
- links are inconsistent. */
- card = GetLink( card, NEXT, method, class, status );
-
-/* If we have moved past the last card and are now pointing back at the
- list head, then indicate that we are at end-of-file by setting the
- card pointer NULL. */
- if( (void *) card == this->head ){
- card = NULL;
-
-/* Otherwise, increment the number of cards moved. We ignore cards which
- have been read into an AST object if the external "ignore_used" flag is
- set. */
- } else if( card ){
- if( !CARDUSED(card) ) moved++;
- }
- }
-
-/* Now deal with negative movements (towards the list head), so long as
- we are not currently at the list head. */
- } else if( (void *) card != this->head ){
-
-/* If we are currently at end-of-file, replace the NULL pointer for the
- current card with a pointer to the list head. The first step backwards
- will make the last card the current card. */
- if( !card ) card = (FitsCard *) this->head;
-
-/* Loop round until the correct number of cards have been moved. */
- while( moved < -move && card ){
-
-/* If cards which have been read into an AST object are to be included in the
- count of moved cards, get a pointer to the previous card in the list,
- reporting an error if the links are inconsistent. */
- if( !ignore_used ){
- card = GetLink( card, PREVIOUS, method, class, status );
-
-/* If cards which have been read into an AST object are to be ignored... */
- } else {
-
-/* We need to find the previous card which has not been read into an AST
- object. We do not search beyond the start of the list. */
- card0 = GetLink( card, PREVIOUS, method, class, status );
- while( card0 && CARDUSED(card0) && (void *) card0 != this->head ){
- card0 = GetLink( card0, PREVIOUS, method, class, status );
- }
-
-/* If no such card was found we leave the card where it is. */
- if( card0 && ( card0->flags & USED ) ) {
- break;
-
-/* Otherwise, move back to card found above. */
- } else {
- card = card0;
- }
- }
-
-/* Increment the number of cards moved. */
- moved++;
-
-/* If the current card is the list head, break out of the loop. */
- if( (void *) card == this->head ) break;
- }
- }
-
-/* Store the new current card. */
- this->card = (void *) card;
-
-/* Return the answer. */
- return moved;
-}
-
-static double NearestPix( AstMapping *map, double val, int axis, int *status ){
-/*
-* Name:
-* NearestPix
-
-* Purpose:
-* Find an axis value which corresponds to an integer pixel value.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* double NearestPix( AstMapping *map, double val, int axis, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The supplied axis value is transformed using the inverse of the
-* supplied Mapping (other axes are given the value AST__BAD). The
-* resulting axis values are rounded to the nearest whole number, and
-* then transformed back using the supplied Mapping in the forward
-* direction. If the nominated axis value is good, it is returned as
-* the function value, otherwise the supplied value is returned unchanged.
-
-* Parameters:
-* map
-* A Mapping (usually the input coordinates will correspond to
-* pixel coordinates).
-* val
-* A value for one of the outputs of the "map" Mapping.
-* axis
-* The index of the Mapping output to which "val" refers.
-* status
-* Pointer to the inherited status variable.
-
-* Retuned Value:
-* The modified output axis value.
-*/
-
-/* Local Variables: */
- AstMapping *tmap; /* Mapping to be used */
- AstPointSet *pset1; /* Pixel coords PointSet */
- AstPointSet *pset2; /* WCS coords PointSet */
- double **ptr1; /* Pointer to data in pset1 */
- double **ptr2; /* Pointer to data in pset2 */
- double result; /* Returned value */
- int *ins; /* Array holding input axis indices */
- int i; /* Loop count */
- int nin; /* Number of Mapping inputs */
- int nout; /* Number of Mapping outputs */
-
-/* Initialise. */
- result = val;
-
-/* Check inherited status, and that the supplied value is good. */
- if( !astOK || result == AST__BAD ) return result;
-
-/* If the supplied Mapping has no inverse, trying splitting off the
- transformation for the required axis, which may have an inverse.
- If succesful, use the 1-in,1-out Mapping returned by astMapSPlit
- instead of the supplied Mapping, and adjust the axis index accordingly. */
- if( !astGetTranInverse( map ) ) {
- astInvert( map );
- ins = astMapSplit( map, 1, &axis, &tmap );
- if( tmap ) {
- astInvert( tmap );
- axis = 0;
- } else {
- tmap = astClone( map );
- }
- ins = astFree( ins );
- astInvert( map );
- } else {
- tmap = astClone( map );
- }
-
-/* If the Mapping still has no inverse, return the supplied value
- unchanged. */
- if( astGetTranInverse( tmap ) ) {
-
-/* Get the number of input and output coordinates. */
- nin = astGetNin( tmap );
- nout = astGetNout( tmap );
-
-/* Create PointSets to hold a single input position and the corresponding
- output position. */
- pset1 = astPointSet( 1, nin, "", status );
- ptr1 = astGetPoints( pset1 );
- pset2 = astPointSet( 1, nout, "", status );
- ptr2 = astGetPoints( pset2 );
- if( astOK ) {
-
-/* Assign AST__BAD values to all output axes, except for the specified
- axis, which is given the supplied axis value. */
- for( i = 0; i < nout; i++ ) ptr2[ i ][ 0 ] = AST__BAD;
- ptr2[ axis ][ 0 ] = val;
-
-/* Transform this output position into an input position. */
- (void) astTransform( tmap, pset2, 0, pset1 );
-
-/* Round all good axis values in the resulting input position to the nearest
- integer. */
- for( i = 0; i < nin; i++ ) {
- if( ptr1[ i ][ 0 ] != AST__BAD ) {
- ptr1[ i ][ 0 ] = (int) ( ptr1[ i ][ 0 ] + 0.5 );
- }
- }
-
-/* Transform this input position back into output coords. */
- (void) astTransform( tmap, pset1, 1, pset2 );
-
-/* If the resulting axis value is good, return it. */
- if( ptr2[ axis ] [ 0 ] != AST__BAD ) result = ptr2[ axis ] [ 0 ];
- }
-
-/* Free resources. */
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
- }
- tmap = astAnnul( tmap );
-
-/* Return the result. */
- return result;
-}
-
-static void NewCard( AstFitsChan *this, const char *name, int type,
- const void *data, const char *comment, int flags,
- int *status ){
-
-/*
-* Name:
-* NewCard
-
-* Purpose:
-* Insert a new card in front of the current card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void NewCard( AstFitsChan *this, const char *name, int type,
-* const void *data, const char *comment, int flags,
-* int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The supplied keyword name, data type and value, and comment are
-* stored in a new FitsCard structure, and this structure is
-* inserted into the circular linked list stored in the supplied
-* FitsChan. It is inserted in front of the current card.
-
-* Parameters:
-* this
-* Pointer to the FitsChan containing the list of cards.
-* name
-* Pointer to a string holding the keyword name of the new card.
-* type
-* An integer value representing the data type of the keyword.
-* data
-* Pointer to the data associated with the keyword.
-* comment
-* Pointer to a null-terminated string holding a comment.
-* flags
-* The flags to assign to the card.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - The new card is inserted into the list in front of the current card,
-* so that the "next" link from the new card points to the current card.
-* If the FitsChan is currently at end-of-file (indicated by a NULL
-* pointer being stored for the current card), then the card is appended
-* to the end of the list. The pointer to the current card is left
-* unchanged.
-* - Keyword names are converted to upper case before being stored.
-* - Any trailing white space in a string value is saved as supplied.
-* - Logical values are converted to zero or one before being stored.
-* - The "comment" and/or "data" pointers may be supplied as NULL.
-*/
-
-/* Local Variables: */
- FitsCard *new; /* Pointer to the new card */
- FitsCard *prev; /* Pointer to the previous card in the list */
- char *b; /* Pointer to next stored character */
- const char *a; /* Pointer to next supplied character */
- int lval; /* Logical data value restricted to 0 or 1 */
- int nc; /* No. of characters to store */
-
-/* Check the global status. */
- if( !astOK ) return;
-
-/* Get memory to hold the new FitsCard structure. */
- new = (FitsCard *) astMalloc( sizeof( FitsCard ) );
-
-/* Check the pointer can be used. */
- if( astOK ){
-
-/* Copy the keyword name, converting to upper case. */
- a = name;
- b = new->name;
- while( *a ) *(b++) = (char) toupper( (int) *(a++) );
- *b = 0;
-
-/* Ensure that a KeyMap exists to hold the keywords currently in the
- FitsChan. */
- if( !this->keywords ) this->keywords = astKeyMap( " ", status );
-
-/* Add the keyword name to the KeyMap. The value associated with the
- KeyMap entry is not used and is set arbitrarily to zero. */
- astMapPut0I( this->keywords, new->name, 0, NULL );
-
-/* Copy the data type. */
- new->type = type;
-
-/* Copy any data (ignore any data supplied for an UNDEF value). */
- if( data && type != AST__UNDEF ){
-
-/* Logical values are converted to zero or one before being stored. */
- if( type == AST__LOGICAL ){
- lval = *( (int *) data ) ? 1 : 0;
- new->size = sizeof( int );
- new->data = astStore( NULL, (void *) &lval, sizeof( int ) );
-
-/* String values... */
- } else if( type == AST__STRING || type == AST__CONTINUE ){
-
-/* Find the number of characters excluding the trailing null character. */
- nc = strlen( data );
-
-/* Store the string, reserving room for a terminating null. */
- new->size = (size_t)( nc + 1 );
- new->data = astStore( NULL, (void *) data, (size_t)( nc + 1 ) );
-
-/* Terminate it. */
- ( (char *) new->data)[ nc ] = 0;
-
-/* Other types are stored as supplied. */
- } else if( type == AST__INT ){
- new->size = sizeof( int );
- new->data = astStore( NULL, (void *) data, sizeof( int ) );
- } else if( type == AST__FLOAT ){
- new->size = sizeof( double );
- new->data = astStore( NULL, (void *) data, sizeof( double ) );
- } else if( type == AST__COMPLEXF ){
- if( *( (double *) data ) != AST__BAD ) {
- new->size = 2*sizeof( double );
- new->data = astStore( NULL, (void *) data, 2*sizeof( double ) );
- } else {
- nc = strlen( BAD_STRING );
- new->size = (size_t)( nc + 1 );
- new->data = astStore( NULL, BAD_STRING, (size_t)( nc + 1 ) );
- ( (char *) new->data)[ nc ] = 0;
- }
- } else if( type == AST__COMPLEXI ){
- new->size = 2*sizeof( int );
- new->data = astStore( NULL, (void *) data, 2*sizeof( int ) );
- } else {
- new->size = 0;
- new->data = NULL;
- }
- } else {
- new->size = 0;
- new->data = NULL;
- }
-
-/* Find the first non-blank character in the comment, and find the used
- length of the remaining string. We retain leading and trailing white
- space if the card is a COMMENT card. */
- if( comment ){
- a = comment;
- if( type != AST__COMMENT ) {
- while( isspace( *a ) ) a++;
- nc = ChrLen( a, status );
- } else {
- nc = strlen( a );
- }
- } else {
- nc = 0;
- }
-
-/* Copy any comment, excluding leading and trailing white space unless
- this is a COMMENT card */
- if( nc > 0 ){
- new->comment = astStore( NULL, (void *) a, (size_t)( nc + 1 ) );
- ( (char *) new->comment)[ nc ] = 0;
- } else {
- new->comment = NULL;
- }
-
-/* Set the supplied flag values. */
- new->flags = flags;
-
-/* Insert the copied card into the list, in front of the current card. If
- the current card is the list head, make the new card the list head. */
- if( this->card ){
- prev = ( ( FitsCard *) this->card )->prev;
- ( ( FitsCard *) this->card )->prev = new;
- new->prev = prev;
- prev->next = new;
- new->next = (FitsCard *) this->card;
- if( this->card == this->head ) this->head = (void *) new;
-
-/* If the FitsChan is at end-of-file, append the new card to the end of
- the list (i.e. insert it just before the list head). */
- } else {
- if( this->head ){
- prev = ( (FitsCard *) this->head )->prev;
- ( (FitsCard *) this->head )->prev = new;
- new->prev = prev;
- prev->next = new;
- new->next = (FitsCard *) this->head;
-
-/* If there are no cards in the list, start a new list. */
- } else {
- new->prev = new;
- new->next = new;
- this->head = (void *) new;
- this->card = NULL;
- }
- }
- }
-
-/* Return. */
- return;
-}
-
-static AstMapping *NonLinSpecWcs( AstFitsChan *this, char *algcode,
- FitsStore *store, int i, char s,
- AstSpecFrame *specfrm, const char *method,
- const char *class, int *status ) {
-
-/*
-* Name:
-* NonLinSpecWcs
-
-* Purpose:
-* Create a Mapping describing a FITS-WCS non-linear spectral algorithm
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* AstMapping *NonLinSpecWcs( AstFitsChan *this, char *algcode,
-* FitsStore *store, int i, char s,
-* AstSpecFrame *specfrm, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function uses the contents of the supplied FitsStore to create
-* a Mapping which goes from Intermediate World Coordinate (known as "w"
-* in the context of FITS-WCS paper III) to the spectral system
-* described by the supplied SpecFrame.
-*
-* The returned Mapping implements the non-linear "X2P" algorithms
-* described in FITS-WCS paper III. The axis is linearly sampled in
-* system "X" but expressed in some other system (specified by the
-* supplied SpecFrame).
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* algcode
-* Pointer to a string holding the non-linear "-X2P" code for the
-* required algorithm. This includes aleading "-" character.
-* store
-* Pointer to the FitsStore structure holding the values to use for
-* the WCS keywords.
-* i
-* The zero-based index of the spectral axis within the FITS header
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* specfrm
-* Pointer to the SpecFrame. This specified the "S" system - the
-* system in which the CRVAL kewyords (etc) are specified.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to a Mapping, or NULL if an error occurs.
-*/
-
-/* Local Variables: */
- AstFrameSet *fs;
- AstMapping *map1;
- AstMapping *ret;
- AstSpecFrame *xfrm;
- AstMapping *map2;
- char buf[ 100 ];
- char pc;
- double crv;
- double ds;
- double in_a;
- double in_b;
- double out_a;
- double out_b;
- int ok;
- int s_sys;
-
-/* Check the global status. */
- ret = NULL;
- if( !astOK ) return ret;
-
-/* Identify the spectral "X" system within the "X2P" algorithm code, and
- create a SpecFrame describing the X system ("X" is the system in
- which the axis is linearly sampled). This is done by copying the
- supplied SpecFrame and then setting its System attribute. Copying
- the supplied SpecFrame ensures that all the other attributes (RestFreq,
- etc.) are set correctly. */
- ok = 1;
- xfrm = astCopy( specfrm );
- if( algcode[ 1 ] == 'F' ) {
- astSetSystem( xfrm, AST__FREQ );
- astSetUnit( xfrm, 0, "Hz" );
- } else if( algcode[ 1 ] == 'W' ) {
- astSetSystem( xfrm, AST__WAVELEN );
- astSetUnit( xfrm, 0, "m" );
- } else if( algcode[ 1 ] == 'V' ) {
- astSetSystem( xfrm, AST__VREL );
- astSetUnit( xfrm, 0, "m/s" );
- } else if( algcode[ 1 ] == 'A' ) {
- astSetSystem( xfrm, AST__AIRWAVE );
- astSetUnit( xfrm, 0, "m" );
- } else {
- ok = 0;
- }
-
-/* If the X system was identified, find a Mapping from the "S" (specfrm)
- system to the X system. */
- map1 = NULL;
- if( ok ) {
- ok = 0;
- fs = astConvert( specfrm, xfrm, "" );
- if( fs ) {
- map1 = astGetMapping( fs, AST__BASE, AST__CURRENT );
- fs = astAnnul( fs );
- ok = 1;
- }
-
-/* Issue a warning if the "P" system is not the correct one for the given
- "S" system. We can however continue, sine AST interprets illegal "P"
- systems correctly. */
- pc = 0;
- s_sys = astGetSystem( specfrm );
- if( s_sys == AST__FREQ || s_sys == AST__ENERGY ||
- s_sys == AST__WAVENUM || s_sys == AST__VRADIO ) {
- pc = 'F';
- } else if( s_sys == AST__WAVELEN || s_sys == AST__VOPTICAL ||
- s_sys == AST__REDSHIFT ){
- pc = 'W';
- } else if( s_sys == AST__AIRWAVE ) {
- pc = 'A';
- } else if( s_sys == AST__BETA || s_sys == AST__VREL ) {
- pc = 'V';
- } else if( astOK ) {
- pc = algcode[ 3 ];
- astError( AST__INTER, "%s: Function NonLinSpecWcs does not yet "
- "support spectral axes of type %s (internal AST "
- "programming error).", status, method, astGetC( specfrm, "System" ) );
- }
- if( algcode[ 3 ] != pc ) {
- sprintf( buf, "The spectral CTYPE value %s%s is not legal - "
- "using %s%.3s%c instead.", astGetC( specfrm, "System" ),
- algcode, astGetC( specfrm, "System" ), algcode, pc );
- Warn( this, "badctype", buf, method, class, status );
- }
- }
-
-/* If succesfull, use this Mapping to find the reference value (CRVAL)
- in the "X" system. */
- if( ok ) {
-
-/* Get the CRVAL value for the spectral axis (this will be in the S system). */
- crv = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( crv == AST__BAD ) crv = 0.0;
-
-/* Convert it to the X system. */
- astTran1( map1, 1, &crv, 1, &crv );
-
-/* Invert this Mapping so that it forward transformation goes from X to S. */
- astInvert( map1 );
-
-/* Find the rate of change of S with respect to X (dS/dX) at the reference
- point (x = crv). */
- ds = astRate( map1, &crv, 0, 0 );
- if( ds != AST__BAD && ds != 0.0 ) {
-
-/* FITS-WCS paper III says that dS/dw must be 1.0 at the reference point.
- Therefore dX/dw = dX/dS at the reference point. Also, since the spectral
- axis is linear in X, dX/dw must be constant. Therefore the Mapping from
- IWC to X is a WinMap which scales the IWC axis ("w") by dX/dw and adds
- on the X value at the reference point. */
- if( crv != 0.0 ) {
- in_a = 0.0;
- out_a = crv;
- in_b = crv*ds;
- out_b = 2.0*crv;
- map2 = (AstMapping *) astWinMap( 1, &in_a, &in_b, &out_a, &out_b, "", status );
- } else {
- map2 = (AstMapping *) astZoomMap( 1, 1.0/ds, "", status );
- }
-
-/* The Mapping to be returned is the concatenation of the above Mapping
- (from w to X) with the Mapping from X to S. */
- ret = (AstMapping *) astCmpMap( map2, map1, 1, "", status );
- map1 = astAnnul( map1 );
- map2 = astAnnul( map2 );
- }
- }
- xfrm = astAnnul( xfrm );
-
-/* Return the result */
- return ret;
-}
-
-static double *OrthVector( int n, int m, double **in, int *status ){
-/*
-* Name:
-* OrthVector
-
-* Purpose:
-* Find a unit vector which is orthogonal to a set of supplied vectors.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* double *OrthVector( int n, int m, double **in, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A set of M vectors is supplied, each vector being N-dimensional.
-* It is assumed that M < N and that the supplied vectors span M
-* axes within the N dimensional space. An N-dimensional unit vector is
-* returned which is orthogonal to all the supplied vectors.
-*
-* The required vector is orthogonal to all the supplied vectors.
-* Therefore the dot product of the required vector with each of the
-* supplied vectors must be zero. This gives us M equations of the
-
-* form:
-*
-* a1*r1 + a2*r2 + a3*r3 + .... + aN*rN = 0.0
-* b1*r1 + b2*r2 + b3*r3 + .... + bN*rN = 0.0
-* ...
-*
-* where (a1,a2,..,aN), (b1,b2,..,bN), ... are the supplied vectors
-* and (r1,r2,...,rN) is the required vector. Since M is less
-* than N the system of linear simultaneous equations is under
-* specified and we need to assign arbitrary values to some of the
-* components of the required vector in order to allow the equations
-* to be solved. We arbitrarily assume that 1 element of the required
-* vector has value 1.0 and (N-M-1) have value zero. The selection of
-* *which* elements to set constant is based on the magnitudes of the
-* columns of coefficients (a1,b1...), (a2,b2,...), etc. The M components
-* of the required vector which are *not* set constant are the ones which
-* have coefficient columns with the *largest* magnitude. This choice is
-* made in order to minimise the risk of the remaining matrix of
-* coefficients being singular (for instance, if a component of the
-* required vector has a coefficient of zero in every supplied vector
-* then the column magnitude will be zero and that component will be
-* set to 1.0). After choosing the M largest columns, the largest
-* remaining column is assigned a value of 1.0 in the required vector,
-* and all other columns are assigned the value zero in the required
-
-* vector. This means that the above equations becomes:
-*
-* a1*r1 + a2*r2 + a3*r3 + .... + aM*rM = -aM+1
-* b1*r1 + b2*r2 + b3*r3 + .... + bM*rM = -bM+1
-* ...
-*
-* Where the indices are now not direct indices into the supplied and
-* returned vectors, but indices into an array of indices which have
-* been sorted into column magnitude order. This is now a set of MxM
-
-* simultaneous linear equations which we can solve using palDmat:
-*
-* MAT.R = V
-*
-* where MAT is the the matrix of columns (coefficients) on the left
-* hand side of the above set of simultaneous equations, R is the
-* required vector (just the components which have *not* been set
-* constant), and V is a constant vector equal to the column of values
-* on the right hand side in the above set of simultaneous equations.
-* The palDmat function solves this equation to obtain R.
-
-* Parameters:
-* n
-* The number of dimensions
-* m
-* The number of supplied vectors.
-* in
-* A pointer to an array with "m" elements, each element being a
-* pointer to an array with "n" elements. Each of these "n" element
-* array holds one of the supplied vectors.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The pointer to some newly allocated memory holding the returned N
-* dimensional unit vector. The memory should be freed using astFree when
-* no longer needed.
-
-* Notes:
-* - NULL is returned if an error occurs.
-* - NULL is returned (without error) if the required vector cannot
-* be found (.e.g becuase the supplied M vectors span less than M axes).
-*/
-
-/* Local Variables: */
- double *colmag;
- double *d;
- double *e;
- double *mat;
- double *mel;
- double *ret;
- double *rhs;
- double det;
- double sl;
- int *colperm;
- int *iw;
- int done;
- int i;
- int ih;
- int ii;
- int il;
- int j;
- int sing;
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Return if any of the M supplied vectors are NULL. */
- for( i = 0; i < m; i++ ) {
- if( !in[ i ] ) return ret;
- }
-
-/* Allocate rquired memory. */
- ret = astMalloc( sizeof( double )*(size_t) n );
- rhs = astMalloc( sizeof( double )*(size_t) m );
- mat = astMalloc( sizeof( double )*(size_t) m*m );
- iw = astMalloc( sizeof( int )*(size_t) m );
- colmag = astMalloc( sizeof( double )*(size_t) n );
- colperm = astMalloc( sizeof( int )*(size_t) n );
-
-/* Check memory can be used safely. */
- if( astOK ) {
-
-/* Find the magnitude of each column of coefficients in the full set of
- simultaneous linear equations (before setting any components of the
- required vector constant). Also initialise the column permutation array
- to indicate that the columns are in their original order. The outer
- loop loops through the columns and the inner loop loops through rows
- (i.e. equations). */
- for( i = 0; i < n; i++ ) {
- colperm[ i ] = i;
- colmag[ i ] = 0.0;
- for( j = 0; j < m; j++ ) {
- colmag[ i ] += in[ j ][ i ]*in[ j ][ i ];
- }
- }
-
-/* Now re-arrange the column indices within the permutation array so that
- they are in order of decreasing ciolumn magnitude (i.e. colperm[0] will
- be left holding the index of the column with the largest magnitude). A
- simple bubble sort is used. */
- ii = 1;
- done = 0;
- while( !done ) {
- done = 1;
- for( i = ii; i < n; i++ ) {
- ih = colperm[ i ];
- il = colperm[ i - 1 ];
- if( colmag[ ih ] > colmag[ il ] ) {
- colperm[ i ] = il;
- colperm[ i - 1 ] = ih;
- done = 0;
- }
- }
- ii++;
- }
-
-/* The first M elements in "colperm" now hold the indices of the
- columns which are to be used within the MAT matrix, the next element
- of "colperm" hold the index of the column which is to be included in the
- V vector (other elements hold the indices of the columns which are
- being ignored because they will be mutiplied by a value of zero - the
- assumed value of the corresponding components of the returned vector). We
- now copy the these values into arrays which can be passed to palDmat.
- First, initialise a pointer used to step through the mat array. */
- mel = mat;
-
-/* Loop through all the supplied vectors. Get a pointer to the first
- element of the vector. */
- for( i = 0; i < m; i++ ) {
- d = in[ i ];
-
-/* Copy the required M elements of this supplied vector into the work array
- which will be passed to palDmat. */
- for( j = 0; j < m; j++ ) *(mel++) = d[ colperm[ j ] ];
-
-/* Put the next right-hand side value into the "rhs" array. */
- rhs[ i ] = -d[ colperm[ m ] ];
- }
-
-/* Use palDmat to find the first M elements of the returned array. These
- are stored in "rhs", over-writing the original right-hand side values. */
- palDmat( m, mat, rhs, &det, &sing, iw );
-
-/* If the supplied vectors span fewer than M axes, the above call will fail.
- In this case, annul the returned vector. */
- if( sing != 0 ) {
- ret = astFree( ret );
-
-/* If succesful, copy the M elements of the solution vector into the
- required M elements of the returned vector. Also find the squared length
- of the vector. */
- } else {
- sl = 0.0;
- e = rhs;
- for( j = 0; j < m; j++ ) {
- sl += (*e)*(*e);
- ret[ colperm[ j ] ] = *(e++);
- }
-
-/* Put 1.0 into the next element of the returned vector. */
- sl += 1.0;
- ret[ colperm[ m ] ] = 1.0;
-
-/* Fill up the rest of the returned vector with zeros. */
- for( j = m + 1; j < n; j++ ) ret[ colperm[ j ] ] = 0.0;
-
-/* Normalise the returned vector so that it is a unit vector.Also ensure
- that any zeros are "+0.0" insteasd of "-0.0". */
- e = ret;
- sl = sqrt( sl );
- for( j = 0; j < n; e++,j++ ) {
- *e /= sl;
- if( *e == 0.0 ) *e = 0.0;
- }
- }
- }
-
-/* Free workspace. */
- rhs = astFree( rhs );
- mat = astFree( mat );
- iw = astFree( iw );
- colmag = astFree( colmag );
- colperm = astFree( colperm );
-
-/* Free the returned vector if an error has occurred. */
- if( !astOK ) ret = astFree( ret );
-
-/* Return the answer. */
- return ret;
-}
-
-static double **OrthVectorSet( int n, int m, double **in, int *status ){
-/*
-* Name:
-* OrthVectorSet
-
-* Purpose:
-* Find a set of mutually orthogonal vectors.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* double **OrthVectorSet( int n, int m, double **in, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A set of M vectors is supplied, each vector being N-dimensional.
-* It is assumed that the supplied vectors span M axes within the
-* N dimensional space. A pointer to a set of N vectors is returned.
-* The first M returned vectors are copies of the M supplied vectors.
-* The remaining returned vectors are unit vectors chosen to be
-* orthogonal to all other vectors in the returned set.
-
-* Parameters:
-* n
-* The number of dimensions
-* m
-* The number of supplied vectors.
-* in
-* A pointer to an array with "m" elements, each element being a
-* pointer to an array with "n" elements. Each of these "n" element
-* array holds one of the supplied vectors.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The pointer to some newly allocated memory holding the returned N
-* vectors. The pointer locates an array of N elements, each of which
-* is a pointer to an array holding the N elements of a single vector.
-* The memory (including the inner pointers) should be freed using
-* astFree when no longer needed.
-
-* Notes:
-* - NULL is returned if an error occurs.
-* - NULL is returned (without error) if the required vectors cannot
-* be found (e.g. becuase the supplied M vectors span less than M axes).
-*/
-
-/* Local Variables: */
- double **ret;
- int i;
- int bad;
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Allocate required memory. */
- ret = astMalloc( sizeof( double * )*(size_t) n );
-
-/* Check memory can be used safely. */
- bad = 0;
- if( astOK ) {
-
-/* Copy the supplied vectors into the returned array. */
- for( i = 0; i < m; i++ ) {
- ret[ i ] = astStore( NULL, in[ i ], sizeof( double )*n );
- }
-
-/* For the remaining vectors, find a vector which is orthogonal to all
- the vectors currently in the returned set. */
- for( ; i < n; i++ ) {
- ret[ i ] = OrthVector( n, i, ret, status );
- if( !ret[ i ] ) bad = 1;
- }
- }
-
-/* Free the returned vectors if an error has occurred. */
- if( bad || !astOK ) {
- for( i = 0; ret && i < n; i++ ) ret[ i ] = astFree( ret[ i ] );
- ret = astFree( ret );
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static AstMapping *OtherAxes( AstFitsChan *this, AstFrameSet *fs, double *dim,
- int *wperm, char s, FitsStore *store,
- double *crvals, int *axis_done,
- const char *method, const char *class,
- int *status ){
-
-/*
-* Name:
-* OtherAxes
-
-* Purpose:
-* Add values to a FitsStore describing unknown axes in a Frame.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* AstMapping *OtherAxes( AstFitsChan *this, AstFrameSet *fs, double *dim,
-* int *wperm, char s, FitsStore *store,
-* double *crvals, int *axis_done,
-* const char *method, const char *class,
-* int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* FITS WCS keyword values are added to the supplied FitsStore which
-* describe any as yet undescribed axes in the supplied FrameSet. These
-* axes are assumed to be linear and to follow the conventions
-* of FITS-WCS paper I (if in fact they are not linear, then the
-* grid->iwc mapping determined by MakeIntWorld will not be linear and
-* so the axes will be rejected).
-*
-* Note, this function does not store values for keywords which define
-* the transformation from pixel coords to Intermediate World Coords
-* (CRPIX, PC and CDELT), but a Mapping is returned which embodies these
-* values. This Mapping is from the current Frame in the FrameSet (WCS
-* coords) to a Frame representing IWC. The IWC Frame has the same number
-* of axes as the WCS Frame which may be greater than the number of base
-* Frame (i.e. pixel) axes.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* fs
-* Pointer to the FrameSet. The base Frame should represent FITS pixel
-* coordinates, and the current Frame should represent FITS WCS
-* coordinates. The number of base Frame axes should not exceed the
-* number of current Frame axes.
-* dim
-* An array holding the image dimensions in pixels. AST__BAD can be
-* supplied for any unknwon dimensions.
-* wperm
-* Pointer to an array of integers with one element for each axis of
-* the current Frame. Each element holds the zero-based
-* index of the FITS-WCS axis (i.e. the value of "i" in the keyword
-* names "CTYPEi", "CRVALi", etc) which describes the Frame axis.
-* s
-* The co-ordinate version character. A space means the primary
-* axis descriptions. Otherwise the supplied character should be
-* an upper case alphabetical character ('A' to 'Z').
-* store
-* The FitsStore in which to store the FITS WCS keyword values.
-* crvals
-* Pointer to an array holding the default CRVAL value for each
-* axis in the WCS Frame.
-* axis_done
-* An array of flags, one for each Frame axis, which indicate if a
-* description of the corresponding axis has yet been stored in the
-* FitsStore.
-* 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:
-* If any axis descriptions were added to the FitsStore, a Mapping from
-* the current Frame of the supplied FrameSet, to the IWC Frame is returned.
-* Otherwise, a UnitMap is returned. Note, the Mapping only defines the IWC
-* transformation for the described axes. Any other (previously
-* described) axes are passed unchanged by the returned Mapping.
-*/
-
-/* Local Variables: */
- AstFitsTable *table; /* Pointer to structure holding -TAB table info */
- AstFrame *wcsfrm; /* WCS Frame within FrameSet */
- AstMapping *axmap; /* Mapping from WCS to IWC */
- AstMapping *map; /* FITS pixel->WCS Mapping */
- AstMapping *ret; /* Returned Mapping */
- AstMapping *tmap0; /* Pointer to a temporary Mapping */
- AstMapping *tmap1; /* Pointer to a temporary Mapping */
- AstPermMap *pm; /* PermMap pointer */
- AstPointSet *pset1; /* PointSet holding central pixel position */
- AstPointSet *pset2; /* PointSet holding reference WCS position */
- char buf[80]; /* Text buffer */
- const char *lab; /* Pointer to axis Label */
- const char *sym; /* Pointer to axis Symbol */
- double **ptr1; /* Pointer to data for pset1 */
- double **ptr2; /* Pointer to data for pset2 */
- double *lbnd_p; /* Pointer to array of lower pixel bounds */
- double *ubnd_p; /* Pointer to array of upper pixel bounds */
- double crval; /* The value for the FITS CRVAL keyword */
- int *inperm; /* Pointer to permutation array for input axes */
- int *outperm; /* Pointer to permutation array for output axes */
- int extver; /* Table version number for -TAB headers */
- int fits_i; /* FITS WCS axis index */
- int i; /* Loop count */
- int iax; /* WCS Frame axis index */
- int icolindex; /* Index of table column holding index vector */
- int icolmain; /* Index of table column holding main coord array */
- int interp; /* Interpolation method for look-up tables */
- int log_axis; /* Is the axis logarithmically spaced? */
- int nother; /* Number of axes still to be described */
- int npix; /* Number of pixel axes */
- int nwcs; /* Number of WCS axes */
- int tab_axis; /* Can the axis be described by the -TAB algorithm? */
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Get the number of WCS axes. */
- nwcs = astGetNaxes( fs );
-
-/* Count the number of WCS axes which have not yet been described. */
- nother = 0;
- for( iax = 0; iax < nwcs; iax++ ) {
- if( ! axis_done[ iax ] ) nother++;
- }
-
-/* Only proceed if there are some axes to described. */
- if( nother ) {
-
-/* Get a pointer to the WCS Frame. */
- wcsfrm = astGetFrame( fs, AST__CURRENT );
-
-/* Get a pointer to the pixel->wcs Mapping. */
- map = astGetMapping( fs, AST__BASE, AST__CURRENT );
-
-/* Store the number of pixel and WCS axes. */
- npix = astGetNin( fs );
- nwcs = astGetNout( fs );
-
-/* Store the upper and lower pixel bounds. */
- lbnd_p = astMalloc( sizeof( double )*(size_t) npix );
- ubnd_p = astMalloc( sizeof( double )*(size_t) npix );
- if( astOK ) {
- for( iax = 0; iax < npix; iax++ ) {
- lbnd_p[ iax ] = 1.0;
- ubnd_p[ iax ] = ( dim[ iax ] != AST__BAD ) ? dim[ iax ] : 500;
- }
- }
-
-/* Transform the central pixel coords into WCS coords */
- pset1 = astPointSet( 1, npix, "", status );
- ptr1 = astGetPoints( pset1 );
- pset2 = astPointSet( 1, nwcs, "", status );
- ptr2 = astGetPoints( pset2 );
- if( astOK ) {
- for( iax = 0; iax < npix; iax++ ) {
- ptr1[ iax ][ 0 ] = ( dim[ iax ] != AST__BAD ) ? floor( 0.5*dim[ iax ] ) : 1.0;
- }
- (void) astTransform( map, pset1, 1, pset2 );
- }
-
-/* Loop round all WCS axes, producing descriptions of any axes which have not
- yet been described. */
- for( iax = 0; iax < nwcs && astOK; iax++ ) {
- if( ! axis_done[ iax ] ) {
-
-/* Get the (one-based) FITS WCS axis index to use for this Frame axis. */
- fits_i = wperm[ iax ];
-
-/* Use the supplied default CRVAL value. If bad, use the WCS value
- corresponding to the central pixel found above (if this value is bad,
- abort). */
- crval = crvals ? crvals[ iax ] : AST__BAD;
- if( crval == AST__BAD ) crval = ptr2[ iax ][ 0 ];
- if( crval == AST__BAD ) {
- break;
- } else {
- SetItem( &(store->crval), fits_i, 0, s, crval, status );
- }
-
-/* Initialise flags indicating the type of the axis. */
- log_axis = 0;
- tab_axis = 0;
-
-/* Get the table version number to use if we end up using the -TAB
- algorithm. This is the set value of the TabOK attribute (if positive). */
- extver = astGetTabOK( this );
-
-/* See if the axis is linear. If so, create a ShiftMap which subtracts off
- the CRVAL value. */
-
- if( IsMapLinear( map, lbnd_p, ubnd_p, iax, status ) ) {
- crval = -crval;
- tmap0 = (AstMapping *) astShiftMap( 1, &crval, "", status );
- axmap = AddUnitMaps( tmap0, iax, nwcs, status );
- tmap0 = astAnnul( tmap0 );
- crval = -crval;
-
-/* If it is not linear, see if it is logarithmic. If the "log" algorithm is
- appropriate (as defined in FITS-WCS paper III), the supplied Frame (s) is
- related to pixel coordinate (p) by
- s = Sr.EXP( a*p - b ). If this
- is the case, the log of s will be linearly related to pixel coordinates.
- Test this. If the test is passed a Mapping is returned from WCS to IWC. */
- } else if( (axmap = LogAxis( map, iax, nwcs, lbnd_p, ubnd_p,
- crval, status ) ) ) {
- log_axis = 1;
-
-/* If it is not linear or logarithmic, and the TabOK attribute is
- non-zero, describe it using the -TAB algorithm. */
- } else if( extver > 0 ){
-
-/* Get any pre-existing FitsTable from the FitsStore. This is the table
- in which the tabular data will be stored (if the Mapping can be expressed
- in -TAB form). */
- if( !astMapGet0A( store->tables, AST_TABEXTNAME, &table ) ) table = NULL;
-
-/* See if the Mapping can be expressed in -TAB form. */
- tmap0 = IsMapTab1D( map, 1.0, NULL, wcsfrm, dim, iax, fits_i,
- &table, &icolmain, &icolindex, &interp,
- status );
- if( tmap0 ) {
- tab_axis = 1;
-
-/* The values stored in the table index vector are GRID coords. So we
- need to ensure that IWC are equivalent to GRID coords. So set CRVAL
- to zero. */
- crval = 0.0;
-
-/* Store TAB-specific values in the FitsStore. First the name of the
- FITS binary table extension holding the coordinate info. */
- SetItemC( &(store->ps), fits_i, 0, s, AST_TABEXTNAME, status );
-
-/* Next the table version number. This is the set (positive) value for the
- TabOK attribute. */
- SetItem( &(store->pv), fits_i, 1, s, extver, status );
-
-/* Also store the table version in the binary table header. */
- astSetFitsI( table->header, "EXTVER", extver,
- "Table version number", 0 );
-
-/* Next the name of the table column containing the main coords array. */
- SetItemC( &(store->ps), fits_i, 1, s,
- astColumnName( table, icolmain ), status );
-
-/* Next the name of the column containing the index array */
- if( icolindex >= 0 ) SetItemC( &(store->ps), fits_i, 2, s,
- astColumnName( table, icolindex ), status );
-
-/* The interpolation method (an AST extension to the published -TAB
- algorithm, communicated through the QVi_4a keyword). */
- SetItem( &(store->pv), fits_i, 4, s, interp, status );
-
-/* Also store the FitsTable itself in the FitsStore. */
- astMapPut0A( store->tables, AST_TABEXTNAME, table, NULL );
-
-/* Create the WCS -> IWC Mapping (AST uses grid coords as IWC coords for
- the -TAB algorithm). First, get a Mapping that combines the TAB axis
- Mapping( tmap0) in parallel with one or two UnitMaps in order to put
- the TAB axis at the required index. */
- tmap1 = AddUnitMaps( tmap0, iax, nwcs, status );
-
-/* Now get a PermMap that permutes the WCS axes into the FITS axis order. */
- inperm = astMalloc( sizeof( double )*nwcs );
- outperm = astMalloc( sizeof( double )*nwcs );
- if( astOK ) {
- for( i = 0; i < nwcs; i++ ) {
- inperm[ i ] = wperm[ i ];
- outperm[ wperm[ i ] ] = i;
- }
- }
- pm = astPermMap( nwcs, inperm, nwcs, outperm, NULL, "",
- status );
-
-/* Combine these two Mappings in series, to get the Mapping from WCS to
- IWC. */
- axmap = (AstMapping *) astCmpMap( pm, tmap1, 1, " ",
- status );
-
-/* Free resources. */
- inperm = astFree( inperm );
- outperm = astFree( outperm );
- pm = astAnnul( pm );
- tmap0 = astAnnul( tmap0 );
- tmap1 = astAnnul( tmap1 );
- }
- if( table ) table = astAnnul( table );
- }
-
-/* If the axis cannot be described by any of the above methods, we
- pretend it is linear. This will generate a non-linear PIXEL->IWC
- mapping later (in MakeIntWorld) which will cause the write operation
- to fail. */
- if( !axmap ) {
- crval = -crval;
- tmap0 = (AstMapping *) astShiftMap( 1, &crval, "", status );
- axmap = AddUnitMaps( tmap0, iax, nwcs, status );
- tmap0 = astAnnul( tmap0 );
- crval = -crval;
- }
-
-/* Combine the Mapping for this axis in series with those of earlier axes. */
- if( ret ) {
- tmap0 = (AstMapping *) astCmpMap( ret, axmap, 1, "", status );
- (void) astAnnul( ret );
- ret = tmap0;
- } else {
- ret = astClone( axmap );
- }
-
-/* Get axis label and symbol. */
- sym = astGetSymbol( wcsfrm, iax );
- lab = astGetLabel( wcsfrm, iax );
-
-/* The axis symbols are taken as the CTYPE values. Append "-LOG" or "-TAB" if
- the axis is logarithmic or tabular. */
- if( sym && strlen( sym ) ) {
- (void) sprintf( buf, "%s", sym );
- } else {
- (void) sprintf( buf, "AXIS%d", iax + 1 );
- }
- if( log_axis ) {
- SetAlgCode( buf, "-LOG", status );
- } else if( tab_axis ) {
- SetAlgCode( buf, "-TAB", status );
- }
- SetItemC( &(store->ctype), fits_i, 0, s, buf, status );
-
-/* The axis labels are taken as the comment for the CTYPE keywords and as
- the CNAME keyword (but only if a label has been set and is different to
- the symbol). */
- if( lab && lab[ 0 ] && astTestLabel( wcsfrm, iax ) && strcmp( sym, lab ) ) {
- SetItemC( &(store->ctype_com), fits_i, 0, s, (char *) lab, status );
- SetItemC( &(store->cname), fits_i, 0, s, (char *) lab, status );
- } else {
- sprintf( buf, "Type of co-ordinate on axis %d", iax + 1 );
- SetItemC( &(store->ctype_com), fits_i, 0, s, buf, status );
- }
-
-/* If a value has been set for the axis units, use it as CUNIT. */
- if( astTestUnit( wcsfrm, iax ) ){
- SetItemC( &(store->cunit), fits_i, 0, s, (char *) astGetUnit( wcsfrm, iax ), status );
- }
-
-/* Indicate this axis has now been described. */
- axis_done[ iax ] = 1;
-
-/* Release Resources. */
- axmap = astAnnul( axmap );
- }
- }
-
-/* Release Resources. */
- wcsfrm = astAnnul( wcsfrm );
- map = astAnnul( map );
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
- lbnd_p = astFree( lbnd_p );
- ubnd_p = astFree( ubnd_p );
- }
-
-/* If we have a Mapping to return, simplify it. Otherwise, create
- a UnitMap to return. */
- if( ret ) {
- tmap0 = ret;
- ret = astSimplify( tmap0 );
- tmap0 = astAnnul( tmap0 );
- } else {
- ret = (AstMapping *) astUnitMap( nwcs, "", status );
- }
-
-/* Return the result. */
- return ret;
-}
-
-static int PCFromStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* PCFromStore
-
-* Purpose:
-* Store WCS keywords in a FitsChan using FITS-PC encoding.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int PCFromStore( AstFitsChan *this, FitsStore *store,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function copies the WCS information stored in the supplied
-* FitsStore into the supplied FitsChan, using FITS-PC encoding.
-*
-* Zero is returned if the primary axis descriptions cannot be produced.
-* Whether or not secondary axis descriptions can be produced does not
-* effect the returned value (i.e. failure to produce a specific set of
-* secondary axes does not prevent other axis descriptions from being
-* produced).
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore.
-* 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 value of 1 is returned if succesfull, and zero is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- char *comm; /* Pointer to comment string */
- char *cval; /* Pointer to string keyword value */
- char combuf[80]; /* Buffer for FITS card comment */
- char keyname[10]; /* Buffer for keyword name string */
- char primsys[20]; /* Buffer for primnary RADECSYS value */
- char type[MXCTYPELEN];/* Buffer for CTYPE value */
- char s; /* Co-ordinate version character */
- char sign[2]; /* Fraction's sign character */
- char sup; /* Upper limit on s */
- double *c; /* Pointer to next array element */
- double *d; /* Pointer to next array element */
- double *matrix; /* Pointer to Frame PC/CD matrix */
- double *primpc; /* Pointer to primary PC/CD matrix */
- double fd; /* Fraction of a day */
- double mjd99; /* MJD at start of 1999 */
- double primdt; /* Primary mjd-obs value */
- double primeq; /* Primary equinox value */
- double primln; /* Primary lonpole value */
- double primlt; /* Primary latpole value */
- double primpv[10]; /* Primary projection parameter values */
- double val; /* General purpose value */
- int axlat; /* Index of latitude FITS WCS axis */
- int axlon; /* Index of longitude FITS WCS axis */
- int axspec; /* Index of spectral FITS WCS axis */
- int i; /* Axis index */
- int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */
- int is; /* Co-ordinate version index */
- int iymdf[ 4 ]; /* Year, month, date, fractional day */
- int j; /* Axis index */
- int jj; /* SlaLib status */
- int m; /* Parameter index */
- int maxm; /* Upper limit on m */
- int naxis; /* No. of axes */
- int nc; /* Length of string */
- int ok; /* Frame written out succesfully? */
- int prj; /* Projection type */
- int ret; /* Returned value. */
-
-/* Initialise */
- ret = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Find the number of co-ordinate versions in the FitsStore. FITS-PC
- can only encode 10 axis descriptions (including primary). */
- sup = GetMaxS( &(store->crval), status );
- if( sup > 'I' ) return ret;
-
-/* Initialise */
- primdt = AST__BAD;
- primeq = AST__BAD;
- primln = AST__BAD;
- primlt = AST__BAD;
-
-/* Loop round all co-ordinate versions (0-9) */
- primpc = NULL;
- for( s = ' '; s <= sup && astOK; s++ ){
- is = s - 'A' + 1;
-
-/* Assume the Frame can be created succesfully. */
- ok = 1;
-
-/* Save the number of wcs axes */
- val = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- naxis = (int) ( val + 0.5 );
- SetValue( this, FormatKey( "WCSAXES", -1, -1, s, status ),
- &naxis, AST__INT, "Number of WCS axes", status );
- } else {
- naxis = GetMaxJM( &(store->crpix), s, status ) + 1;
- }
-
-/* PC matrix:
- --------- */
-
-/* This encoding does not allow the PC matrix to be specified for each
- version - instead they all share the primary PC matrix. Therefore we
- need to check that all versions can use the primary PC matrix. Allocate
- memory to hold the PC matrix for this version. */
- matrix = (double *) astMalloc( sizeof(double)*naxis*naxis );
- if( matrix ){
-
-/* Fill these array with the values supplied in the FitsStore. */
- c = matrix;
- for( i = 0; i < naxis; i++ ){
- for( j = 0; j < naxis; j++ ){
- *c = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
- if( *c == AST__BAD ) *c = ( i == j ) ? 1.0 : 0.0;
- c++;
- }
- }
-
-/* If we are currently processing the primary axis description, take
- a copy of the PC matrix. */
- if( s == ' ' ) {
- primpc = (double *) astStore( NULL, (void *) matrix,
- sizeof(double)*naxis*naxis );
-
-/* Store each matrix element in turn. */
- c = matrix;
- for( i = 0; i < naxis; i++ ){
- for( j = 0; j < naxis; j++ ){
-
-/* Set the element bad if it takes its default value. */
- val = *(c++);
- if( i == j ){
- if( astEQUAL( val, 1.0 ) ) val = AST__BAD;
- } else {
- if( astEQUAL( val, 0.0 ) ) val = AST__BAD;
- }
-
-/* Only store elements which do not take their default values. */
- if( val != AST__BAD ){
- sprintf( keyname, "PC%.3d%.3d", i + 1, j + 1 );
- SetValue( this, keyname, &val, AST__FLOAT, NULL, status );
- }
- }
- }
-
-/* For secondary axis descriptions, a check is made that the PC values are
- the same as the primary PC values stored earlier. If not, the current
- Frame cannot be stored as a secondary axis description so continue on
- to the next Frame. */
- } else {
- if( primpc ){
- c = matrix;
- d = primpc;
- for( i = 0; i < naxis; i++ ){
- for( j = 0; j < naxis; j++ ){
- if( !astEQUAL( *c, *d ) ){
- ok = 0;
- } else {
- c++;
- d++;
- }
- }
- }
-
-/* Continue with the next Frame if the PC matrix for this Frame is different
- to the primary PC matrix. */
- if( !ok ) goto next;
- }
- }
- matrix = (double *) astFree( (void *) matrix );
- }
-
-/* CDELT:
- ------ */
- for( i = 0; i < naxis; i++ ){
- val = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- goto next;
- }
- sprintf( combuf, "Pixel scale on axis %d", i + 1 );
- if( s == ' ' ) {
- sprintf( keyname, "CDELT%d", i + 1 );
- } else {
- sprintf( keyname, "C%dELT%d", is, i + 1 );
- }
- SetValue( this, keyname, &val, AST__FLOAT, combuf, status );
- }
-
-/* CRPIX:
- ------ */
- for( j = 0; j < naxis; j++ ){
- val = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- goto next;
- }
- sprintf( combuf, "Reference pixel on axis %d", j + 1 );
- if( s == ' ' ) {
- sprintf( keyname, "CRPIX%d", j + 1 );
- } else {
- sprintf( keyname, "C%dPIX%d", is, j + 1 );
- }
- SetValue( this, keyname, &val, AST__FLOAT, combuf, status );
- }
-
-/* CRVAL:
- ------ */
- for( i = 0; i < naxis; i++ ){
- val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- goto next;
- }
- sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 );
- if( s == ' ' ) {
- sprintf( keyname, "CRVAL%d", i + 1 );
- } else {
- sprintf( keyname, "C%dVAL%d", is, i + 1 );
- }
- SetValue( this, keyname, &val, AST__FLOAT, combuf, status );
- }
-
-/* CTYPE:
- ------ */
- for( i = 0; i < naxis; i++ ){
- cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- nc = strlen( cval );
- if( !cval || ( nc > 4 && !strcmp( cval + 4, "-TAB" ) ) ) {
- ok = 0;
- goto next;
- }
- comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status );
- if( !comm ) {
- sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 );
- comm = combuf;
- }
- if( s == ' ' ) {
- sprintf( keyname, "CTYPE%d", i + 1 );
- } else {
- sprintf( keyname, "C%dYPE%d", is, i + 1 );
- }
-
-/* FITS-PC cannot handle celestial axes of type "xxLT" or "xxLN".
- Neither can it handle the "-TAB". */
- if( ( nc > 2 && !strncmp( cval + 2, "LT-", 3 ) ) ||
- ( nc > 2 && !strncmp( cval + 2, "LN-", 3 ) ) ||
- ( nc > 4 && !strncmp( cval + 4, "-TAB", 4 ) ) ){
- ok = 0;
- goto next;
- }
-
-/* Extract the projection type as specified by the last 4 characters
- in the CTYPE keyword value. This will be AST__WCSBAD for non-celestial
- axes. */
- prj = astWcsPrjType( cval + 4 );
-
-/* Change the new SFL projection code to to the older equivalent GLS */
- if( prj == AST__SFL ) {
- strcpy( type, cval );
- (void) strcpy( type + 4, "-GLS" );
- cval = type;
- }
-
-/* FITS-PC cannot handle the AST-specific TPN projection. */
- if( prj == AST__TPN ) {
- ok = 0;
- goto next;
- }
-
-/* Store the CTYPE value */
- SetValue( this, keyname, &cval, AST__STRING, comm, status );
- }
-
-/* Get and save CUNIT for all intermediate axes. These are NOT required, so
- do not pass on if they are not available. */
- for( i = 0; i < naxis; i++ ){
- cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status );
- if( cval ) {
- sprintf( combuf, "Units for axis %d", i + 1 );
- if( s == ' ' ) {
- sprintf( keyname, "CUNIT%d", i + 1 );
- } else {
- sprintf( keyname, "C%dNIT%d", is, i + 1 );
- }
- SetValue( this, keyname, &cval, AST__STRING, combuf, status );
- }
- }
-
-/* Get and save RADESYS. This is NOT required, so do not pass on if it is
- not available. If RADECSYS is provided for a secondary axis, it must
- be the same as the primary axis RADECSYS value. If it is not, pass on to
- the next Frame. */
- cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status );
- if( cval ) {
- if( s == ' ' ) {
- strcpy( primsys, cval );
- SetValue( this, "RADECSYS", &cval, AST__STRING,
- "Reference frame for RA/DEC values", status );
- } else if( strcmp( cval, primsys ) ) {
- ok = 0;
- goto next;
- }
- }
-
-/* Reference equinox. This is NOT required, so do not pass on if it is
- not available. If equinox is provided for a secondary axis, it must
- be the same as the primary axis equinox value. If it is not, pass on to
- the next Frame. */
- val = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status );
- if( s == ' ' ) {
- primeq = val;
- if( val != AST__BAD ) SetValue( this, "EQUINOX", &val, AST__FLOAT,
- "Epoch of reference equinox", status );
- } else if( !astEQUAL( val, primeq ) ){
- ok = 0;
- goto next;
- }
-
-/* Latitude of native north pole. This is NOT required, so do not pass on
- if it is not available. If latpole is provided for a secondary axis, it
- must be the same as the primary axis value. If it is not, pass on to
- the next Frame. */
- val = GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status );
- if( s == ' ' ) {
- primlt = val;
- if( val != AST__BAD ) SetValue( this, "LATPOLE", &val, AST__FLOAT,
- "Latitude of native north pole", status );
- } else if( !EQUALANG( val, primlt ) ){
- ok = 0;
- goto next;
- }
-
-/* Longitude of native north pole. This is NOT required, so do not pass on
- if it is not available. If lonpole is provided for a secondary axis, it
- must be the same as the primary axis value. If it is not, pass on to
- the next Frame. */
- val = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status );
- if( s == ' ' ) {
- primln = val;
- if( val != AST__BAD ) SetValue( this, "LONGPOLE", &val, AST__FLOAT,
- "Longitude of native north pole", status );
- } else if( !EQUALANG( val, primln ) ){
- ok = 0;
- goto next;
- }
-
-/* Date of observation. This is NOT required, so do not pass on if it is
- not available. If mjd-obs is provided for a secondary axis, it must be
- the same as the primary axis value. If it is not, pass on to the next
- Frame. */
- val = GetItem( &(store->mjdobs), 0, 0, s, NULL, method, class, status );
- if( s == ' ' ) {
- primdt = val;
- if( val != AST__BAD ) {
- SetValue( this, "MJD-OBS", &val, AST__FLOAT,
- "Modified Julian Date of observation", status );
-
-/* The format used for the DATE-OBS keyword depends on the value of the
- keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format.
- Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */
- palCaldj( 99, 1, 1, &mjd99, &jj );
- if( val < mjd99 ) {
- palDjcal( 0, val, iymdf, &jj );
- sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ],
- iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) );
- } else {
- palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj );
- palDd2tf( 3, fd, sign, ihmsf );
- sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d",
- iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1],
- ihmsf[2], ihmsf[3] );
- }
-
-/* Now store the formatted string in the FitsChan. */
- cval = combuf;
- SetValue( this, "DATE-OBS", &cval, AST__STRING,
- "Date of observation", status );
- }
- } else if( !astEQUAL( val, primdt ) ){
- ok = 0;
- goto next;
- }
-
-/* Look for the celestial and spectral axes. */
- FindLonLatSpecAxes( store, s, &axlon, &axlat, &axspec, method, class, status );
-
-/* If both longitude and latitude axes are present ...*/
- if( axlon >= 0 && axlat >= 0 ) {
-
-/* Get the CTYPE values for the latitude axis. */
- cval = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status );
-
-/* Extract the projection type as specified by the last 4 characters
- in the CTYPE keyword value. */
- prj = ( cval ) ? astWcsPrjType( cval + 4 ) : AST__WCSBAD;
-
-/* Projection parameters. If provided for a secondary axis, they must be
- the same as the primary axis value. If it is not, pass on to the next
- Frame. PC encoding ignores parameters associated with the longitude
- axis. The old PC TAN projection did not have any parameters.
- Pass on if a TAN projection with parameters is found. The number of
- parameters was limited to 10. Pass on if more than 10 are supplied. */
- maxm = GetMaxJM( &(store->pv), ' ', status );
- for( i = 0; i < naxis; i++ ){
- if( i != axlon ) {
- for( m = 0; m <= maxm; m++ ){
- val = GetItem( &(store->pv), i, m, s, NULL, method, class, status );
- if( s == ' ' ){
- if( val != AST__BAD ) {
- if( i != axlat || prj == AST__TAN || m >= 10 ){
- ok = 0;
- goto next;
- } else {
- SetValue( this, FormatKey( "PROJP", m, -1, ' ', status ), &val,
- AST__FLOAT, "Projection parameter", status );
- }
- }
- if( i == axlat && m < 10 ) primpv[m] = val;
- } else {
- if( ( ( i != axlat || m >= 10 ) && val != AST__BAD ) ||
- ( i == axlat && m < 10 && !astEQUAL( val, primpv[m] ) ) ){
- ok = 0;
- goto next;
- }
- }
- }
- }
- }
- }
-
-/* See if a Frame was sucessfully written to the FitsChan. */
-next:
- ok = ok && astOK;
-
-/* If so, indicate we have something to return. */
- if( ok ) ret = 1;
-
-/* Clear any error status so we can continue to produce the next Frame.
- Retain the error if the primary axes could not be produced. After the
- primary axes, do the A axes. */
- if( s != ' ' ) {
- astClearStatus;
- } else {
- s = 'A' - 1;
- }
-
-/* Remove the secondary "new" flags from the FitsChan. This flag is
- associated with cards which have been added to the FitsChan during
- this pass through the main loop in this function. If the Frame was
- written out succesfully, just clear the flags. If anything went wrong
- with this Frame, remove the flagged cards from the FitsChan. */
- FixNew( this, NEW2, !ok, method, class, status );
-
-/* Set the current card so that it points to the last WCS-related keyword
- in the FitsChan (whether previously read or not). */
- FindWcs( this, 1, 1, 0, method, class, status );
- }
-
-/* Annul the array holding the primary PC matrix. */
- primpc = (double *) astFree( (void *) primpc );
-
-/* Return zero or ret depending on whether an error has occurred. */
- return astOK ? ret : 0;
-}
-
-static void PreQuote( const char *value,
- char string[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ], int *status ) {
-
-/*
-* Name:
-* PreQuote
-
-* Purpose:
-* Pre-quote FITS character data.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void PreQuote( const char *value,
-* char string[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ] )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function processes a string value in such a way that it can
-* be stored as a FITS character value (associated with a keyword)
-* and later retrieved unchanged, except for possible truncation.
-*
-* This pre-processing is necessary because FITS does not regard
-* trailing white space as significant, so it is lost. This
-* function adds double quote (") characters around the string if
-* it is necessary in order to prevent this loss. These quotes are
-* also added to zero-length strings and to strings that are
-* already quoted (so that the original quotes are not lost when
-* they are later un-quoted).
-*
-* This function will silently truncate any string that is too long
-* to be stored as a FITS character value, but will ensure that the
-* maximum number of characters are retained, taking account of any
-* quoting required.
-
-* Parameters:
-* value
-* Pointer to a constant null-terminated string containing the
-* input character data to be quoted. All white space is
-* significant.
-* string
-* A character array into which the result string will be
-* written, with a terminating null. The maximum number of
-* characters from the input string that can be accommodated in
-* this is (AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 4), but this
-* will be reduced if quoting is necessary.
-
-* Notes:
-* - The UnPreQuote function should be used to reverse the effect
-* of this function on a string (apart from any truncation).
-*/
-
-/* Local Variables: */
- int dq; /* Number of double quotes needed */
- int dquotes; /* Final number of double quotes */
- int i; /* Loop counter for input characters */
- int j; /* Counter for output characters */
- int nc; /* Number of characters to be accommodated */
- int sq; /* Number of single quotes needed */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Initialise, setting the default number of double quotes (which
- applies to a zero-length string) to 2. */
- dquotes = 2;
- nc = 0;
- sq = 0;
-
-/* Loop to consider each input character to see if it will fit into
- the result string. */
- for ( i = 0; value[ i ]; i++ ) {
-
-/* If a single quote character is to be included, count it. When the
- string is encoded as FITS character data, these quotes will be
- doubled, so will increase the overall string length by one. */
- if ( value[ i ] == '\'' ) sq++;
-
-/* See how many double quotes are needed around the string (0 or
- 2). These are needed if there is trailing white space that needs
- protecting (this is not significant in FITS and will be removed),
- or if the string already has quotes at either end (in which case an
- extra set is needed to prevent the original ones being removed when
- it is later un-quoted). Note we do not need to double existing
- double quote characters within the string, because the position of
- the ends of the string are known (from the quoting supplied by
- FITS) so only the first and last characters need be inspected when
- un-quoting the string.
- In assessing the number of double quotes, assume the string will be
- truncated after the current character. */
- dq = ( isspace( value[ i ] ) ||
- ( ( value[ 0 ] == '"' ) && ( value[ i ] == '"' ) ) ) ? 2 : 0;
-
-/* See if the length of the resulting string, including the current
- character and all necessary quotes, is too long. If so, give up
- here. */
- if ( ( nc + 1 + dq + sq ) >
- ( AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 4 ) ) break;
-
-/* If the string is not too long, accept the character and note the
- number of double quotes needed. */
- nc = i + 1;
- dquotes = dq;
- }
-
-/* If double quotes are needed, insert the opening quote into the
- output string. */
- j = 0;
- if ( dquotes ) string[ j++ ] = '"';
-
-/* Follow this with the maximum number of input string characters that
- can be accommodated. */
- for ( i = 0; i < nc; i++ ) string[ j++ ] = value[ i ];
-
-/* Append the closing quote if necessary and terminate the output
- string. */
- if ( dquotes ) string[ j++ ] = '"';
- string[ j ] = '\0';
-}
-
-static void PurgeWCS( AstFitsChan *this, int *status ){
-
-/*
-*++
-* Name:
-c astPurgeWCS
-f AST_PURGEWCS
-
-* Purpose:
-* Delete all cards in the FitsChan describing WCS information.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-c void astPurgeWCS( AstFitsChan *this )
-f CALL AST_PURGEWCS( THIS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* deletes all cards in a FitsChan that relate to any of the recognised
-* WCS encodings. On exit, the current card is the first remaining card
-* in the FitsChan.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-*--
-*/
-
-/* Local Variables: */
- AstObject *obj;
- int oldclean;
-
-/* Check the global status. */
- if( !astOK ) return;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Ensure the Clean attribute is set so that WCS keywords are removed
- even if an error occurs. */
- if( astTestClean( this ) ) {
- oldclean = astGetClean( this );
- astSetClean( this, 1 );
- } else {
- astSetClean( this, 1 );
- oldclean = -1;
- }
-
-/* Loop round attempting to read AST objects form the FitsChan. This will
- flag cards as used that are involved in the creation of these object
- (including NATIVE encodings). Ignore any error that ocurs whilst doing
- this. */
- astClearCard( this );
- if( astOK ) {
- int oldreporting = astReporting( 0 );
- obj = astRead( this );
- while( obj ) {
- obj = astAnnul( obj );
- astClearCard( this );
- obj = astRead( this );
- }
- if( !astOK ) astClearStatus;
- astReporting( oldreporting );
- }
-
-/* We now loop round to remove any spurious WCS-related cards left in the
- FitsChan that did not form part of a complete WCS encoding. Find the
- first WCS-related card left in the FitsChan. */
- FindWcs( this, 0, 0, 1, "DeleteWcs", "FitsChan", status );
-
-/* Loop round marking each WCS-related card as used until none are left */
- while( this->card && astOK ) {
-
-/* Mark the current card as having been read. */
- ( (FitsCard*) this->card )->flags = USED;
-
-/* Find the next WCS-related card. */
- FindWcs( this, 0, 0, 0, "DeleteWcs", "FitsChan", status );
- }
-
-/* Rewind the FitsChan. */
- astClearCard( this );
-
-/* Reset the Clean attribute. */
- if( oldclean == -1 ) {
- astClearClean( this );
- } else {
- astSetClean( this, oldclean );
- }
-
-}
-
-static void PutCards( AstFitsChan *this, const char *cards, int *status ) {
-
-/*
-*++
-* Name:
-c astPutCards
-f AST_PUTCARDS
-
-* Purpose:
-* Store a set of FITS header cards in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c void astPutCards( AstFitsChan *this, const char *cards )
-f CALL AST_PUTCARDS( THIS, CARDS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* stores a set of FITS header cards in a FitsChan. The cards are
-* supplied concatenated together into a single character string.
-* Any existing cards in the FitsChan are removed before the new cards
-* are added. The FitsChan is "re-wound" on exit by clearing its Card
-* attribute. This means that a subsequent invocation of
-c astRead
-f AST_READ
-* can be made immediately without the need to re-wind the FitsChan
-* first.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c cards
-f CARDS = CHARACTER * ( * ) (Given)
-c Pointer to a null-terminated character string
-f A character string
-* containing the FITS cards to be stored. Each individual card
-* should occupy 80 characters in this string, and there should be
-* no delimiters, new lines, etc, between adjacent cards. The final
-* card may be less than 80 characters long.
-c This is the format produced by the fits_hdr2str function in the
-c CFITSIO library.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - An error will result if the supplied string contains any cards
-* which cannot be interpreted.
-*--
-*/
-
-/* Local Variables: */
- const char *a; /* Pointer to start of next card */
- int clen; /* Length of supplied string */
- int i; /* Card index */
- int ncard; /* No. of cards supplied */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Empty the FitsChan. */
- astEmptyFits( this );
-
-/* Loop round the supplied string in 80 character segments, inserting
- each segment into the FitsChan as a header card. Allow the last card
- to be less than 80 characters long. */
- clen = strlen( cards );
- ncard = clen/80;
- if( ncard*80 < clen ) ncard++;
- a = cards;
- for( i = 0; i < ncard; i++, a += 80 ) astPutFits( this, a, 1 );
-
-/* Rewind the FitsChan. */
- astClearCard( this );
-}
-
-static void PutFits( AstFitsChan *this, const char card[ AST__FITSCHAN_FITSCARDLEN + 1 ],
- int overwrite, int *status ){
-
-/*
-*++
-* Name:
-c astPutFits
-f AST_PUTFITS
-
-* Purpose:
-* Store a FITS header card in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c void astPutFits( AstFitsChan *this, const char card[ 80 ],
-c int overwrite )
-f CALL AST_PUTFITS( THIS, CARD, OVERWRITE, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function stores a FITS header card in a FitsChan. The card
-f This routine stores a FITS header card in a FitsChan. The card
-* is either inserted before the current card (identified by the
-* Card attribute), or over-writes the current card, as required.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c card
-f CARD = CHARACTER * ( 80 ) (Given)
-c Pointer to a possibly null-terminated character string
-c containing the FITS card to be stored. No more than 80
-c characters will be used from this string (or fewer if a null
-c occurs earlier).
-f A character string string containing the FITS card to be
-f stored. No more than 80 characters will be used from this
-f string.
-c overwrite
-f OVERWRITE = LOGICAL (Given)
-c If this value is zero, the new card is inserted in front of
-f If this value is .FALSE., the new card is inserted in front of
-* the current card in the FitsChan (as identified by the
-c initial value of the Card attribute). If it is non-zero, the
-f initial value of the Card attribute). If it is .TRUE., the
-* new card replaces the current card. In either case, the Card
-* attribute is then incremented by one so that it subsequently
-* identifies the card following the one stored.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - If the Card attribute initially points at the "end-of-file"
-* (i.e. exceeds the number of cards in the FitsChan), then the new
-* card is appended as the last card in the FitsChan.
-* - An error will result if the supplied string cannot be interpreted
-* as a FITS header card.
-*--
-*/
-
-/* Local Variables: */
- char *comment; /* The keyword comment */
- char *name; /* The keyword name */
- char *value; /* The keyword value */
- const char *class; /* Object class */
- const char *method; /* Current method */
- double cfval[2]; /* Complex floating point keyword value */
- double fval; /* floating point keyword value */
- int cival[2]; /* Complex integer keyword value */
- int ival; /* Integer keyword value */
- int len; /* No. of characters to read from the value string */
- int nc; /* No. of characters read from value string */
- int type; /* Keyword data type */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Store the current method, and the class of the supplied object for use
- in error messages.*/
- method = "astPutFits";
- class = astGetClass( this );
-
-/* Split the supplied card up into name, value and commment strings, and
- get pointers to local copies of them. The data type associated with the
- keyword is returned. */
- type = Split( this, card, &name, &value, &comment, method, class, status );
-
-/* Check that the pointers can be used. */
- if( astOK ){
-
-/* Initialise the number of characters read from the value string. */
- nc = 0;
-
-/* Store the number of characters in the value string. */
- len = strlen( value );
-
-/* Read and store floating point values from the value string. NB, this
- list is roughly in the order of descreasing frequency of use (i.e.
- most FITS keywords are simple floating point values, the next most
- common are strings, etc). */
- if( type == AST__FLOAT ){
- if( 1 == astSscanf( value, " %lf %n", &fval, &nc ) && nc >= len ){
- astSetFitsF( this, name, fval, comment, overwrite );
- } else {
- astError( AST__BDFTS, "%s(%s): Unable to read a floating point "
- "FITS keyword value.", status, method, class );
- }
-
-/* Read and store string values from the value string. */
- } else if( type == AST__STRING ){
- astSetFitsS( this, name, value, comment, overwrite );
-
-/* Read and store string values from the value string. */
- } else if( type == AST__CONTINUE ){
- astSetFitsCN( this, name, value, comment, overwrite );
-
-/* Store comment card. */
- } else if( type == AST__COMMENT ){
- astSetFitsCom( this, name, comment, overwrite );
-
-/* Read and store integer values from the value string. */
- } else if( type == AST__INT ){
- if( 1 == astSscanf( value, " %d %n", &ival, &nc ) && nc >= len ){
- astSetFitsI( this, name, ival, comment, overwrite );
- } else {
- astError( AST__BDFTS, "%s(%s): Unable to read an integer FITS "
- "keyword value.", status, method, class );
- }
-
-/* Read and store logical values from the value string. */
- } else if( type == AST__LOGICAL ){
- astSetFitsL( this, name, (*value == 'T'), comment, overwrite );
-
-/* Read and store undefined values from the value string. */
- } else if( type == AST__UNDEF ){
- astSetFitsU( this, name, comment, overwrite );
-
-/* Read and store complex floating point values from the value string. */
- } else if( type == AST__COMPLEXF ){
- if( 2 == astSscanf( value, " %lf %lf %n", cfval, cfval + 1, &nc ) &&
- nc >= len ){
- astSetFitsCF( this, name, cfval, comment, overwrite );
- } else {
- astError( AST__BDFTS, "%s(%s): Unable to read a complex pair "
- "of floating point FITS keyword values.", status, method, class );
- }
-
-/* Read and store complex integer values from the value string. */
- } else if( type == AST__COMPLEXI ){
- if( 2 == astSscanf( value, " %d %d %n", cival, cival + 1, &nc ) &&
- nc >= len ){
- astSetFitsCI( this, name, cival, comment, overwrite );
- } else {
- astError( AST__BDFTS, "%s(%s): Unable to read a complex pair "
- "of integer FITS keyword values.", status, method, class );
- }
-
-/* Report an error for any other type. */
- } else {
- astError( AST__INTER, "%s: AST internal programming error - "
- "FITS data-type '%d' not yet supported.", status, method, type );
- }
-
-/* Give a context message if an error occurred. */
- if( !astOK ){
- astError( astStatus, "%s(%s): Unable to store the following FITS "
- "header card:\n%s\n", status, method, class, card );
- }
- }
-
-/* Free the memory used to hold the keyword name, comment and value
- strings. */
- (void) astFree( (void *) name );
- (void) astFree( (void *) comment );
- (void) astFree( (void *) value );
-}
-
-static void PutTable( AstFitsChan *this, AstFitsTable *table,
- const char *extnam, int *status ) {
-
-/*
-*++
-* Name:
-c astPutTable
-f AST_PUTTABLE
-
-* Purpose:
-* Store a single FitsTable in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c void astPutTable( AstFitsChan *this, AstFitsTable *table,
-c const char *extnam )
-f CALL AST_PUTTABLE( THIS, TABLE, EXTNAM, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* allows a representation of a single FITS binary table to be
-* stored in a FitsChan. For instance, this may provide the coordinate
-* look-up tables needed subequently when reading FITS-WCS headers
-* for axes described using the "-TAB" algorithm. Since, in general,
-* the calling application may not know which tables will be needed -
-* if any - prior to calling
-c astRead, the astTablesSource function
-f AST_READ, the AST_TABLESOURCE routine
-* provides an alternative mechanism in which a caller-supplied
-* function is invoked to store a named table in the FitsChan.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c table
-f TABLE = INTEGER (Given)
-* Pointer to a FitsTable to be added to the FitsChan. If a FitsTable
-* with the associated extension name already exists in the FitsChan,
-* it is replaced with the new one. A deep copy of the FitsTable is
-* stored in the FitsChan, so any subsequent changes made to the
-* FitsTable will have no effect on the behaviour of the FitsChan.
-c extnam
-f EXTNAM = CHARACTER * ( * ) (Given)
-* The name of the FITS extension associated with the table.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - Tables stored in the FitsChan may be retrieved using
-c astGetTables.
-f AST_GETTABLES.
-c - The astPutTables method can add multiple FitsTables in a single call.
-f - The AST_PUTTABLES method can add multiple FitsTables in a single call.
-*--
-*/
-
-/* Local Variables: */
- AstObject *ft;
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Create a KeyMap to hold the tables within the FitsChan, if this has not
- already been done. */
- if( !this->tables ) this->tables = astKeyMap( " ", status );
-
-/* Store a copy of the FitsTable in the FitsChan. */
- ft = astCopy( table );
- astMapPut0A( this->tables, extnam, ft, NULL );
- ft = astAnnul( ft );
-}
-
-static void PutTables( AstFitsChan *this, AstKeyMap *tables, int *status ) {
-
-/*
-*++
-* Name:
-c astPutTables
-f AST_PUTTABLES
-
-* Purpose:
-* Store one or more FitsTables in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c void astPutTables( AstFitsChan *this, AstKeyMap *tables )
-f CALL AST_PUTTABLES( THIS, TABLES, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* allows representations of one or more FITS binary tables to be
-* stored in a FitsChan. For instance, these may provide the coordinate
-* look-up tables needed subequently when reading FITS-WCS headers
-* for axes described using the "-TAB" algorithm. Since, in general,
-* the calling application may not know which tables will be needed -
-* if any - prior to calling
-c astRead, the astTablesSource function
-f AST_READ, the AST_TABLESOURCE routine
-* provides an alternative mechanism in which a caller-supplied
-* function is invoked to store a named table in the FitsChan.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c tables
-f TABLES = INTEGER (Given)
-* Pointer to a KeyMap holding the tables that are to be added
-* to the FitsChan. Each entry should hold a scalar value which is a
-* pointer to a FitsTable to be added to the FitsChan. Any unusable
-* entries are ignored. The key associated with each entry should be
-* the name of the FITS binary extension from which the table was
-* read. If a FitsTable with the associated key already exists in the
-* FitsChan, it is replaced with the new one. A deep copy of each
-* usable FitsTable is stored in the FitsChan, so any subsequent
-* changes made to the FitsTables will have no effect on the
-* behaviour of the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - Tables stored in the FitsChan may be retrieved using
-c astGetTables.
-f AST_GETTABLES.
-* - The tables in the supplied KeyMap are added to any tables already
-* in the FitsChan.
-c - The astPutTable
-f - The AST_PUTTABLE
-* method provides a simpler means of adding a single table to a FitsChan.
-*--
-*/
-
-/* Local Variables: */
- AstObject *obj;
- const char *key;
- int ientry;
- int nentry;
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Loop through all entries in the supplied KeyMap. */
- nentry = astMapSize( tables );
- for( ientry = 0; ientry < nentry; ientry++ ) {
- key = astMapKey( tables, ientry );
-
-/* Ignore entries that do not contain AST Object pointers, or are not
- scalar. */
- if( astMapType( tables, key ) == AST__OBJECTTYPE &&
- astMapLength( tables, key ) == 1 ) {
-
-/* Get the pointer, amd ignore it if it is not a FitsTable. */
- astMapGet0A( tables, key, &obj );
- if( astIsAFitsTable( obj ) ) {
-
-/* Store it in the FitsChan. */
- astPutTable( this, (AstFitsTable *) obj, key );
- }
-
-/* Annul the Object pointer. */
- obj = astAnnul( obj );
- }
- }
-}
-
-static AstObject *Read( AstChannel *this_channel, int *status ) {
-/*
-* Name:
-* Read
-
-* Purpose:
-* Read an Object from a Channel.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstObject *Read( AstChannel *this_channel, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the astRead method
-* inherited from the Channel class).
-
-* Description:
-* This function reads an Object from a FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the new Object. This will always be a FrameSet.
-
-* Notes:
-* - The pixel Frame is given a title of "Pixel Coordinates", and
-* each axis in the pixel Frame is given a label of the form "Pixel
-* axis <n>", where <n> is the axis index (starting at one).
-* - The FITS CTYPE keyword values are used to set the labels for any
-* non-celestial axes in the physical coordinate Frames, and the FITS
-* CUNIT keywords are used to set the corresponding units strings.
-* - On exit, the pixel Frame is the base Frame, and the physical
-* Frame derived from the primary axis descriptions is the current Frame.
-* - Extra Frames are added to hold any secondary axis descriptions. All
-* axes within such a Frame refer to the same coordinate version ('A',
-* 'B', etc).
-* - For foreign encodings, the first card in the FitsChan must be
-* the current card on entry (otherwise a NULL pointer is returned),
-* and the FitsChan is left at end-of-file on exit.
-* - For the Native encoding, reading commences from the current card
-* on entry (which need not be the first in the FitsChan), and the
-* current Card on exit is the first card following the last one read
-* (or end-of-file).
-*/
-
-/* Local Variables: */
- AstObject *new; /* Pointer to returned Object */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- FitsStore *store; /* Intermediate storage for WCS information */
- const char *method; /* Pointer to string holding calling method */
- const char *class; /* Pointer to string holding object class */
- int encoding; /* The encoding scheme */
- int remove; /* Remove used cards? */
-
-/* Initialise. */
- new = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return new;
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Store the calling method, and object class. */
- method = "astRead";
- class = astGetClass( this );
-
-/* Get the encoding scheme used by the FitsChan. */
- encoding = astGetEncoding( this );
-
-/* If we are reading from a FitsChan in which AST objects are encoded using
- native AST-specific keywords, use the Read method inherited from the
- Channel class. */
- if( encoding == NATIVE_ENCODING ){
- new = (*parent_read)( this_channel, status );
-
-/* Indicate that used cards should be removed from the FitsChan. */
- remove = 1;
-
-/* If we are reading from a FitsChan in which AST objects are encoded using
- any of the other supported encodings, the header may only contain a
- single FrameSet. */
- } else {
- remove = 0;
-
-/* Only proceed if the FitsChan is at start-of-file. */
- if( !astTestCard( this ) && astOK ){
-
-/* Extract the required information from the FITS header into a standard
- intermediary structure called a FitsStore. */
- store = FitsToStore( this, encoding, method, class, status );
-
-/* Now create a FrameSet from this FitsStore. */
- new = FsetFromStore( this, store, method, class, status );
-
-/* Release the resources used by the FitsStore. */
- store = FreeStore( store, status );
-
-/* Indicate that used cards should be retained in the FitsChan. */
- remove = 0;
-
-/* If no object is being returned, rewind the fitschan in order to
- re-instate the original current Card. */
- if( !new ) {
- astClearCard( this );
-
-/* Otherwise, ensure the current card is at "end-of-file". */
- } else {
- astSetCard( this, INT_MAX );
- }
- }
- }
-
-/* If an error occurred, clean up by deleting the new Object and
- return a NULL pointer. */
- if ( !astOK ) new = astDelete( new );
-
-/* If no object is being returned, clear the "provisionally used" flags
- associated with cards which were read. We do not do this if the user
- wants to clean WCS cards from the FitsChan even if an error occurs. */
- if( !new && !astGetClean( this ) ) {
- FixUsed( this, 0, 0, 0, method, class, status );
-
-/* Otherwise, indicate that all the "provisionally used" cards have been
- "definitely used". If native encoding was used, these cards are
- totally removed from the FitsChan. */
- } else {
- FixUsed( this, 0, 1, remove, method, class, status );
- }
-
-/* Return the pointer to the new Object. */
- return new;
-}
-
-static double *ReadCrval( AstFitsChan *this, AstFrame *wcsfrm, char s,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* ReadCrval
-
-* Purpose:
-* Obtain the reference point from the supplied FitsChan in the
-* supplied WCS Frame.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* double *ReadCrval( AstFitsChan *this, AstFrame *wcsfrm, char s,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The original reference point in the "s" coordinate description is read
-* from the CRVAL keywords in the supplied FitsChan, and the original
-* FrameSet is re-read from the FitsChan. If possible, the reference
-* position is then converted from the "s" coordinate description to the
-* supplied WCS Frame, and a pointer to an array holding the axis
-* values for the transformed reference point is returned.
-
-* Parameters:
-* this
-* The FitsChan.
-* wcsfrm
-* The WCS Frame in the FitsChan being written to.
-* s
-* The co-ordinate version character. A space means the primary
-* axis descriptions. Otherwise the supplied character should be
-* an upper case alphabetical character ('A' to 'Z').
-* 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 pointer to a dynamically allocated array holding the reference
-* point in the supplied WCS Frame. NULL is returned if is is not
-* possible to determine the reference point for any reason (for
-* instance, if the FitsChan does not contain values for the CRVAL
-* keywords).
-*/
-
-/* Local Variables: */
- AstFitsChan *fc; /* A copy of the supplied FitsChan */
- AstFrame *tfrm; /* Temporary Frame pointer */
- AstFrameSet *fs; /* The FITS FrameSet */
- AstFrameSet *tfs; /* FrameSet connecting FITS and supplied WCS Frame */
- const char *id; /* Pointer to Object "Id" string */
- char buf[ 11 ]; /* FITS keyword template buffer */
- double *crval; /* CRVAL keyword values in supplied FitsChan */
- double *ret; /* Returned array */
- int hii; /* Highest found FITS axis index */
- int iax; /* Axis index (zero based) */
- int ifr; /* Frames index */
- int loi; /* Lowest found FITS axis index */
- int nax; /* Axis count */
- int nfr; /* No. of Frames in FITS FrameSet */
- int ok; /* Were CRVAL values found? */
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* We want to re-create the original FrameSet represented by the original
- contents of the supplied FitsChan. Some of the contents of the
- FitsChan will already have been marked as "having been read" and so
- will be ignored if we attempt to read a FrameSet directly from the
- supplied FitsChan. Therefore we take a deep copy of the supplied
- FitsChan and clear all the "previusly read" flags in the copy. */
- fc = astCopy( this );
- astClearEncoding( fc );
- FixUsed( fc, 1, 0, 0, method, class, status );
-
-/* Copy the CRVAL values for the "s" axis descriptions into a dynamically
- allocated array ("crval"). */
- if( s == ' ' ) {
- strcpy( buf, "CRVAL%d" );
- } else {
- sprintf( buf, "CRVAL%%d%c", s );
- }
- if( astKeyFields( fc, buf, 1, &hii, &loi ) > 0 ) {
- crval = astMalloc( sizeof( double )*(size_t) hii );
- ok = 1;
- for( iax = 0; iax < hii; iax++ ){
- ok = ok && GetValue( fc, FormatKey( "CRVAL", iax + 1, -1, s, status ),
- AST__FLOAT, (void *) (crval + iax), 0, 0, method,
- class, status );
- }
- } else {
- crval = NULL;
- ok = 0;
- }
-
-/* If the CRVAL values were obtained succesfully, attempt to read a FrameSet
- from the FitsChan copy. Do it in a new error report context so that we
- can annull any error when the FrameSet is read. */
- if( ok ) {
- int oldreporting = astReporting( 0 );
- astClearCard( fc );
- fs = astRead( fc );
- if( fs ) {
-
-/* We want to find a conversion from the Frame in this FrameSet which
- represents the FITS-WCS "s" coordinate descriptions and the supplied WCS
- Frame. So first find the Frame which has its Ident attribute set to
- "s" and make it the current Frame. */
- nfr = astGetNframe( fs );
- for( ifr = 1; ifr <= nfr; ifr++ ) {
- astSetCurrent( fs, ifr );
- tfrm = astGetFrame( fs, ifr );
- id = astTestIdent( tfrm ) ? astGetIdent( tfrm ) : NULL;
- tfrm = astAnnul( tfrm );
- if( id && strlen( id ) == 1 && id[ 0 ] == s ) break;
- }
-
-/* Check a Frame was found, and that we have CRVAL values for all axes in
- the Frame. */
- if( ifr <= nfr && astGetNaxes( fs ) == hii ) {
-
-/* Attempt to find a conversion route from the Frame found above to the
- supplied WCS Frame. */
- tfs = astConvert( fs, wcsfrm, astGetDomain( wcsfrm ) );
- if( tfs ) {
-
-/* Allocate memory to hold the returned reference point. */
- nax = astGetNaxes( wcsfrm );
- ret = astMalloc( sizeof( double )*(size_t) nax );
-
-/* Transform the original reference position from the "s" Frame to the
- supplied WCS Frame using the Mapping returned by astConvert. */
- astTranN( tfs, 1, hii, 1, crval, 1, nax, 1, ret );
-
-/* Free resources. */
- tfs = astAnnul( tfs );
- }
- }
-
-/* Free resources. */
- fs = astAnnul( fs );
-
-/* Annul any error that occurred reading the FitsChan. */
- } else if( !astOK ) {
- astClearStatus;
- }
-
-/* Re-instate error reporting. */
- astReporting( oldreporting );
- }
-
-/* Free resources. */
- if( crval ) crval = astFree( crval );
- fc = astAnnul( fc );
-
-/* If an error occurred, free the returned array. */
- if( !astOK ) ret = astFree( ret );
-
-/* Return the result. */
- return ret;
-}
-
-static void ReadFits( AstFitsChan *this, int *status ){
-
-/*
-*++
-* Name:
-c astReadFits
-f AST_READFITS
-
-* Purpose:
-* Read cards into a FitsChan from the source function.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-c void astReadFits( AstFitsChan *this )
-f CALL AST_READFITS( THIS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* reads cards from the source function that was specified when the
-* FitsChan was created, and stores them in the FitsChan. This
-* normally happens once-only, when the FitsChan is accessed for the
-* first time.
-c This function
-f This routine
-* provides a means of forcing a re-read of the external source, and
-* may be useful if (say) new cards have been deposited into the
-* external source. Any newcards read from the source are appended to
-* the end of the current contents of the FitsChan.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - This function returns without action if no source function was
-* specified when the FitsChan was created.
-* - The SourceFile attribute is ignored by this
-c function.
-f routine.
-* New cards are read from the source file whenever a new value is
-* assigned to the SourceFile attribute.
-
-*--
-*/
-
-/* Check the inherited status */
- if( !astOK ) return;
-
-/* If no source function is available, re-instate any saved source
- function pointer. */
- if( !this->source ) {
- this->source = this->saved_source;
- this->saved_source = NULL;
- }
-
-/* Call the source function. */
- ReadFromSource( this, status );
-}
-
-static void ReadFromSource( AstFitsChan *this, int *status ){
-
-/*
-* Name:
-* ReadFromSource
-
-* Purpose:
-* Fill the FitsChan by reading cards from the source function.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void ReadFromSource( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The source function specified when the FitsChan was created is
-* called repeatedly until it returns a NULL pointer. The string
-* returned by each such call is assumed to be a FITS header card,
-* and is stored in the FitsChan using astPutFits.
-*
-* If no source function was provided, the FitsChan is left as supplied.
-* This is different to a standard Channel, which tries to read data
-* from standard input if no source function is provided.
-*
-* This function should be called at the start of most public or protected
-* FitsChan functions, and most private functions that are used to override
-* methods inherited form the Channel class. Previously, this function
-* was called only once, from the FitsChan initialiser (astInitFitschan).
-* However, calling it from astInitFitsChan means that application code
-* cannot use the astPutChannelData function with a FitsChan, since the
-* source function would already have been called by the time the
-* FitsChan constructor returned (and thus before astPutChannelData
-* could have been called). In order to ensure that the source
-* function is called only once, this function now nullifies the source
-* function pointer after its first use.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - The new cards are appended to the end of the FitsChan.
-* - The first of the new cards is made the current card on exit. If no
-* source function is supplied, the current card is left unchanged.
-*/
-
-/* Local Variables: */
- const char *(* source)( void ); /* Pointer to source function */
- const char *card; /* Pointer to externally-read header card */
- int icard; /* Current card index on entry */
-
-/* Check the global status. */
- if( !astOK || !this ) return;
-
-/* Only proceed if source function and wrapper were supplied when the FitsChan
- was created and are still available. */
- if( this->source && this->source_wrap ){
-
-/* Save the source function pointer and then nullify the pointer in the
- FitsChan structure. This avoids infinte loops. */
- source = this->source;
- this->source = NULL;
-
-/* Save the source fubnction pointer in the FitsChan so that it can be
- re-instated if required (e.g. by astReadFits). */
- this->saved_source = source;
-
-/* Ensure the FitsChan is at end-of-file. This will result in the
- new cards being appended to the end of the FitsChan. */
- astSetCard( this, INT_MAX );
-
-/* Store the current card index. */
- icard = astGetCard( this );
-
-/* Obtain the first header card from the source function. This is an
- externally supplied function which may not be thread-safe, so lock a
- mutex first. Also store the channel data pointer in a global variable
- so that it can be accessed in the source function using macro
- astChannelData. */
- astStoreChannelData( this );
- LOCK_MUTEX2;
- card = ( *this->source_wrap )( source, status );
- UNLOCK_MUTEX2;
-
-/* Loop until a NULL pointer is returned by the source function, or an
- error occurs. */
- while( card && astOK ){
-
-/* Store the card in the FitsChan. */
- astPutFits( this, card, 0 );
-
-/* Free the memory holding the header card. */
- card = (char *) astFree( (void *) card );
-
-/* Obtain the next header card. Also store the channel data pointer in a
- global variable so that it can be accessed in the source function using
- macro astChannelData. */
- astStoreChannelData( this );
- LOCK_MUTEX2;
- card = ( *this->source_wrap )( source, status );
- UNLOCK_MUTEX2;
- }
-
-/* Set the current card index so that the first of the new cards will be the
- next card to be read from the FitsChan. */
- astSetCard( this, icard );
- }
-}
-
-static void RemoveTables( AstFitsChan *this, const char *key, int *status ){
-
-/*
-*++
-* Name:
-c astRemoveTables
-f AST_REMOVETABLES
-
-* Purpose:
-* Remove one or more tables from a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c void astRemoveTables( AstFitsChan *this, const char *key )
-f CALL AST_REMOVETABLES( THIS, KEY, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* removes the named tables from the FitsChan, it they exist (no error
-* is reported if any the tables do not exist).
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c key
-f KEY = CHARACTER * ( * ) (Given)
-* The key indicating which tables to exist. A single key or a
-* comma-separated list of keys can be supplied. If a blank string
-* is supplied, all tables are removed.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-*--
-*/
-
-/* Local variables: */
- char **words;
- int itable;
- int ntable;
-
-/* Return if the global error status has been set, or the FitsChan
- contains no tables KeyMap. */
- if( !astOK || !this->tables ) return;
-
-/* If the string is blank, remove all tables. */
- if( astChrLen( key ) == 0 ) {
- ntable = astMapSize( this->tables );
- for( itable = 0; itable < ntable; itable++ ) {
- astMapRemove( this->tables, astMapKey( this->tables, itable ) );
- }
-
-/* Otherwise, split the supplied comma-separated string up into individual
- items. */
- } else {
- words = astChrSplitC( key, ',', &ntable );
-
-/* Attempt to remove each one, and then free the string. */
- if( astOK ) {
- for( itable = 0; itable < ntable; itable++ ) {
- astMapRemove( this->tables, words[ itable ] );
- words[ itable ] = astFree( words[ itable ] );
- }
- }
-
-/* Free the list. */
- words = astFree( words );
- }
-}
-
-static void RetainFits( AstFitsChan *this, int *status ){
-
-/*
-*++
-* Name:
-c astRetainFits
-f AST_RETAINFITS
-
-* Purpose:
-* Indicate that the current card in a FitsChan should be retained.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-c void astRetainFits( AstFitsChan *this )
-f CALL AST_RETAINFITS( THIS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* stores a flag with the current card in the FitsChan indicating that
-* the card should not be removed from the FitsChan when an Object is
-* read from the FitsChan using
-c astRead.
-f AST_READ.
-*
-* Cards that have not been flagged in this way are removed when a
-* read operation completes succesfully, but only if the card was used
-* in the process of creating the returned AST Object. Any cards that
-* are irrelevant to the creation of the AST Object are retained whether
-* or not they are flagged.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - This function returns without action if the FitsChan is
-* initially positioned at the "end-of-file" (i.e. if the Card
-* attribute exceeds the number of cards in the FitsChan).
-* - The current card is not changed by this function.
-*--
-*/
-
-/* Local variables: */
- int flags;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Return if the global error status has been set, or the current card
- is not defined. */
- if( !astOK || !this->card ) return;
-
-/* Set the PROTECTED flag in the current card. */
- flags = ( (FitsCard *) this->card )->flags;
- ( (FitsCard *) this->card )->flags = flags | PROTECTED;
-}
-
-static void RoundFString( char *text, int width, int *status ){
-/*
-* Name:
-* RoundString
-
-* Purpose:
-* Modify a formatted floating point number to round out long
-* sequences of zeros or nines.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void RoundFString( char *text, int width )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The supplied string is assumed to be a valid decimal representation of
-* a floating point number. It is searched for sub-strings consisting
-* of NSEQ or more adjacent zeros, or NSEQ or more adjacent nines. If found
-* the string is modified to represent the result of rounding the
-* number to remove the sequence of zeros or nines.
-
-* Parameters:
-* text
-* The formatted number. Modified on exit to round out long
-* sequences of zeros or nines. The returned string is right justified.
-* width
-* The minimum field width to use. The value is right justified in
-* this field width. Ignored if zero.
-*/
-
-/* Local Constants: */
-#define NSEQ 4 /* No. of adjacent 0's or 9's to produce rounding */
-
-/* Local Variables: */
- char *a;
- char *c;
- char *dot;
- char *exp;
- char *last;
- char *start;
- char *end;
- int i;
- int neg;
- int nnine;
- int nonzero;
- int nzero;
- int replace;
- int started;
- int len;
- int bu;
- int nls;
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* Save the original length of the text. */
- len = strlen( text );
-
-/* Locate the start of any exponent string. */
- exp = strpbrk( text, "dDeE" );
-
-/* First check for long strings of adjacent zeros.
- =============================================== */
-
-/* Indicate that we have not yet found a decimal point in the string. */
- dot = NULL;
-
-/* The "started" flag controls whether *leading* zeros should be removed
- if there are more than NSEQ of them. They are only removed if there is an
- exponent. */
- started = ( exp != NULL );
-
-/* We are not currently replacing digits with zeros. */
- replace = 0;
-
-/* We have not yet found any adjacent zeros. */
- nzero = 0;
-
-/* We have no evidence yet that the number is non-zero. */
- nonzero = 0;
-
-/* Loop round the supplied text string. */
- c = text;
- while( *c && c != exp ){
-
-/* If this is a zero, increment the number of adjacent zeros found, so
- long as we have previously found a non-zero digit (or there is an
- exponent). If this is the NSEQ'th adjacent zero, indicate that
- subsequent digits should be replaced by zeros. */
- if( *c == '0' ){
- if( started && ++nzero >= NSEQ ) replace = 1;
-
-/* Note if the number contains a decimal point. */
- } else if( *c == '.' ){
- dot = c;
-
-/* If this character is a non-zero digit, indicate that we have found a
- non-zero digit. If we have previously found a long string of adjacent
- zeros, replace the digit by '0'. Otherwise, reset the count of
- adjacent zeros, and indicate the final number is non-zero. */
- } else if( *c != ' ' && *c != '+' && *c != '-' ){
- started = 1;
- if( replace ) {
- *c = '0';
- } else {
- nzero = 0;
- nonzero = 1;
- }
- }
-
-/* Move on to the next character. */
- c++;
- }
-
-/* If the final number is zero, just return the most simple decimal zero
- value. */
- if( !nonzero ) {
- strcpy( text, "0.0" );
-
-/* Otherwise, we remove any trailing zeros which occur to the right of a
- decimal point. */
- } else if( dot ) {
-
-/* Find the last non-zero digit. */
- while( c-- > text && *c == '0' );
-
-/* If any trailing zeros were found... */
- if( c > text ) {
-
-/* Retain one trailing zero after a decimal point. */
- if( *c == '.' ) c++;
-
-/* We put a terminator following the last non-zero character. The
- terminator is the exponent, if there was one, or a null character.
- Remember to update the pointer to the start of the exponent. */
- c++;
- if( exp ) {
- a = exp;
- exp = c;
- while( ( *(c++) = *(a++) ) );
- } else {
- *c = 0;
- }
- }
- }
-
-/* Next check for long strings of adjacent nines.
- ============================================= */
-
-/* We have not yet found any adjacent nines. */
- nnine = 0;
-
-/* We have not yet found a non-nine digit. */
- a = NULL;
-
-/* We have not yet found a non-blank character */
- start = NULL;
- last = NULL;
-
-/* Number is assumed positive. */
- neg = 0;
-
-/* Indicate that we have not yet found a decimal point in the string. */
- dot = NULL;
-
-/* Loop round the supplied text string. */
- c = text;
- while( *c && c != exp ){
-
-/* Note the address of the first non-blank character. */
- if( !start && *c != ' ' ) start = c;
-
-/* If this is a nine, increment the number of adjacent nines found. */
- if( *c == '9' ){
- ++nnine;
-
-/* Note if the number contains a decimal point. */
- } else if( *c == '.' ){
- dot = c;
-
-/* Note if the number is negative. */
- } else if( *c == '-' ){
- neg = 1;
-
-/* If this character is a non-nine digit, and we have not had a long
- sequence of 9's, reset the count of adjacent nines, and update a pointer
- to "the last non-nine digit prior to a long string of nines". */
- } else if( *c != ' ' && *c != '+' ){
- if( nnine < NSEQ ) {
- nnine = 0;
- a = c;
- }
- }
-
-/* Note the address of the last non-blank character. */
- if( *c != ' ' ) last = c;
-
-/* Move on to the next character. */
- c++;
- }
-
-/* If a long string of adjacent nines was found... */
- if( nnine >= NSEQ ) {
- c = NULL;
-
-/* If we found at least one non-nine digit. */
- if( a ) {
-
-/* "a" points to the last non-nine digit before the first of the group of 9's.
- Increment this digit by 1. Since we know the digit is not a nine, there
- is no danger of a carry. */
- *a = *a + 1;
-
-/* Fill with zeros up to the decimal point, or to the end if there is no
- decimal point. */
- c = a + 1;
- if( dot ) {
- while( c < dot ) *(c++) = '0';
- } else {
- while( *c ) *(c++) = '0';
- }
-
-/* Now make "c" point to the first character for the terminator. This is
- usually the character following the last non-nine digit. However, if
- the last non-nine digit appears immediately before a decimal point, then
- we append ".0" to the string before appending the terminator. */
- if( *c == '.' ) {
- *(++c) = '0';
- c++;
- }
-
-/* If all digits were nines, the rounded number will occupy one more
- character than the supplied number. We can only do the rounding if there
- is a spare character (i.e.a space) in the supplied string. */
- } else if( last - start + 1 < len ) {
-
-/* Put the modified text at the left of the available space. */
- c = text;
-
-/* Start with a minus sing if needed, followed by the leading "1" (caused
- by the overflow from the long string of 9's). */
- if( neg ) *(c++) = '-';
- *(c++) = '1';
-
-/* Now find the number of zeros to place after the leading "1". This is
- the number of characters in front of the terminator marking the end of
- the integer part of the number. */
- if( dot ) {
- nzero = dot - start;
- } else if( exp ) {
- nzero = exp - start;
- } else {
- nzero = last - start;
- }
-
-/* If the number is negative, the above count will include the leading
- minus sign, which is not a digit. So reduce the count by one. */
- if( neg ) nzero--;
-
-/* Now put in the correct number of zeros. */
- for( i = 0; i < nzero; i++ ) *(c++) = '0';
-
-/* If the original string containsed a decimal point, make sure the
- returned string also contains one. */
- if( dot ) {
- *(c++) = '.';
- if( *c ) *(c++) = '0';
- }
- }
-
-/* We put a terminator following the last non-zero character. The
- terminator is the exponent, if there was one, or a null character. */
- if( c ) {
- if( exp ) {
- while( ( *(c++) = *(exp++) ) );
- } else {
- *c = 0;
- }
- }
- }
-
-/* Right justify the returned string in the original field width. */
- end = text + len;
- c = text + strlen( text );
- if( c != end ) {
- while( c >= text ) *(end--) = *(c--);
- while( end >= text ) *(end--) = ' ';
- }
-
-/* If a minimum field width was given, shunt the text to the left in
- order to reduce the used field width to the specified value. This
- requires there to be some leading spaces (because we do not want to
- loose any non-blank characters from the left hand end of the string).
- If there are insufficient leading spaces to allow the field width to
- be reduced to the specified value, then reduce the field width as far
- as possible. First find the number of spaces we would like to remove
- from the front of the string (in order to reduce the used width to the
- specified value). */
- bu = len - width;
-
-/* If we need to remove any leading spaces... */
- if( width > 0 && bu > 0 ) {
-
-/* Find the number of leading spaces which are available to be removed. */
- c = text - 1;
- while( *(++c) == ' ' );
- nls = c - text;
-
-/* If there are insufficient leading spaces, just use however many there
- are. */
- if( bu > nls ) bu = nls;
-
-/* Shift the string. */
- c = text;
- a = c + bu;
- while( ( *(c++) = *(a++) ) );
- }
-
-/* Undefine local constants. */
-#undef NSEQ
-}
-
-static int SAOTrans( AstFitsChan *this, AstFitsChan *out, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* SAOTrans
-
-* Purpose:
-* Translate an SAO encoded header into a TPN encoded header.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int SAOTrans( AstFitsChan *this, AstFitsChan *out, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Search "this" for keywords that give a description of a distorted
-* TAN projection using the SAO representation and, if found, write
-* keywords to "out" that describe an equivalent projection using TPN
-* representation. The definition of the SAO polynomial is taken from
-* the platepos.c file included in Doug Mink's WCSTools.
-
-* Parameters:
-* this
-* Pointer to the FitsChan to read.
-* out
-* Pointer to a FitsCHan in which to store translated keywords.
-* 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:
-* Non-zero if "this" contained an SAO encoded header. Zero otherwise.
-
-*/
-
-#define NC 13
-
-/* Local Variables: */
- char keyname[10];
- double co[ 2 ][ NC ];
- double pv;
- int i;
- int is_sao;
- int m;
- int ok;
- int result;
-
-/* Initialise */
- result = 0;
-
-/* Check the inherited status. */
- if( !astOK ) return result;
-
-/* Check there are exactly two CTYPE keywords in the header. */
- if( 2 == astKeyFields( this, "CTYPE%d", 0, NULL, NULL ) ){
-
-/* Initialise all cooefficients. */
- memset( co, 0, sizeof( co ) );
-
-/* Get the required SAO keywords. */
- is_sao = 1;
- ok = 1;
- for( i = 0; i < 2 && ok && is_sao; i++ ) {
-
- ok = 0;
- for( m = 0; m < NC; m++ ) {
-
-/* Get the value of the next "COi_j" keyword. If any of the first 3 values
- are missing on either axis, we assume this is not an SAO header. */
- sprintf( keyname, "CO%d_%d", i + 1, m + 1 );
- if( !GetValue( this, keyname, AST__FLOAT, &co[ i ][ m ], 0, 1, method,
- class, status ) ) {
- if( m < 3 ) is_sao = 0;
- break;
- }
-
-/* Check that we have at least one non-zero coefficient (excluding the
- first constant term ). */
- if( co[ i ][ m ] != 0.0 && m > 0 ) ok = 1;
- }
- }
-
-/* If this is an SAO header.. */
- if( is_sao ) {
-
-/* Issue a warning if all coefficients for this axis are zero. */
- if( !ok ) {
- Warn( this, "badpv", "This FITS header describes an SAO encoded "
- "distorted TAN projection, but all the distortion "
- "coefficients for at least one axis are zero.", method, class,
- status );
-
-/* Otherwise, calculate and store the equivalent PV projection parameters. */
- } else {
- pv = co[ 0 ][ 0 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_0", &pv,
- AST__FLOAT, NULL, status );
-
- pv = co[ 0 ][ 1 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_1", &pv,
- AST__FLOAT, NULL, status );
-
- pv = co[ 0 ][ 2 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_2", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 0 ][ 3 ] != AST__BAD ) pv += co[ 0 ][ 3 ];
- if( co[ 0 ][ 10 ] != AST__BAD ) pv += co[ 0 ][ 10 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_4", &pv,
- AST__FLOAT, NULL, status );
-
- pv = co[ 0 ][ 5 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_5", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 0 ][ 4 ] != AST__BAD ) pv += co[ 0 ][ 4 ];
- if( co[ 0 ][ 10 ] != AST__BAD ) pv += co[ 0 ][ 10 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_6", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 0 ][ 6 ] != AST__BAD ) pv += co[ 0 ][ 6 ];
- if( co[ 0 ][ 11 ] != AST__BAD ) pv += co[ 0 ][ 11 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_7", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 0 ][ 8 ] != AST__BAD ) pv += co[ 0 ][ 8 ];
- if( co[ 0 ][ 12 ] != AST__BAD ) pv += co[ 0 ][ 12 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_8", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 0 ][ 9 ] != AST__BAD ) pv += co[ 0 ][ 9 ];
- if( co[ 0 ][ 11 ] != AST__BAD ) pv += co[ 0 ][ 11 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_9", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 0 ][ 7 ] != AST__BAD ) pv += co[ 0 ][ 7 ];
- if( co[ 0 ][ 12 ] != AST__BAD ) pv += co[ 0 ][ 12 ];
- if( pv != AST__BAD ) SetValue( out, "PV1_10", &pv,
- AST__FLOAT, NULL, status );
-
- pv = co[ 1 ][ 0 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_0", &pv,
- AST__FLOAT, NULL, status );
-
- pv = co[ 1 ][ 2 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_1", &pv,
- AST__FLOAT, NULL, status );
-
- pv = co[ 1 ][ 1 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_2", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 1 ][ 4 ] != AST__BAD ) pv += co[ 1 ][ 4 ];
- if( co[ 1 ][ 10 ] != AST__BAD ) pv += co[ 1 ][ 10 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_4", &pv,
- AST__FLOAT, NULL, status );
-
- pv = co[ 1 ][ 5 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_5", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 1 ][ 3 ] != AST__BAD ) pv += co[ 1 ][ 3 ];
- if( co[ 1 ][ 10 ] != AST__BAD ) pv += co[ 1 ][ 10 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_6", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 1 ][ 7 ] != AST__BAD ) pv += co[ 1 ][ 7 ];
- if( co[ 1 ][ 12 ] != AST__BAD ) pv += co[ 1 ][ 12 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_7", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 1 ][ 9 ] != AST__BAD ) pv += co[ 1 ][ 9 ];
- if( co[ 1 ][ 11 ] != AST__BAD ) pv += co[ 1 ][ 11 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_8", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 1 ][ 8 ] != AST__BAD ) pv += co[ 1 ][ 8 ];
- if( co[ 1 ][ 12 ] != AST__BAD ) pv += co[ 1 ][ 12 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_9", &pv,
- AST__FLOAT, NULL, status );
-
- pv = 0.0;
- if( co[ 1 ][ 6 ] != AST__BAD ) pv += co[ 1 ][ 6 ];
- if( co[ 1 ][ 11 ] != AST__BAD ) pv += co[ 1 ][ 11 ];
- if( pv != AST__BAD ) SetValue( out, "PV2_10", &pv,
- AST__FLOAT, NULL, status );
-
-/* From an example header provided by Bill Joye, it seems that the SAO
- polynomial includes the rotation and scaling effects of the CD matrix.
- Therefore we mark as read all CDi_j, CDELT and CROTA values. Without
- this, the rotation and scaling would be applied twice. First, mark the
- original values as having been used, no matter which FitsChan they are
- in. */
- GetValue( this, "CD1_1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "CD1_2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "CD2_1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "CD2_2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "PC1_1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "PC1_2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "PC2_1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "PC2_2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "CDELT1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "CDELT2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "CROTA1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( this, "CROTA2", AST__FLOAT, &pv, 0, 1, method, class, status );
-
- GetValue( out, "CD1_1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "CD1_2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "CD2_1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "CD2_2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "PC1_1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "PC1_2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "PC2_1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "PC2_2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "CDELT1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "CDELT2", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "CROTA1", AST__FLOAT, &pv, 0, 1, method, class, status );
- GetValue( out, "CROTA2", AST__FLOAT, &pv, 0, 1, method, class, status );
-
-/* Now store new default values in the returned FitsChan. */
- pv = 1.0;
- SetValue( out, "PC1_1", &pv, AST__FLOAT, NULL,
- status );
- SetValue( out, "PC2_2", &pv, AST__FLOAT, NULL,
- status );
- SetValue( out, "CDELT1", &pv, AST__FLOAT, NULL,
- status );
- SetValue( out, "CDELT2", &pv, AST__FLOAT, NULL,
- status );
-
- pv = 0.0;
- SetValue( out, "PC1_2", &pv, AST__FLOAT, NULL,
- status );
- SetValue( out, "PC2_1", &pv, AST__FLOAT, NULL,
- status );
-
-/* Indicate we have converted an SAO header. */
- result = 1;
- }
- }
- }
-
-/* Return a flag indicating if an SAO header was found. */
- return result;
-}
-#undef NC
-
-static int SearchCard( AstFitsChan *this, const char *name,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* SearchCard
-
-* Purpose:
-* Search the whole FitsChan for a card refering to given keyword.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int SearchCard( AstFitsChan *this, const char *name,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Searches the whole FitsChan for a card refering to the supplied keyword,
-* and makes it the current card. The card following the current card is
-* checked first. If this is not the required card, then a search is
-* performed starting with the first keyword in the FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a string holding the keyword name.
-* method
-* Pointer to string holding name of calling method.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A value of 1 is returned if a card was found refering to the given
-* keyword. Otherwise zero is returned.
-
-* Notes:
-* - If a NULL pointer is supplied for "name" then the current card
-* is left unchanged.
-* - The current card is set to NULL (end-of-file) if no card can be
-* found for the supplied keyword.
-*/
-
-/* Local Variables: */
- int ret; /* Was a card found? */
-
-/* Check the global status, and supplied keyword name. */
- if( !astOK || !name ) return 0;
-
-/* Indicate that no card has been found yet. */
- ret = 0;
-
-/* The required card is very often the next card in the FitsChan, so check the
- next card, and only search the entire FitsChan if the check fails. */
- MoveCard( this, 1, method, class, status );
- if( !astFitsEof( this ) &&
- !Ustrncmp( CardName( this, status ), name, FITSNAMLEN, status ) ){
- ret = 1;
-
-/* If the next card is not the required card, rewind the FitsChan back to
- the first card. */
- } else {
- astClearCard( this );
-
-/* Attempt to find the supplied keyword, searching from the first card. */
- ret = FindKeyCard( this, name, method, class, status );
- }
-
-/* Return. */
- return ret;
-}
-
-static void SetAlgCode( char *buf, const char *algcode, int *status ){
-/*
-* Name:
-* SetAlgCode
-
-* Purpose:
-* Create a non-linear CTYPE string from a system code and an algorithm
-* code.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void SetAlgCode( char *buf, const char *algcode, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* FITS-WCS paper 1 says that non-linear axes must have a CTYPE of the
-* form "4-3" (e.g. "VRAD-TAB"). This function handles the truncation
-* of long system codes, or the padding of short system codes.
-
-* Parameters:
-* buf
-* A buffer in which is stored the system code. Modified on exit to
-* hold the combined CTYPE value. It should have a length long
-* enough to hold the system code and the algorithm code.
-* algcode
-* Pointer to a string holding the algorithm code (with a leading
-* "-", e.g. "-TAB").
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- int nc;
-
-/* Check inherited status */
- if( !astOK ) return;
-
-/* Pad the supplied string to at least 4 characters using "-" characters. */
- nc = strlen( buf );
- while( nc < 4 ) buf[ nc++ ] = '-';
-
-/* Insert the null-terminated code at position 4. */
- strcpy( buf + 4, algcode );
-}
-
-static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
-/*
-* Name:
-* SetAttrib
-
-* Purpose:
-* Set an attribute value for a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void SetAttrib( AstObject *this, const char *setting )
-
-* Class Membership:
-* FitsChan member function (over-rides the astSetAttrib protected
-* method inherited from the Channel class).
-
-* Description:
-* This function assigns an attribute value for a FitsChan, 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 FitsChan.
-* setting
-* Pointer to a null-terminated string specifying the new attribute
-* value.
-*/
-
-/* Local Variables: */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- const char *class; /* Object class */
- int ival; /* Integer attribute value */
- int len; /* Length of setting string */
- int nc; /* Number of characters read by astSscanf */
- int offset; /* Offset of attribute string */
- int warn; /* Offset of Warnings string */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_object;
-
-/* Obtain the length of the setting string. */
- len = (int) strlen( setting );
-
-/* Obtain the object class. */
- class = astGetClass( this );
-
-/* Card. */
-/* ----- */
- if ( nc = 0,
- ( 1 == astSscanf( setting, "card= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetCard( this, ival );
-
-/* Encoding. */
-/* --------- */
- } else if( nc = 0,
- ( 0 == astSscanf( setting, "encoding=%n%*[^\n]%n", &ival, &nc ) )
- && ( nc >= len ) ) {
- nc = ChrLen( setting + ival, status );
- if( !Ustrncmp( setting + ival, NATIVE_STRING, nc, status ) ){
- astSetEncoding( this, NATIVE_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSPC_STRING, nc, status ) ){
- astSetEncoding( this, FITSPC_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSPC_STRING2, nc, status ) ){
- astSetEncoding( this, FITSPC_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSWCS_STRING, nc, status ) ){
- astSetEncoding( this, FITSWCS_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSWCS_STRING2, nc, status ) ){
- astSetEncoding( this, FITSWCS_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSIRAF_STRING, nc, status ) ){
- astSetEncoding( this, FITSIRAF_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSIRAF_STRING2, nc, status ) ){
- astSetEncoding( this, FITSIRAF_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSAIPS_STRING, nc, status ) ){
- astSetEncoding( this, FITSAIPS_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSAIPS_STRING2, nc, status ) ){
- astSetEncoding( this, FITSAIPS_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSAIPSPP_STRING, nc, status ) ){
- astSetEncoding( this, FITSAIPSPP_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSAIPSPP_STRING2, nc, status ) ){
- astSetEncoding( this, FITSAIPSPP_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSCLASS_STRING, nc, status ) ){
- astSetEncoding( this, FITSCLASS_ENCODING );
- } else if( !Ustrncmp( setting + ival, FITSCLASS_STRING2, nc, status ) ){
- astSetEncoding( this, FITSCLASS_ENCODING );
- } else if( !Ustrncmp( setting + ival, DSS_STRING, nc, status ) ){
- astSetEncoding( this, DSS_ENCODING );
- } else {
- astError( AST__BADAT, "astSet(%s): Unknown encoding system '%s' "
- "requested for a %s.", status, class, setting + ival, class );
- }
-
-/* FitsDigits. */
-/* ----------- */
- } else if ( nc = 0,
- ( 1 == astSscanf( setting, "fitsdigits= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetFitsDigits( this, ival );
-
-/* FitsAxisOrder. */
-/* -------------- */
- } else if ( nc = 0,
- ( 0 == astSscanf( setting, "fitsaxisorder=%n%*[^\n]%n",
- &offset, &nc ) )
- && ( nc >= len ) ) {
- astSetFitsAxisOrder( this, setting + offset );
-
-/* CDMatrix */
-/* -------- */
- } else if ( nc = 0,
- ( 1 == astSscanf( setting, "cdmatrix= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetCDMatrix( this, ival );
-
-/* DefB1950 */
-/* -------- */
- } else if ( nc = 0,
- ( 1 == astSscanf( setting, "defb1950= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetDefB1950( this, ival );
-
-/* TabOK */
-/* ----- */
- } else if ( nc = 0,
- ( 1 == astSscanf( setting, "tabok= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetTabOK( this, ival );
-
-/* CarLin */
-/* ------ */
- } else if ( nc = 0,
- ( 1 == astSscanf( setting, "carlin= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetCarLin( this, ival );
-
-/* PolyTan */
-/* ------- */
- } else if ( nc = 0,
- ( 1 == astSscanf( setting, "polytan= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetPolyTan( this, ival );
-
-/* Iwc */
-/* --- */
- } else if ( nc = 0,
- ( 1 == astSscanf( setting, "iwc= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetIwc( this, ival );
-
-/* Clean */
-/* ----- */
- } else if ( nc = 0,
- ( 1 == astSscanf( setting, "clean= %d %n", &ival, &nc ) )
- && ( nc >= len ) ) {
- astSetClean( this, ival );
-
-/* Warnings. */
-/* -------- */
- } else if ( nc = 0,
- ( 0 == astSscanf( setting, "warnings=%n%*[^\n]%n", &warn, &nc ) )
- && ( nc >= len ) ) {
- astSetWarnings( this, setting + warn );
-
-/* Define a macro to see if the setting string matches any of the
- read-only attributes of this class. */
-#define MATCH(attrib) \
- ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \
- ( nc >= len ) )
-
-/* If the attribute was not recognised, use this macro to report an error
- if a read-only attribute has been specified. */
- } else if ( MATCH( "ncard" ) ||
- MATCH( "cardtype" ) ||
- MATCH( "cardcomm" ) ||
- MATCH( "cardname" ) ||
- MATCH( "nkey" ) ||
- MATCH( "allwarnings" ) ){
- astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status,
- setting, astGetClass( this ) );
- astError( AST__NOWRT, "This is a read-only attribute." , status);
-
-/* If the attribute is still not recognised, pass it on to the parent
- method for further interpretation. */
- } else {
- (*parent_setattrib)( this_object, setting, status );
- }
-}
-
-static void SetCard( AstFitsChan *this, int icard, int *status ){
-
-/*
-*+
-* Name:
-* astSetCard
-
-* Purpose:
-* Set the value of the Card attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void astSetCard( AstFitsChan *this, int icard )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function sets the value of the Card attribute for the supplied
-* FitsChan. This is the index of the next card to be read from the
-* FitsChan. If a value of 1 or less is supplied, the first card in
-* the FitsChan will be read next. If a value greater than the number
-* of cards in the FitsChan is supplied, the FitsChan will be left in an
-* "end-of-file" condition, in which no further read operations can be
-* performed.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* icard
-* The index of the next card to read.
-
-* Notes:
-* - This function attempts to execute even if an error has occurred.
-*-
-*/
-
-/* Check the supplied object. */
- if ( !this ) return;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Rewind the FitsChan. */
- astClearCard( this );
-
-/* Move forward the requested number of cards. */
- MoveCard( this, icard - 1, "astSetCard", astGetClass( this ), status );
-
-/* Return. */
- return;
-}
-
-static void SetItem( double ****item, int i, int jm, char s, double val, int *status ){
-/*
-* Name:
-* SetItem
-
-* Purpose:
-* Store a value for a axis keyword value in a FitStore structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void SetItem( double ****item, int i, int jm, char s, double val, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The supplied keyword value is stored in the specified array,
-* at a position indicated by the axis and co-ordinate version.
-* The array is created or extended as necessary to make room for
-* the new value. Any old value is over-written.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->crval) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (i), and the pointer locates an
-* array of axis keyword values. These arrays of keyword values have
-* one element for every pixel axis (j) or projection parameter (m).
-* i
-* The zero based intermediate axis index in the range 0 to 98. Set
-* this to zero for keywords (e.g. CRPIX) which are not indexed by
-* intermediate axis number.
-* jm
-* The zero based pixel axis index (in the range 0 to 98) or parameter
-* index (in the range 0 to WCSLIB__MXPAR-1). Set this to zero for
-* keywords (e.g. CRVAL) which are not indexed by either pixel axis or
-* parameter number.
-* val
-* The keyword value to store.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- int el; /* Array index */
- int nel; /* Number of elements in array */
- int si; /* Integer co-ordinate version index */
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* Convert the character co-ordinate version into an integer index, and
- check it is within range. The primary axis description (s=' ') is
- given index zero. 'A' is 1, 'B' is 2, etc. */
- if( s == ' ' ) {
- si = 0;
- } else if( islower(s) ){
- si = (int) ( s - 'a' ) + 1;
- } else {
- si = (int) ( s - 'A' ) + 1;
- }
- if( si < 0 || si > 26 ) {
- astError( AST__INTER, "SetItem(fitschan): AST internal error; "
- "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s );
-
-/* Check the intermediate axis index is within range. */
- } else if( i < 0 || i > 98 ) {
- astError( AST__INTER, "SetItem(fitschan): AST internal error; "
- "intermediate axis index %d is invalid.", status, i );
-
-/* Check the pixel axis or parameter index is within range. */
- } else if( jm < 0 || jm > 99 ) {
- astError( AST__INTER, "SetItem(fitschan): AST internal error; "
- "pixel axis or parameter index %d is invalid.", status, jm );
-
-/* Otherwise proceed... */
- } else {
-
-/* Store the current number of coordinate versions in the supplied array */
- nel = astSizeOf( (void *) *item )/sizeof(double **);
-
-/* If required, extend the array located by the supplied pointer so that
- it is long enough to hold the specified co-ordinate version. */
- if( nel < si + 1 ){
- *item = (double ***) astGrow( (void *) *item, si + 1,
- sizeof(double **) );
-
-/* Check the pointer can be used. */
- if( astOK ){
-
-/* Initialise the new elements to hold NULL. Note, astGrow may add more
- elements to the array than is actually needed, so use the actual current
- size of the array as implied by astSize rather than the index si. */
- for( el = nel;
- el < astSizeOf( (void *) *item )/sizeof(double **);
- el++ ) (*item)[el] = NULL;
- }
- }
-
-/* If the above went OK... */
- if( astOK ){
-
-/* Store the currrent number of intermediate axes in the supplied array */
- nel = astSizeOf( (void *) (*item)[si] )/sizeof(double *);
-
-/* If required, extend the array so that it is long enough to hold the
- specified intermediate axis. */
- if( nel < i + 1 ){
- (*item)[si] = (double **) astGrow( (void *) (*item)[si], i + 1,
- sizeof(double *) );
-
-/* Check the pointer can be used. */
- if( astOK ){
-
-/* Initialise the new elements to hold NULL. */
- for( el = nel;
- el < astSizeOf( (void *) (*item)[si] )/sizeof(double *);
- el++ ) (*item)[si][el] = NULL;
- }
- }
-
-/* If the above went OK... */
- if( astOK ){
-
-/* Store the current number of pixel axis or parameter values in the array. */
- nel = astSizeOf( (void *) (*item)[si][i] )/sizeof(double);
-
-/* If required, extend the array so that it is long enough to hold the
- specified axis. */
- if( nel < jm + 1 ){
- (*item)[si][i] = (double *) astGrow( (void *) (*item)[si][i],
- jm + 1, sizeof(double) );
-
-/* Check the pointer can be used. */
- if( astOK ){
-
-/* Initialise the new elements to hold AST__BAD. */
- for( el = nel;
- el < astSizeOf( (void *) (*item)[si][i] )/sizeof(double);
- el++ ) (*item)[si][i][el] = AST__BAD;
- }
- }
-
-/* If the above went OK, store the supplied keyword value. */
- if( astOK ) (*item)[si][i][jm] = val;
- }
- }
- }
-}
-
-static void SetItemC( char *****item, int i, int jm, char s, const char *val,
- int *status ){
-/*
-* Name:
-* SetItemC
-
-* Purpose:
-* Store a character string for an axis keyword value in a FitStore
-* structure.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void SetItemC( char *****item, int i, int jm, char s, const char *val,
-* int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The supplied keyword string value is stored in the specified array,
-* at a position indicated by the axis and co-ordinate version.
-* The array is created or extended as necessary to make room for
-* the new value. Any old value is over-written.
-
-* Parameters:
-* item
-* The address of the pointer within the FitsStore which locates the
-* arrays of values for the required keyword (eg &(store->ctype) ).
-* The array located by the supplied pointer contains a vector of
-* pointers. Each of these pointers is associated with a particular
-* co-ordinate version (s), and locates an array of pointers for that
-* co-ordinate version. Each such array of pointers has an element
-* for each intermediate axis number (i), and the pointer locates an
-* array of axis keyword string pointers. These arrays of keyword
-* string pointers have one element for every pixel axis (j) or
-* projection parameter (m).
-* i
-* The zero based intermediate axis index in the range 0 to 98. Set
-* this to zero for keywords (e.g. RADESYS) which are not indexed by
-* intermediate axis number.
-* jm
-* The zero based pixel axis index (in the range 0 to 98) or parameter
-* index (in the range 0 to WCSLIB__MXPAR-1). Set this to zero for
-* keywords (e.g. CTYPE) which are not indexed by either pixel axis or
-* parameter number.
-* val
-* The keyword string value to store. A copy of the supplied string
-* is taken.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- int el; /* Array index */
- int nel; /* Number of elements in array */
- int si; /* Integer co-ordinate version index */
-
-/* Check the inherited status and the supplied pointer. */
- if( !astOK || !val ) return;
-
-/* Convert the character co-ordinate version into an integer index, and
- check it is within range. The primary axis description (s=' ') is
- given index zero. 'A' is 1, 'B' is 2, etc. */
- if( s == ' ' ) {
- si = 0;
- } else if( islower(s) ){
- si = (int) ( s - 'a' ) + 1;
- } else {
- si = (int) ( s - 'A' ) + 1;
- }
- if( si < 0 || si > 26 ) {
- astError( AST__INTER, "SetItemC(fitschan): AST internal error; "
- "co-ordinate version '%c' ( char(%d) ) is invalid.", status, s, s );
-
-/* Check the intermediate axis index is within range. */
- } else if( i < 0 || i > 98 ) {
- astError( AST__INTER, "SetItemC(fitschan): AST internal error; "
- "intermediate axis index %d is invalid.", status, i );
-
-/* Check the pixel axis or parameter index is within range. */
- } else if( jm < 0 || jm > 99 ) {
- astError( AST__INTER, "SetItemC(fitschan): AST internal error; "
- "pixel axis or parameter index %d is invalid.", status, jm );
-
-/* Otherwise proceed... */
- } else {
-
-/* Store the current number of coordinate versions in the supplied array */
- nel = astSizeOf( (void *) *item )/sizeof(char ***);
-
-/* If required, extend the array located by the supplied pointer so that
- it is long enough to hold the specified co-ordinate version. */
- if( nel < si + 1 ){
- *item = (char ****) astGrow( (void *) *item, si + 1,
- sizeof(char ***) );
-
-/* Check the pointer can be used. */
- if( astOK ){
-
-/* Initialise the new elements to hold NULL. Note, astGrow may add more
- elements to the array than is actually needed, so use the actual current
- size of the array as implied by astSize rather than the index si. */
- for( el = nel;
- el < astSizeOf( (void *) *item )/sizeof(char ***);
- el++ ) (*item)[el] = NULL;
- }
- }
-
-/* If the above went OK... */
- if( astOK ){
-
-/* Store the currrent number of intermediate axes in the supplied array */
- nel = astSizeOf( (void *) (*item)[si] )/sizeof(char **);
-
-/* If required, extend the array so that it is long enough to hold the
- specified intermediate axis. */
- if( nel < i + 1 ){
- (*item)[si] = (char ***) astGrow( (void *) (*item)[si], i + 1,
- sizeof(char **) );
-
-/* Check the pointer can be used. */
- if( astOK ){
-
-/* Initialise the new elements to hold NULL. */
- for( el = nel;
- el < astSizeOf( (void *) (*item)[si] )/sizeof(char **);
- el++ ) (*item)[si][el] = NULL;
- }
- }
-
-/* If the above went OK... */
- if( astOK ){
-
-/* Store the current number of pixel axis or parameter values in the array. */
- nel = astSizeOf( (void *) (*item)[si][i] )/sizeof(char *);
-
-/* If required, extend the array so that it is long enough to hold the
- specified axis. */
- if( nel < jm + 1 ){
- (*item)[si][i] = (char **) astGrow( (void *) (*item)[si][i],
- jm + 1, sizeof(char *) );
-
-/* Check the pointer can be used. */
- if( astOK ){
-
-/* Initialise the new elements to hold NULL. */
- for( el = nel;
- el < astSizeOf( (void *) (*item)[si][i] )/sizeof(char *);
- el++ ) (*item)[si][i][el] = NULL;
- }
- }
-
-/* If the above went OK... */
- if( astOK ){
-
-/* Store a copy of the supplied string, using any pre-allocated memory. */
- (*item)[si][i][jm] = (char *) astStore( (void *) (*item)[si][i][jm],
- (void *) val,
- strlen( val ) + 1 );
- }
- }
- }
- }
-}
-
-static void SetSourceFile( AstChannel *this_channel, const char *source_file,
- int *status ) {
-/*
-* Name:
-* SetSourceFile
-
-* Purpose:
-* Set a new value for the SourceFile attribute.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void SetSourceFile( AstChannel *this, const char *source_file,
-* int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the astSetSourceFile
-* method inherited from the Channel class).
-
-* Description:
-* This function stores the supplied string as the new value for the
-* SourceFile attribute. In addition, it also attempts to open the
-* file, read FITS headers from it and append them to the end of the
-* FitsChan. It then closes the SourceFile.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* source_file
-* The new attribute value. Should be the path to an existing text
-* file, holding FITS headers (one per line)
-* status
-* Inherited status pointer.
-
-*/
-
-/* Local Constants: */
-#define ERRBUF_LEN 80
-
-/* Local Variables: */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- FILE *fd; /* Descriptor for source file */
- char *errstat; /* Pointer for system error message */
- char card[ AST__FITSCHAN_FITSCARDLEN + 2 ]; /* Buffer for source line */
- char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Invoke the parent astSetSourceFile method to store the supplied
- string in the Channel structure. */
- (*parent_setsourcefile)( this_channel, source_file, status );
-
-/* Attempt to open the file. */
- fd = NULL;
- if( astOK ) {
- fd = fopen( source_file, "r" );
- if( !fd ) {
- if ( errno ) {
-#if HAVE_STRERROR_R
- strerror_r( errno, errbuf, ERRBUF_LEN );
- errstat = errbuf;
-#else
- errstat = strerror( errno );
-#endif
- astError( AST__RDERR, "astSetSourceFile(%s): Failed to open input "
- "SourceFile '%s' - %s.", status, astGetClass( this ),
- source_file, errstat );
- } else {
- astError( AST__RDERR, "astSetSourceFile(%s): Failed to open input "
- "SourceFile '%s'.", status, astGetClass( this ),
- source_file );
- }
- }
- }
-
-/* Move the FitsChan to EOF */
- astSetCard( this, INT_MAX );
-
-/* Read each line from the file, remove trailing space, and append to the
- FitsChan. */
- while( astOK && fgets( card, AST__FITSCHAN_FITSCARDLEN + 2, fd ) ) {
- card[ astChrLen( card ) ] = 0;
- astPutFits( this, card, 0 );
- }
-
-/* Close the source file. */
- if( fd ) fclose( fd );
-
-}
-
-static void SetTableSource( AstFitsChan *this,
- void (*tabsource)( void ),
- void (*tabsource_wrap)( void (*)( void ),
- AstFitsChan *, const char *,
- int, int, int * ),
- int *status ){
-
-/*
-*+
-* Name:
-* astSetTableSource
-
-* Purpose:
-* Register source and wrapper function for accessing tables in FITS files.
-
-* Type:
-* Protected function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void astSetTableSource( AstFitsChan *this,
-* void (*tabsource)( void ),
-* void (*tabsource_wrap)( void (*)( void ),
-* AstFitsChan *, const char *,
-* int, int, int * ),
-* int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function registers a table source function and its wrapper. A
-* wrapper function exists to adapt the API of the table source
-* function to the needs of different languages. The wrapper is called
-* from the FitsChan code. The wrapper then adjusts the arguments as
-* required and then calls the actualy table source function.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* tabsource
-* Pointer to the table source function. The API for this function
-* will depend on the language, and so is cast to void here. It
-* should be cast to the required form within the wrapper function.
-* tabsource_wrap
-* The wrapper function.
-*-
-*/
-
-/* Local Variables: */
-
-/* Check the global error status. */
- if ( !astOK ) return;
- this->tabsource = tabsource;
- this->tabsource_wrap = tabsource_wrap;
-}
-
-static void SetValue( AstFitsChan *this, const char *keyname, void *value,
- int type, const char *comment, int *status ){
-
-/*
-* Name:
-* SetValue
-
-* Purpose:
-* Save a FITS keyword value, over-writing any existing keyword value.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void SetValue( AstFitsChan *this, char *keyname, void *value,
-* int type, const char *comment, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function saves a keyword value as a card in the supplied
-* FitsChan. Comment cards are always inserted in-front of the current
-* card. If the keyword is not a comment card, any existing value
-* for the keyword is over-written with the new value (even if it is
-* marked as having been read). Otherwise, (i.e. if it is not a comment
-* card, and no previous value exists) it is inserted in front
-* of the current card.
-
-* Parameters:
-* this
-* A pointer to the FitsChan.
-* keyname
-* A pointer to a string holding the keyword name.
-* value
-* A pointer to a buffer holding the keyword value. For strings,
-* the buffer should hold a pointer to the character string.
-* type
-* The FITS data type of the supplied keyword value.
-* comment
-* A comment to store with the keyword.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - Nothing is stored if a NULL pointer is supplied for "value".
-* - If the keyword has a value of AST__BAD then nothing is stored,
-* and an error is reported.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- FitsCard *card; /* Pointer to original current card */
- const char *class; /* Class name to include in error messages */
- const char *method; /* Method name to include in error messages */
- int newcard; /* Has the original current card been deleted? */
- int old_ignore_used; /* Original setting of external ignore_used variable */
- int stored; /* Has the keyword been stored? */
-
-/* Check the status and supplied value pointer. */
- if( !astOK || !value ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Set up the method and class names for inclusion in error mesages. */
- method = "astWrite";
- class = astGetClass( this );
-
-/* Comment card are always inserted in-front of the current card. */
- if ( type == AST__COMMENT ) {
- SetFits( this, keyname, value, type, comment, 0, status );
-
-/* Otherwise... */
- } else {
-
-/* Report an error if a bad value is stored for a keyword. */
- if( type == AST__FLOAT ){
- if( *( (double *) value ) == AST__BAD && astOK ) {
- astError( AST__BDFTS, "%s(%s): The required FITS keyword "
- "\"%s\" is indeterminate.", status, method, class, keyname );
- }
- }
-
-/* Save a pointer to the current card. */
- card = (FitsCard *) this->card;
-
-/* Indicate that we should not skip over cards marked as having been
- read. */
- old_ignore_used = ignore_used;
- ignore_used = 0;
-
-/* Indicate that we have not yet stored the keyword value. */
- stored = 0;
-
-/* Attempt to find a card refering to the supplied keyword. If one is
- found, it becomes the current card. */
- if( SearchCard( this, keyname, "astWrite", astGetClass( this ), status ) ){
-
-/* If the card which was current on entry to this function will be
- over-written, we will need to take account of this when re-instating the
- original current card. Make a note of this. */
- newcard = ( card == (FitsCard *) this->card );
-
-/* Replace the current card with a card holding the supplied information. */
- SetFits( this, keyname, value, type, comment, 1, status );
- stored = 1;
-
-/* If we have just replaced the original current card, back up a card
- so that the replacement card becomes the current card. */
- if( newcard ) {
- MoveCard( this, -1, "astWrite", astGetClass( this ), status );
-
-/* Otherwise, re-instate the original current card. */
- } else {
- this->card = (void *) card;
- }
- }
-
-/* If the keyword has not yet been stored (i.e. if it did not exist in the
- FitsChan), re-instate the original current card and insert the new card
- before the original current card, leaving the current card unchanged. */
- if( !stored ) {
- this->card = (void *) card;
- SetFits( this, keyname, value, type, comment, 0, status );
- }
-
-/* Re-instate the original flag indicating if cards marked as having been
- read should be skipped over. */
- ignore_used = old_ignore_used;
- }
-}
-
-static void Shpc1( double xmin, double xmax, int n, double *d, double *w,
- int *status ){
-/*
-* Name:
-* Shpc1
-
-* Purpose:
-* Modifies a one-dimensional polynomial to scale the polynomial argument.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void Shpc1( double xmin, double xmax, int n, double *d, double *w,
-* int *status )
-
-* Description:
-* Given the coefficients of a one-dimensional polynomial P(u) defined on a
-* unit interval (i.e. -1 <= u <= +1 ), find the coefficients of another
-* one-dimensional polynomial Q(x) where:
-*
-* Q(x) = P(u)
-* u = ( 2*x - ( xmax + xmin ) ) / ( xmax - xmin )
-*
-* That is, u is a scaled version of x, such that the unit interval in u
-* maps onto (xmin:xmax) in x.
-
-* Parameters:
-* xmin
-* X value corresponding to u = -1
-* xmax
-* X value corresponding to u = +1
-* n
-* One more than the maximum power of u within P.
-* d
-* An array of n elements supplied holding the coefficients of P such
-* that the coefficient of (u^i) is held in element (i).
-* w
-* An array of n elements returned holding the coefficients of Q such
-* that the coefficient of (x^i) is held in element (i).
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - Vaguely inspired by the Numerical Recipes routine "pcshft". But the
-* original had bugs, so I wrote this new version from first principles.
-
-*/
-
-/* Local Variables: */
- double b;
- double a;
- int j;
- int i;
-
-/* Check inherited status */
- if( !astOK ) return;
-
-/* Get the scale and shift terms so that u = a*x + b */
- a = 2.0/( xmax - xmin );
- b = ( xmin + xmax )/( xmin - xmax );
-
-/* Initialise the returned coeffs */
- for( i = 0; i < n; i++ ) w[ i ] = 0.0;
-
-/* The supplied Polynomial is
-
- P(u) = d0 + d1*u + d2*u^2 + ...
-
- = d0 + u*( d1 + u*( d2 + ... u*( d{n-1} ) ) ) . . . . . (1)
-
- = d0 + (a*x+b)*( d1 + (a*x+b)*( d2 + ... (a*x+b)*( d[n-1] ) ) )
-
- The inner-most parenthesised expression is a polynomial of order zero
- (a constant - d[n-1]). Store the coefficients of this zeroth order
- polynomial in the returned array. The "w" array is used to hold the
- coefficients of Q, i.e. coefficients of powers of "x", not "u", but
- since the inner-most polynomial is a constant, it makes no difference
- (x^0 == u^0 == 1). */
- w[ 0 ] = d[ n - 1 ];
-
-/* Now loop through each remaining level of parenthetic nesting in (1). At
- each level, the parenthesised expression represents a polynomial of order
- "i". At the end of each pass though this loop, the returned array "w"
- holds the coefficients of this "i"th order polynomial. So on the last
- loop, i = n-1, "w" holds the required coefficients of Q. */
- for( i = 1; i < n; i++ ) {
-
-/* If "R" is the polynomial at the "i-1"th level of nesting (the
- coefficiemts of which are currently held in "w"), and "S" is the
- polynomial at the "i"th level of nesting, we can see from (1) that:
-
- S = d[ n - 1 - i ] + u*R
-
- Substituting for "u", this becomes
-
- S = d[ n - 1 - i ] + ( a*x + b )*R
- = d[ n - 1 - i ] + a*R*x + b*R
-
- Looking at each of these three terms in reverse order:
-
- 1) The "b*R" term is implemented by simply scaling the current contents
- of the "w" array by "b"; in the "a*R*x" term.
-
- 2) In "a*R*x", the effect of multiplying by "x" is to move the existing
- coefficients in "w" up one element. We then multiply the shifted
- coefficients by "a" and add them onto the coefficients produced at
- step 1) above.
-
- We know that "w" still contains the initial zeros at indices higher than
- "i" so we only need to scale the bottom "i" elements. We do not do the
- zeroth term in this loop since there is no lower term to shift up into
- it. */
-
- for( j = i; j > 0; j-- ){
- w[ j ] = b*w[ j ] + a*w[ j - 1 ];
- }
-
-/* Now do the zeroth term. Scale the existing zeroth term by "b" as
- required by step 1) and add on the first term, the constant
- "d[ n - 1 - i ]". Step 2) is a no-op, since in effect the value of
- "w[-1]" is zero. */
- w[ 0 ] = d[ n - i - 1 ] + b*w[ 0 ];
- }
-
-}
-
-static void ShowFits( AstFitsChan *this, int *status ){
-
-/*
-*++
-* Name:
-c astShowFits
-f AST_SHOWFITS
-
-* Purpose:
-* Display the contents of a FitsChan on standard output.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-c void astShowFits( AstFitsChan *this )
-f CALL AST_SHOWFITS( THIS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* formats and displays all the cards in a FitsChan on standard output.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-*--
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- char card[ AST__FITSCHAN_FITSCARDLEN + 1]; /* Buffer for header card */
- int icard; /* Current card index on entry */
- int old_ignore_used; /* Original value of external variable ignore_used */
-
-/* Check the global status. */
- if( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Store the current card index. */
- icard = astGetCard( this );
-
-/* Indicate that cards which have been read into an AST object should skipped
- over by the functions which navigate the linked list of cards. */
- old_ignore_used = ignore_used;
- ignore_used = 1;
-
-/* Ensure that the first card in the FitsChan will be the next one to be
- read. */
- astSetCard( this, 1 );
-
-/* Loop round obtaining and writing out each card, until all cards have been
- processed. */
- while( !astFitsEof( this ) && astOK ){
-
-/* Get the current card, and display it. The call to astFindFits increments
- the current card. */
- if( astFindFits( this, "%f", card, 1 ) ) printf( "%s\n", card );
- }
-
-/* Re-instate the original flag indicating if cards marked as having been
- read should be skipped over. */
- ignore_used = old_ignore_used;
-
-/* Set the current card index back to what it was on entry. */
- astSetCard( this, icard );
-
-}
-
-static int Similar( const char *str1, const char *str2, int *status ){
-/*
-* Name:
-* Similar
-
-* Purpose:
-* Are two string effectively the same to human readers?
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void Similar( const char *str1, const char *str2, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function returns a non-zero value if the two supplied strings
-* are equivalent to a human reader. This is assumed to be the case if
-* the strings are equal apart from leading and trailing white space,
-* multiple embedded space, and case.
-
-* Parameters:
-* str1
-* The first string
-* str2
-* The second string
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Non-zero if the two supplied strings are equivalent, and zero
-* otherwise.
-*/
-
-/* Local Variables: */
- const char *ea; /* Pointer to end of string a */
- const char *eb; /* Pointer to end of string b */
- const char *a; /* Pointer to next character in string a */
- const char *b; /* Pointer to next character in string b */
- int result; /* Are the two strings equivalent? */
- int ss; /* Skip subsequent spaces? */
-
-/* Initialise */
- result = 0;
-
-/* Check the status and supplied value pointer. */
- if( !astOK ) return result;
-
-/* Initialise pointers into the two strings. */
- a = str1;
- b = str2;
-
-/* Get a pointer to the character following the last non-blank character in
- each string. */
- ea = a + ChrLen( a, status ) - 1;
- eb = b + ChrLen( b, status ) - 1;
-
-/* Set a flag indicating that spaces before the next non-blank character
- should be ignored. */
- ss = 1;
-
-/* Compare the strings. */
- while( 1 ){
-
-/* Move on to the next significant character in both strings. */
- while( a < ea && *a == ' ' && ss ) a++;
- while( b < eb && *b == ' ' && ss ) b++;
-
-/* If one string has been exhausted but the other has not, the strings
- are not equivalent. */
- if( ( a < ea && b == eb ) || ( a == ea && b < eb ) ) {
- break;
-
-/* If both strings have been exhausted simultaneously, the strings
- are equivalent. */
- } else if( b == eb && a == ea ) {
- result = 1;
- break;
-
-/* If neither string has been exhausted, compare the current character
- for equality, ignoring case. Break if they are different. */
- } else if( tolower( *a ) != tolower( *b ) ){
- break;
-
-/* If the two characters are both spaces, indicate that subsequent spaces
- should be skipped. */
- } else if( *a == ' ' ) {
- ss = 1;
-
-/* If the two characters are not spaces, indicate that subsequent spaces
- should not be skipped. */
- } else {
- ss = 0;
- }
-
-/* Move on to the next characters. */
- a++;
- b++;
- }
-
-/* Return the result. */
- return result;
-}
-
-static void SinkWrap( void (* sink)( const char * ), const char *line, int *status ) {
-/*
-* Name:
-* SinkWrap
-
-* Purpose:
-* Wrapper function to invoke a C FitsChan sink function.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void SinkWrap( void (* sink)( const char * ), const char *line, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function invokes the sink function whose pointer is
-* supplied in order to write an output line to an external data
-* store.
-
-* Parameters:
-* sink
-* Pointer to a sink function, whose single parameter is a
-* pointer to a const, null-terminated string containing the
-* text to be written, and which returns void. This is the form
-* of FitsChan sink function employed by the C language interface
-* to the AST library.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Invoke the sink function. */
- ( *sink )( line );
-}
-
-static AstMapping *SIPMapping( double *dim, FitsStore *store, char s,
- int naxes, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* SIPMapping
-
-* Purpose:
-* Create a Mapping descriping "-SIP" (Spitzer) distortion.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstMapping *SIPMapping( double *dim, FitsStore *store, char s, int naxes,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function uses the values in the supplied FitsStore to create a
-* Mapping which implements the "-SIP" distortion code. This is the
-
-* code used by the Spitzer project and is described in:
-*
-* http://irsa.ipac.caltech.edu/data/SPITZER/docs/files/spitzer/shupeADASS.pdf
-*
-* SIP distortion can only be applied to axes 0 and 1. Other axes are
-* passed unchanged by the returned Mapping.
-
-* Parameters:
-* dim
-* The dimensions of the array in pixels. AST__BAD is stored for
-* each value if dimensions are not known.
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* naxes
-* The number of intermediate world coordinate axes (WCSAXES).
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the Mapping.
-*/
-
-/* Local Variables: */
- AstMapping *ret; /* Pointer to the returned Mapping */
- AstPolyMap *pmap; /* PolyMap describing the distortion */
- AstPolyMap *pmap2; /* New PolyMap describing the distortion */
- double ****item; /* Address of FitsStore item to use */
- double *c; /* Pointer to start of coefficient description */
- double *coeff_f; /* Array of coeffs. for forward transformation */
- double *coeff_i; /* Array of coeffs. for inverse transformation */
- double cof; /* Coefficient value */
- double lbnd[ 2 ]; /* Lower bounds of fitted region */
- double ubnd[ 2 ]; /* Upper bounds of fitted region */
- int def; /* Is transformation defined? */
- int iin; /* Input (u or v) index */
- int iout; /* Output (U or V) index */
- int ncoeff_f; /* No. of coeffs. for forward transformation */
- int ncoeff_i; /* No. of coeffs. for inverse transformation */
- int p; /* Power of u or U */
- int pmax; /* Max power of u or U */
- int q; /* Power of v or V */
- int qmax; /* Max power of v or V */
-
-/* Initialise the pointer to the returned Mapping. */
- ret = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return ret;
-
-/* Store coefficients of the forward transformation:
- ================================================ */
-
-/* Indicate that we have as yet no coefficients for the forward polynomials. */
- ncoeff_f = 0;
-
-/* Indicate that we do not yet have any evidence that the forward
- transformation is defined. */
- def = 0;
-
-/* Allocate workspace to hold descriptions of (initially) 20 coefficients used
- within the forward polynomials. */
- coeff_f = astMalloc( sizeof( double )*20 );
-
-/* Store the coefficients of the polynomial which produces each output
- axis (U or V) in turn. */
- for( iout = 0; iout < 2; iout++ ){
-
-/* Get a pointer to the FitsStore item holding the values defining this
- output. */
- item = ( iout == 0 ) ? &(store->asip) : &(store->bsip);
-
-/* Get the largest powers used of u and v. */
- pmax = GetMaxI( item, s, status );
- qmax = GetMaxJM( item, s, status );
-
-/* Loop round all combination of powers. */
- for( p = 0; p <= pmax; p++ ){
- for( q = 0; q <= qmax; q++ ){
-
-/* Get the polynomial coefficient for this combination of powers. */
- cof = GetItem( item, p, q, s, NULL, method, class, status );
-
-/* If there is no coefficient for this combination of powers, use a value
- of zero. Otherwise indicate we have found at least one coefficient. */
- if( cof == AST__BAD ) {
- cof = 0.0;
- } else {
- def = 1;
- }
-
-/* The distortion polynomial gives a correction to be added on to the
- input value. On the other hand, the returned Mapping is a direct
- transformation from input to output. Therefore increment the coefficient
- value by 1 for the term which corresponds to the current output axis. */
- if( p == ( 1 - iout ) && q == iout ) cof += 1.0;
-
-/* If the coefficient is not zero, store it in the array of coefficient
- descriptions. */
- if( cof != 0.0 ) {
-
-/* Increment the number of coefficients for the forward polynomials. */
- ncoeff_f++;
-
-/* Ensure the "coeff_f" array is large enough to hold the new coefficient. */
- coeff_f = astGrow( coeff_f, sizeof( double )*4, ncoeff_f );
- if( astOK ) {
-
-/* Store it. Each coefficient is described by 4 values (since we have 2
- inputs to the Mapping). The first is the coefficient value, the second
- is the (1-based) index of the output to which the coefficient relates.
- The next is the power of input 0, and the last one is the power of input 1. */
- c = coeff_f + 4*( ncoeff_f - 1 );
- c[ 0 ] = cof;
- c[ 1 ] = iout + 1;
- c[ 2 ] = p;
- c[ 3 ] = q;
- }
- }
- }
- }
- }
-
-/* If no coefficients were supplied in the FitsStore, the forward
- transformation is undefined. */
- if( !def ) ncoeff_f = 0;
-
-/* Store coefficients of the inverse transformation:
- ================================================ */
-
-/* Indicate that we have as yet no coefficients for the inverse polynomials. */
- ncoeff_i = 0;
-
-/* Indicate that we do not yet have any evidence that the forward
- transformation is defined. */
- def = 0;
-
-/* Allocate workspace to hold descriptions of (initially) 20 coefficients used
- within the inverse polynomials. */
- coeff_i = astMalloc( sizeof( double )*20 );
-
-/* Store the coefficients of the polynomial which produces each input
- axis (u or v) in turn. */
- for( iin = 0; iin < 2; iin++ ){
-
-/* Get a pointer to the FitsStore item holding the values defining this
- output. */
- item = ( iin == 0 ) ? &(store->apsip) : &(store->bpsip);
-
-/* Get the largest powers used of U and V. */
- pmax = GetMaxI( item, s, status );
- qmax = GetMaxJM( item, s, status );
-
-/* Loop round all combination of powers. */
- for( p = 0; p <= pmax; p++ ){
- for( q = 0; q <= qmax; q++ ){
-
-/* Get the polynomial coefficient for this combination of powers. */
- cof = GetItem( item, p, q, s, NULL, method, class, status );
-
-/* If there is no coefficient for this combination of powers, use a value
- of zero. Otherwise indicate we have found at least one coefficient. */
- if( cof == AST__BAD ) {
- cof = 0.0;
- } else {
- def = 1;
- }
-
-/* The distortion polynomial gives a correction to be added on to the
- output value. On the other hand, the returned Mapping is a direct
- transformation from output to input. Therefore increment the coefficient
- value by 1 for the term which corresponds to the current input axis. */
- if( p == ( 1 - iin ) && q == iin ) cof += 1.0;
-
-/* If the coefficient is not zero, store it in the array of coefficient
- descriptions. */
- if( cof != 0.0 ) {
-
-/* Increment the number of coefficients for the inverse polynomials. */
- ncoeff_i++;
-
-/* Ensure the "coeff_i" array is large enough to hold the new coefficient. */
- coeff_i = astGrow( coeff_i, sizeof( double )*4, ncoeff_i );
- if( astOK ) {
-
-/* Store it. Each coefficient is described by 4 values (since we have 2
- outputs to the Mapping). The first is the coefficient value, the second
- is the (1-based) index of the input to which the coefficient relates. The
- next is the power of output 0, and the last one is the power of output 1. */
- c = coeff_i + 4*( ncoeff_i - 1 );
- c[ 0 ] = cof;
- c[ 1 ] = iin + 1;
- c[ 2 ] = p;
- c[ 3 ] = q;
- }
- }
- }
- }
- }
-
-/* If no coefficients were supplied in the FitsStore, the forward
- transformation is undefined. */
- if( !def ) ncoeff_i = 0;
-
-/* Create the returned Mapping:
- ============================ */
-
-/* If neither transformation is defined, create a UnitMap. */
- if( ncoeff_f == 0 && ncoeff_i == 0 ){
- ret = (AstMapping *) astUnitMap( naxes, "", status );
-
-/* Otherwise, create a PolyMap to describe axes 0 and 1. */
- } else {
- pmap = astPolyMap( 2, 2, ncoeff_f, coeff_f, ncoeff_i, coeff_i, "", status );
-
-/* The inverse transformations supplied within SIP headers are often
- inaccurate. So replace any existing inverse by sampling the supplied
- transformation, and fitting a polynomial to the sampled positions. If
- the fit fails to reach 0.01 pixel accuracy, forget it and rely on the
- (slower) iterative inverse provided by the PolyMap class. Do the fit
- over an area three times the size of the image to provide accurate
- values outside the image.*/
- lbnd[ 0 ] = ( dim[ 0 ] != AST__BAD ) ? -dim[ 0 ] : -1000.0;
- lbnd[ 1 ] = ( dim[ 1 ] != AST__BAD ) ? -dim[ 1 ] : -1000.0;
- ubnd[ 0 ] = ( dim[ 0 ] != AST__BAD ) ? 2*dim[ 0 ] : 2000.0;
- ubnd[ 1 ] = ( dim[ 1 ] != AST__BAD ) ? 2*dim[ 1 ] : 2000.0;
- pmap2 = astPolyTran( pmap, (ncoeff_f == 0), 0.0001, 0.01, 7, lbnd,
- ubnd );
- if( pmap2 ) {
- (void) astAnnul( pmap );
- pmap = pmap2;
- } else {
- astSet( pmap, "IterInverse=1,NiterInverse=6,TolInverse=1.0E-8",
- status );
- }
-
-/* Add the above Mapping in parallel with a UnitMap which passes any
- other axes unchanged. */
- ret = AddUnitMaps( (AstMapping *) pmap, 0, naxes, status );
- pmap = astAnnul( pmap );
- }
-
-/* Free resources. */
- coeff_f = astFree( coeff_f );
- coeff_i = astFree( coeff_i );
-
-/* Return the result. */
- return ret;
-}
-
-static void SkyPole( AstWcsMap *map2, AstMapping *map3, int ilon, int ilat,
- int *wperm, char s, FitsStore *store, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* SkyPole
-
-* Purpose:
-* Put values for FITS keywords LONPOLE and LATPOLE into a FitsStore.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void SkyPole( AstWcsMap *map2, AstMapping *map3, int ilon, int ilat,
-* int *wperm, char s, FitsStore *store, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function calculates values for the LONPOLE and LATPOLE FITS
-* keywords and stores them in the supplied FitsStore. LONPOLE and
-* LATPOLE are the longitude and latitude of the celestial north pole
-* in native spherical coordinates.
-
-* Parameters:
-* map2
-* Pointer to the Mapping from Intermediate World Coordinates to Native
-* Spherical Coordinates.
-* map3
-* Pointer to the Mapping from Native Spherical Coordinates to celestial
-* coordinates.
-* ilon
-* Zero-based index of longitude output from "map3".
-* ilat
-* Zero-based index of latitude output from "map3".
-* wperm
-* Pointer to an array of integers with one element for each axis of
-* the current Frame. Each element holds the zero-based
-* index of the FITS-WCS axis (i.e. the value of "i" in the keyword
-* names "CTYPEi", "CRVALi", etc) which describes the Frame axis.
-* s
-* The co-ordinate version character. A space means the primary
-* axis descriptions. Otherwise the supplied character should be
-* an upper case alphabetical character ('A' to 'Z').
-* store
-* The FitsStore in which to store the FITS WCS keyword values.
-* 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.
-*/
-
-/* Local Variables: */
- AstPointSet *pset1; /* PointSet holding intermediate wcs coords */
- AstPointSet *pset2; /* PointSet holding final WCS coords */
- double **ptr1; /* Pointer to coordinate data */
- double **ptr2; /* Pointer to coordinate data */
- double alpha0; /* Long. of fiducial point in standard system */
- double alphap; /* Celestial longitude of native north pole */
- double deflonpole; /* Default value for lonpole */
- double delta0; /* Lat. of fiducial point in standard system */
- double latpole; /* Native latitude of celestial north pole */
- double lonpole; /* Native longitude of celestial north pole */
- double phi0; /* Native longitude at fiducial point */
- double theta0; /* Native latitude at fiducial point */
- int axlat; /* Index of latitude output from "map2" */
- int axlon; /* Index of longitude output from "map2" */
- int fits_ilat; /* FITS WCS axis index for latitude axis */
- int fits_ilon; /* FITS WCS axis index for longitude axis */
- int iax; /* Axis index */
- int nax; /* Number of IWC axes */
- int nax2; /* Number of WCS axes */
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* Store the indices of the native longitude and latitude outputs of the
- WcsMap. */
- axlon = astGetWcsAxis( map2, 0 );
- axlat = astGetWcsAxis( map2, 1 );
-
-/* Store the indices of the FITS WCS axes for longitude and latitude */
- fits_ilon = wperm[ ilon ];
- fits_ilat = wperm[ ilat ];
-
-/* To find the longitude and latitude of the celestial north pole in native
- spherical coordinates, we will transform the coords of the celestial north
- pole into spherical cords using the inverse of "map2", and if the resulting
- native spherical coords differ from the default values of LONPOLE and
- LATPOLE, we store them in the FitsStore. However, for zenithal projections,
- any value can be used simply by introducing an extra rotation into the
- (X,Y) projection plane. If values have been set in the WcsMap (as
- projection parameters PVi_3 and PVi_4 for longitude axis "i") uses
- them. Otherwise, set the values bad to indicate that the default values
- should be used. Note, these projection parameters are used for other
- purposes in a TPN projection. */
- lonpole = AST__BAD;
- latpole = AST__BAD;
- if( astIsZenithal( map2 ) ) {
- if( astGetWcsType( map2 ) != AST__TPN ) {
- lonpole = astTestPV( map2, axlon, 3 ) ? astGetPV( map2, axlon, 3 )
- : AST__BAD;
- latpole = astTestPV( map2, axlon, 4 ) ? astGetPV( map2, axlon, 4 )
- : AST__BAD;
- }
-
-/* For non-zenithal projections, do the full calculation. */
- } else {
-
-/* Allocate resources. */
- nax = astGetNin( map2 );
- pset1 = astPointSet( 1, nax, "", status );
- ptr1 = astGetPoints( pset1 );
- nax2 = astGetNout( map3 );
- pset2 = astPointSet( 1, nax2, "", status );
- ptr2 = astGetPoints( pset2 );
- if( astOK ) {
-
-/* Calculate the longitude and latitude of the celestial north pole
- in native spherical coordinates (using the inverse of map3). These
- values correspond to the LONPOLE and LATPOLE keywords. */
- for( iax = 0; iax < nax2; iax++ ) ptr2[ iax ][ 0 ] = 0.0;
- ptr2[ ilat ][ 0 ] = AST__DPIBY2;
- (void) astTransform( map3, pset2, 0, pset1 );
-
-/* Retrieve the latitude and longitude (in the standard system) of the
- fiducial point (i.e. CRVAL), in radians. */
- delta0 = GetItem( &(store->crval), fits_ilat, 0, s, NULL, method, class, status );
- if( delta0 == AST__BAD ) delta0 = 0.0;
- delta0 *= AST__DD2R;
- alpha0 = GetItem( &(store->crval), fits_ilon, 0, s, NULL, method, class, status );
- if( alpha0 == AST__BAD ) alpha0 = 0.0;
- alpha0 *= AST__DD2R;
-
-/* The default value of the LATPOLE is defined by equation 8 of FITS-WCS
- paper II (taking the +ve signs). Find this value. */
- if( WcsNatPole( NULL, map2, alpha0, delta0, 999.0, ptr1[ axlon ],
- &alphap, &latpole, status ) ){
-
-/* If the default value is defined, compare it to the latitude of the
- north pole found above. If they are equal use a bad value instead to
- prevent an explicit keyword from being added to the FitsChan. */
- if( EQUALANG( ptr1[ axlat ][ 0 ], latpole ) ) {
- latpole = AST__BAD;
- } else {
- latpole = ptr1[ axlat ][ 0 ];
- }
-
-/* If the default value is not defined, always store an explicit LATPOLE
- value. */
- } else {
- latpole = ptr1[ axlat ][ 0 ];
- }
-
-/* The default LONPOLE value is zero if the celestial latitude at the
- fiducial point is greater than or equal to the native latitude at the
- fiducial point. Otherwise, the default is (+ or -) 180 degrees. If LONPOLE
- takes the default value, replace it with AST__BAD to prevent an explicit
- keyword being stored in the FitsChan. */
- GetFiducialNSC( map2, &phi0, &theta0, status );
- lonpole = palDranrm( ptr1[ axlon ][ 0 ] );
- if( delta0 >= theta0 ){
- deflonpole = 0.0;
- } else {
- deflonpole = AST__DPI;
- }
- if( EQUALANG( lonpole, deflonpole ) ) lonpole = AST__BAD;
- }
-
-/* Convert from radians to degrees. */
- if( lonpole != AST__BAD ) lonpole *= AST__DR2D;
- if( latpole != AST__BAD ) latpole *= AST__DR2D;
-
-/* Free resources. */
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
- }
-
-/* Store these values. */
- SetItem( &(store->lonpole), 0, 0, s, lonpole, status );
- SetItem( &(store->latpole), 0, 0, s, latpole, status );
-
-/* FITS-WCS paper 2 recommends putting a copy of LONPOLE and LATPOLE in
- projection parameters 3 and 4 associated with the longitude axis. Only do
- this if the projection is not TPN (since this projection uses these
- parameters for other purposes). */
- if( astGetWcsType( map2 ) != AST__TPN ) {
- SetItem( &(store->pv), fits_ilon, 3, s, lonpole, status );
- SetItem( &(store->pv), fits_ilon, 4, s, latpole, status );
- }
-}
-
-static int SkySys( AstFitsChan *this, AstSkyFrame *skyfrm, int wcstype,
- int wcsproj, FitsStore *store, int axlon, int axlat, char s,
- int isoff, const char *method, const char *class, int *status ){
-/*
-* Name:
-* SkySys
-
-* Purpose:
-* Return FITS-WCS values describing a sky coordinate system.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int SkySys( AstFitsChan *this, AstSkyFrame *skyfrm, int wcstype,
-* int wcsproj, FitsStore *store, int axlon, int axlat, char s,
-* int isoff, const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function sets values for the following FITS-WCS keywords
-* within the supplied FitsStore structure: CTYPE, CNAME, RADESYS, EQUINOX,
-* MJDOBS, CUNIT, OBSGEO-X/Y/Z. The values are derived from the supplied
-* SkyFrame and WcsMap.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* skyfrm
-* A pointer to the SkyFrame to be described.
-* wcstype
-* The type of WCS: 0 = TAB, 1 = WcsMap projection.
-* wcsproj
-* An identifier for the type of WCS projection to use. Should be
-* one of the values defined by the WcsMap class. Only used if "wcstype"
-* is 1.
-* store
-* A pointer to the FitsStore structure in which to store the
-* results.
-* axlon
-* The index of the FITS WCS longitude axis (i.e. the value of "i"
-* in "CTYPEi").
-* axlat
-* The index of the FITS WCS latitude axis (i.e. the value of "i"
-* in "CTYPEi").
-* s
-* Co-ordinate version character.
-* isoff
-* If greater than zero, the description to add to the FitsStore
-* should describe offset coordinates. If less than zero, the
-* description to add to the FitsStore should describe absolute
-* coordinates but should include the SkyRefIs, SkyRef and SkyRefP
-* attributes. If zero, ignore all offset coordinate info. The
-* absolute value indicates the nature of the reference point:
-* 1 == "pole", 2 == "origin", otherwise "ignored".
-* 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:
-* Are the keywords values in the FitsStore usable?
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- char *label; /* Pointer to axis label string */
- char attr[20]; /* Buffer for AST attribute name */
- char com[80]; /* Buffer for keyword comment */
- char lattype[MXCTYPELEN];/* Latitude axis CTYPE value */
- char lontype[MXCTYPELEN];/* Longitude axis CTYPE value */
- const char *latsym; /* SkyFrame latitude axis symbol */
- const char *lonsym; /* SkyFrame longitude axis symbol */
- const char *prj_name; /* Pointer to projection name string */
- const char *skyref; /* Formatted SkyRef position */
- const char *skyrefis; /* SkyRefIs value */
- const char *sys; /* Celestal coordinate system */
- const char *timesys; /* Timescale specified in FitsChan */
- double ep; /* Epoch of observation in required timescale (MJD) */
- double ep_tdb; /* Epoch of observation in TDB timescale (MJD) */
- double ep_utc; /* Epoch of observation in UTC timescale (MJD) */
- double eq; /* Epoch of reference equinox (MJD) */
- double geolat; /* Geodetic latitude of observer (radians) */
- double geolon; /* Geodetic longitude of observer (radians) */
- double h; /* Geodetic altitude of observer (metres) */
- double skyref_lat; /* SkyRef latitude value (rads) */
- double skyrefp_lat; /* SkyRefP latitude value (rads) */
- double skyref_lon; /* SkyRef longitude value (rads) */
- double skyrefp_lon; /* SkyRefP longitude value (rads) */
- double xyz[3]; /* Geocentric position vector (in m) */
- int defdate; /* Can the date keywords be defaulted? */
- int i; /* Character count */
- int isys; /* Celestial coordinate system */
- int latax; /* Index of latitude axis in SkyFrame */
- int lonax; /* Index of longitude axis in SkyFrame */
- int ok; /* Do axis symbols conform to FITS-WCS CTYPE form? */
- int old_ignore_used; /* Original setting of external ignore_used variable */
- int ret; /* Returned flag */
-
-/* Check the status. */
- if( !astOK ) return 0;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Check we have a SkyFrame. */
- if( !IsASkyFrame( skyfrm ) ) return 0;
-
-/* Initialise */
- ret = 1;
-
-/* Get the equinox, epoch of observation, and system of the SkyFrame. The epoch
- is in TDB. It is assumed the Equinox is in UTC. */
- eq = astGetEquinox( skyfrm );
- sys = astGetC( skyfrm, "system" );
- ep_tdb = astTestEpoch( skyfrm ) ? astGetEpoch( skyfrm ) : AST__BAD;
-
-/* Convert the epoch to UTC. */
- ep_utc = TDBConv( ep_tdb, AST__UTC, 1, method, class, status );
-
-/* See if the FitsChan contains a value for the TIMESYS keyword (include
- previously used cards in the search). If so, and if it is not UTC, convert
- the epoch to the specified time scale, and store a TIMESYS value in the
- FitsStore. */
- old_ignore_used = ignore_used;
- ignore_used = 0;
- if( GetValue( this, "TIMESYS", AST__STRING, (void *) &timesys, 0, 0, method,
- class, status ) && strcmp( timesys, "UTC" ) ) {
- ep = TDBConv( ep_tdb, TimeSysToAst( this, timesys, method, class,
- status ),
- 1, method, class, status );
- SetItemC( &(store->timesys), 0, 0, s, timesys, status );
-
-/* If no TIMESYS keyword was found in the FitsChan, or the timesys was
- UTC, we use the UTC epoch value found above. In this case no TIMESYS value
- need be stored in the FitsSTore since UTC is the default for TIMESYS. */
- } else {
- ep = ep_utc;
- }
-
-/* Reinstate the original value for the flag that indicates whether keywords
- in the FitsChan that have been used previously should be ignored. */
- ignore_used = old_ignore_used;
-
-/* The MJD-OBS and DATE-OBS keywords default to the epoch of the
- reference equinox if not supplied. Therefore MJD-OBS and DATE-OBS do
- not need to be stored in the FitsChan if the epoch of observation is
- the same as the epoch of the reference equinox. This can avoid
- producing FITS headers which say unlikely things like
- DATE-OBS = "01/01/50". Set a flag indicating if MJD-OBS and DATE-OBS
- can be defaulted. */
- defdate = astEQUAL( ep_utc, eq );
-
-/* Convert the equinox to a Julian or Besselian epoch. Also get the
- reference frame and standard system. */
- if( !Ustrcmp( sys, "FK4", status ) ){
- eq = palEpb( eq );
- isys = RADEC;
- SetItemC( &(store->radesys), 0, 0, s, "FK4", status );
- } else if( !Ustrcmp( sys, "FK4_NO_E", status ) || !Ustrcmp( sys, "FK4-NO-E", status ) ){
- eq = palEpb( eq );
- isys = RADEC;
- SetItemC( &(store->radesys), 0, 0, s, "FK4-NO-E", status );
- } else if( !Ustrcmp( sys, "FK5", status ) ){
- eq = palEpj( eq );
- isys = RADEC;
- SetItemC( &(store->radesys), 0, 0, s, "FK5", status );
- } else if( !Ustrcmp( sys, "ICRS", status ) ){
- eq = AST__BAD;
- isys = RADEC;
- SetItemC( &(store->radesys), 0, 0, s, "ICRS", status );
- } else if( !Ustrcmp( sys, "GAPPT", status ) ||
- !Ustrcmp( sys, "Apparent", status ) ||
- !Ustrcmp( sys, "Geocentric", status ) ){
- eq = AST__BAD;
- isys = RADEC;
- SetItemC( &(store->radesys), 0, 0, s, "GAPPT", status );
- } else if( !Ustrcmp( sys, "Helioecliptic", status ) ){
- eq = AST__BAD;
- isys = HECLIP;
- } else if( !Ustrcmp( sys, "Galactic", status ) ){
- eq = AST__BAD;
- isys = GALAC;
- } else if( !Ustrcmp( sys, "Supergalactic", status ) ){
- eq = AST__BAD;
- isys = SUPER;
- } else if( !Ustrcmp( sys, "AzEl", status ) ){
- eq = AST__BAD;
- isys = AZEL;
- } else {
- eq = AST__BAD;
- isys = NOCEL;
- }
-
-/* Store these values. Only store the date if it does not take its
- default value. */
- SetItem( &(store->equinox), 0, 0, s, eq, status );
- if( !defdate ) SetItem( &(store->mjdobs), 0, 0, ' ', ep, status );
-
-/* Only proceed if we have usable values */
- if( astOK ) {
-
-/* Get the indices of the latitude and longitude axes within the
- SkyFrame. */
- latax = astGetLatAxis( skyfrm );
- lonax = 1 - latax;
-
-/* The first 4 characters in CTYPE are determined by the celestial coordinate
- system and the second 4 by the projection type. If we are describing
- offset coordinates, then use "OFLN" and "OFLT. Otherwise use the
- standard FITS-WCS name of the system. */
- if( isoff > 0 ){
- strcpy( lontype, "OFLN" );
- strcpy( lattype, "OFLT" );
- } else if( isys == RADEC ){
- strcpy( lontype, "RA--" );
- strcpy( lattype, "DEC-" );
- } else if( isys == ECLIP ){
- strcpy( lontype, "ELON" );
- strcpy( lattype, "ELAT" );
- } else if( isys == HECLIP ){
- strcpy( lontype, "HLON" );
- strcpy( lattype, "HLAT" );
- } else if( isys == GALAC ){
- strcpy( lontype, "GLON" );
- strcpy( lattype, "GLAT" );
- } else if( isys == SUPER ){
- strcpy( lontype, "SLON" );
- strcpy( lattype, "SLAT" );
- } else if( isys == AZEL ){
- strcpy( lontype, "AZ--" );
- strcpy( lattype, "EL--" );
-
-/* For unknown systems, use the axis symbols within CTYPE if they conform
- to the requirement of FITS-WCS (i.e. "xxLN/xxLT" or "xLON/xLAT") or use
- "UNLN/UNLT" otherwise. */
- } else {
- latsym = astGetSymbol( skyfrm, latax );
- lonsym = astGetSymbol( skyfrm, lonax );
- if( astOK ) {
-
- ok = 0;
- if( strlen( latsym ) == 4 && strlen( lonsym ) == 4 ) {
- if( !strcmp( latsym + 2, "LT" ) &&
- !strcmp( lonsym + 2, "LN" ) &&
- !strncmp( latsym, lonsym, 2 ) ) {
- ok = 1;
- } else if( !strcmp( latsym + 1, "LAT" ) &&
- !strcmp( lonsym + 1, "LON" ) &&
- !strncmp( latsym, lonsym, 1 ) ) {
- ok = 1;
- }
- }
-
- if( !ok ) {
- latsym = "UNLT";
- lonsym = "UNLN";
- }
-
- strncpy( lontype, lonsym, 4 );
- for( i = strlen( lonsym ); i < 4; i++ ) {
- lontype[ i ] = '-';
- }
- strncpy( lattype, latsym, 4 );
- for( i = strlen( latsym ); i < 4; i++ ) {
- lattype[ i ] = '-';
- }
- }
- }
-
-/* Store the projection strings. */
- prj_name = ( wcstype == 0 ) ? "-TAB" : astWcsPrjName( wcsproj );
- if( astOK ) {
- strcpy( lontype + 4, prj_name );
- strcpy( lattype + 4, prj_name );
- }
-
-/* Store the total CTYPE strings */
- SetItemC( &(store->ctype), axlon, 0, s, lontype, status );
- SetItemC( &(store->ctype), axlat, 0, s, lattype, status );
-
-/* Store offset coord information. */
- if( isoff ) {
-
-/* If the description is for offset coords store suitable comments for
- the CTYPE keywords. */
- if( isoff > 0 ) {
- skyref = astGetC( skyfrm, "SkyRef" );
-
- sprintf( attr, "Symbol(%d)", axlon + 1 );
- sprintf( com, "%s offset from %s",astGetC( skyfrm, attr )+1, skyref );
- SetItemC( &(store->ctype_com), axlon, 0, s, com, status );
-
- sprintf( attr, "Symbol(%d)", axlat + 1 );
- sprintf( com, "%s offset from %s",astGetC( skyfrm, attr )+1, skyref );
- SetItemC( &(store->ctype_com), axlat, 0, s, com, status );
-
-/* If the description is for absolute coords store the SkyFrame attribute
- values in AST-specific keywords. */
- } else {
- sprintf( attr, "SkyRef(%d)", axlon + 1 );
- skyref_lon = astGetD( skyfrm, attr );
- sprintf( attr, "SkyRef(%d)", axlat + 1 );
- skyref_lat = astGetD( skyfrm, attr );
-
- sprintf( attr, "SkyRefP(%d)", axlon + 1 );
- skyrefp_lon = astGetD( skyfrm, attr );
- sprintf( attr, "SkyRefP(%d)", axlat + 1 );
- skyrefp_lat = astGetD( skyfrm, attr );
-
- skyrefis = (isoff < -2) ? "IGNORED" :
- ( (isoff < -1) ? "ORIGIN" : "POLE" );
-
- SetItemC( &(store->skyrefis), 0, 0, s, skyrefis, status );
- if( astTest( skyfrm, "SkyRef(1)" ) ) {
- SetItem( &(store->skyref), axlon, 0, s, skyref_lon, status );
- SetItem( &(store->skyref), axlat, 0, s, skyref_lat, status );
- }
- if( astTest( skyfrm, "SkyRefP(1)" ) ) {
- SetItem( &(store->skyrefp), axlon, 0, s, skyrefp_lon, status );
- SetItem( &(store->skyrefp), axlat, 0, s, skyrefp_lat, status );
- }
- }
- }
-
-/* If the Label attribute has been set for an axis, use it as the CTYPE
- comment and CNAME value. */
- if( astTestLabel( skyfrm, latax ) ) {
- label = (char *) astGetLabel( skyfrm, latax );
- SetItemC( &(store->ctype_com), axlat, 0, s, label, status );
- SetItemC( &(store->cname), axlat, 0, s, label, status );
- }
- if( astTestLabel( skyfrm, lonax ) ) {
- label = (char *) astGetLabel( skyfrm, lonax );
- SetItemC( &(store->ctype_com), axlon, 0, s, label, status );
- SetItemC( &(store->cname), axlon, 0, s, label, status );
- }
-
-/* Nullify any CUNITS strings for the longitude and latitude axes (they
- always take the default value of degrees). */
- SetItemC( &(store->cunit), axlat, 0, s, NULL, status );
- SetItemC( &(store->cunit), axlon, 0, s, NULL, status );
- }
-
-/* Store the Domain name as the WCSNAME keyword (if set). */
- if( astTestDomain( skyfrm ) ) {
- SetItemC( &(store->wcsname), 0, 0, s, (char *) astGetDomain( skyfrm ), status );
- }
-
-/* Store the observer's position if set (needed for definition of AzEl
- systems). */
- if( astTestObsLon( skyfrm ) && astTestObsLat( skyfrm ) && s == ' ' ) {
- geolon = astGetObsLon( skyfrm );
- geolat = astGetObsLat( skyfrm );
- h = astGetObsAlt( skyfrm );
- if( geolat != AST__BAD && geolon != AST__BAD && h != AST__BAD ) {
- eraGd2gc( 1, geolon, geolat, h, xyz );
- SetItem( &(store->obsgeox), 0, 0, ' ', xyz[0], status );
- SetItem( &(store->obsgeoy), 0, 0, ' ', xyz[1], status );
- SetItem( &(store->obsgeoz), 0, 0, ' ', xyz[2], status );
- }
- }
- if( !astOK ) ret = 0;
- return ret;
-}
-
-static char *SourceWrap( const char *(* source)( void ), int *status ) {
-/*
-* Name:
-* SourceWrap
-
-* Purpose:
-* Wrapper function to invoke a C FitsChan source function.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* char *SourceWrap( const char *, int *status(* source)( void ) )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function invokes the source function whose pointer is
-* supplied in order to read the next input line from an external
-* data store. It then returns a pointer to a dynamic string
-* containing a copy of the text that was read.
-
-* Parameters:
-* source
-* Pointer to a source function, with no parameters, that
-* returns a pointer to a const, null-terminated string
-* containing the text that it read. This is the form of FitsChan
-* source function employed by the C language interface to the
-* AST library.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to a dynamically allocated, null terminated string
-* containing a copy of the text that was read. This string must be
-* freed by the caller (using astFree) when no longer required.
-*
-* A NULL pointer will be returned if there is no more input text
-* to read.
-
-* Notes:
-* - A NULL pointer value will be returned if this function is
-* invoked with the global error status set or if it should fail
-* for any reason.
-*/
-
-/* Local Variables: */
- char *result; /* Pointer value to return */
- const char *line; /* Pointer to input line */
-
-/* Initialise. */
- result = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Invoke the source function to read the next input line and return a
- pointer to the resulting string. */
- line = ( *source )();
-
-/* If a string was obtained, make a dynamic copy of it and save the
- resulting pointer. */
- if ( line ) result = astString( line, (int) strlen( line ) );
-
-/* Return the result. */
- return result;
-}
-
-static AstMapping *SpectralAxes( AstFitsChan *this, AstFrameSet *fs,
- double *dim, int *wperm,
- char s, FitsStore *store, double *crvals,
- int *axis_done, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* SpectralAxes
-
-* Purpose:
-* Add values to a FitsStore describing spectral axes in a Frame.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* AstMapping *SpectralAxes( AstFitsChan *this, AstFrameSet *fs,
-* double *dim, int *wperm,
-* char s, FitsStore *store, double *crvals,
-* int *axis_done, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The current Frame of the supplied FrameSet is searched for spectral
-* axes. If any are found, FITS WCS keyword values describing the axis
-* are added to the supplied FitsStore, if possible (the conventions
-* of FITS-WCS paper III are used). Note, this function does not store
-* values for keywords which define the transformation from pixel
-* coords to Intermediate World Coords (CRPIX, PC and CDELT), but a
-* Mapping is returned which embodies these values. This Mapping is
-* from the current Frame in the FrameSet (WCS coords) to a Frame
-* representing IWC. The IWC Frame has the same number of axes as the
-* WCS Frame which may be greater than the number of base Frame (i.e.
-* pixel) axes.
-*
-* If a spectral axis is found, the RafRA and RefDec attributes of the
-* SpecFrame describing the axis are ignored: it is assumed that the
-* WCS Frame also contains a pair of celestial axes which will result
-* in appropriate celestial reference values being stored in the
-* FitsStore (this asumption should be enforced by calling function
-* MakeFitsFrameSet prior to calling this function).
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* fs
-* Pointer to the FrameSet. The base Frame should represent FITS pixel
-* coordinates, and the current Frame should represent FITS WCS
-* coordinates. The number of base Frame axes should not exceed the
-* number of current Frame axes. The spectral Unit in the returned
-* FrameSet will always be linearly related to the default Units for
-* the spectral System in use by the axis. If this requires a
-* change to the existing spectral Unit, the integrity of the
-* FrameSet will be maintained by suitable adjustments to the Mappings
-* within the FrameSet.
-* dim
-* An array holding the image dimensions in pixels. AST__BAD can be
-* supplied for any unknwon dimensions.
-* wperm
-* Pointer to an array of integers with one element for each axis of
-* the current Frame. Each element holds the zero-based
-* index of the FITS-WCS axis (i.e. one les than the value of "i" in
-* the keyword names "CTYPEi", "CRVALi", etc) which describes the
-* Frame axis.
-* s
-* The co-ordinate version character. A space means the primary
-* axis descriptions. Otherwise the supplied character should be
-* an upper case alphabetical character ('A' to 'Z').
-* store
-* The FitsStore in which to store the FITS WCS keyword values.
-* crvals
-* Pointer to an array holding the default CRVAL value for each
-* axis in the WCS Frame.
-* axis_done
-* An array of flags, one for each Frame axis, which indicate if a
-* description of the corresponding axis has yet been stored in the
-* FitsStore.
-* 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:
-* If a spectral axis was found which can be described using the
-* conventions of FITS-WCS paper III, then a Mapping from the current Frame
-* of the supplied FrameSet, to the IWC Frame is returned. Otherwise,
-* a UnitMap is returned. Note, the Mapping only defines the IWC
-* transformation for spectral axes. Any non-spectral axes are passed
-* unchanged by the returned Mapping.
-*/
-
-/* Local Variables: */
- AstFitsTable *table; /* Pointer to structure holding -TAB table info */
- AstFrame *pframe; /* Primary Frame containing current WCS axis*/
- AstFrame *tfrm1; /* A temporary Frame */
- AstFrame *tfrm; /* A temporary Frame */
- AstFrame *wcsfrm; /* WCS Frame within FrameSet */
- AstFrameSet *tfs; /* A temporary FrameSet */
- AstGrismMap *gmap; /* GrismMap defining the spectral axis */
- AstMapping *axmap; /* Mapping from WCS to IWC */
- AstMapping *map; /* Pixel -> WCS mapping */
- AstMapping *ret; /* Returned Mapping */
- AstMapping *tmap0; /* A temporary Mapping */
- AstMapping *tmap1; /* A temporary Mapping */
- AstMapping *tmap2; /* A temporary Mapping */
- AstMapping *tmap3; /* A temporary Mapping */
- AstMapping *tmap4; /* A temporary Mapping */
- AstMapping *tmap5; /* A temporary Mapping */
- AstMapping *tmap6; /* A temporary Mapping */
- AstPermMap *pm; /* PermMap pointer */
- AstSpecFrame *specfrm; /* The SpecFrame defining current WCS axis */
- char *cname; /* Pointer to CNAME value */
- char ctype[ MXCTYPELEN ]; /* The value for the FITS CTYPE keyword */
- char lin_unit[ 20 ]; /* Linear spectral Units being used */
- char orig_system[ 40 ]; /* Value of System attribute for current WCS axis */
- char system_attr[ 10 ]; /* Name of System attribute for current WCS axis */
- char unit_attr[ 10 ]; /* Name of Unit attribute for current WCS axis */
- const char *cval; /* Pointer to temporary character string */
- const char *x_sys[ 4 ]; /* Basic spectral systems */
- double *lbnd_p; /* Pointer to array of lower pixel bounds */
- double *ubnd_p; /* Pointer to array of upper pixel bounds */
- double crval; /* The value for the FITS CRVAL keyword */
- double dgbyds; /* Rate of change of grism parameter wrt "S" at ref. point */
- double dsbydx; /* Rate of change of "S" wrt "X" at ref. point */
- double geolat; /* Geodetic latitude of observer (radians) */
- double geolon; /* Geodetic longitude of observer (radians) */
- double gval; /* Value of grism parameter at reference point */
- double h; /* Geodetic altitude of observer (metres) */
- double imagfreq; /* Image sideband equivalent to the rest frequency (Hz) */
- double lbnd_s; /* Lower bound on spectral axis */
- double pv; /* Value of projection parameter */
- double restfreq; /* Rest frequency (Hz) */
- double ubnd_s; /* Upper bound on spectral axis */
- double vsource; /* Rel.vel. of source (m/s) */
- double xval; /* Value of "X" system at reference point */
- double xyz[3]; /* Geocentric position vector (in m) */
- double zsource; /* Redshift of source */
- int *inperm; /* Pointer to permutation array for input axes */
- int *outperm; /* Pointer to permutation array for output axes */
- int extver; /* Table version number for -TAB headers */
- int fits_i; /* FITS WCS axis index for current WCS axis */
- int iax; /* Axis index */
- int icolindex; /* Index of table column holding index vector */
- int icolmain; /* Index of table column holding main coord array */
- int interp; /* INterpolation method for look-up tables */
- int ix; /* System index */
- int j; /* Loop count */
- int npix; /* Number of pixel axes */
- int nwcs; /* Number of WCS axes */
- int paxis; /* Axis index within primary Frame */
- int sourcevrf; /* Rest Frame in which SourceVel is accesed */
-
-/* Initialise */
- ret = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* Every supported spectral system is linearly related to one of the
- following four systems. */
- x_sys[ 0 ] = "FREQ";
- x_sys[ 1 ] = "WAVE";
- x_sys[ 2 ] = "AWAV";
- x_sys[ 3 ] = "VELO";
-
-/* Get a pointer to the WCS Frame. */
- wcsfrm = astGetFrame( fs, AST__CURRENT );
-
-/* Store the number of pixel and WCS axes. */
- npix = astGetNin( fs );
- nwcs = astGetNout( fs );
-
-/* Store the upper and lower pixel bounds. */
- lbnd_p = astMalloc( sizeof( double )*(size_t) npix );
- ubnd_p = astMalloc( sizeof( double )*(size_t) npix );
- if( astOK ) {
- for( iax = 0; iax < npix; iax++ ) {
- lbnd_p[ iax ] = 1.0;
- ubnd_p[ iax ] = ( dim[ iax ] != AST__BAD ) ? dim[ iax ] : 500;
- }
- }
-
-/* Check each axis in the WCS Frame to see if it is a spectral axis. */
- axmap = NULL;
- for( iax = 0; iax < nwcs; iax++ ) {
-
-/* Obtain a pointer to the primary Frame containing the current WCS axis. */
- astPrimaryFrame( wcsfrm, iax, &pframe, &paxis );
-
-/* If the current axis belongs to a SpecFrame, we have found a spectral
- axis. */
- if( astIsASpecFrame( pframe ) ) {
- specfrm = (AstSpecFrame *) pframe;
-
-/* Note the (zero-based) FITS WCS axis index to be used for the current
- Frame axis. */
- fits_i = wperm[ iax ];
-
-/* Note the name and original value of the System attribute for the spectral
- axis within the FrameSet current Frame. */
- sprintf( system_attr, "System(%d)", iax + 1 );
- cval = astGetC( wcsfrm, system_attr );
- if( cval ) strcpy( orig_system, cval );
-
-/* Note the name of the Unit attribute for the spectral axis within the
- FrameSet current Frame. */
- sprintf( unit_attr, "Unit(%d)", iax + 1 );
-
-/* Get a pointer to the Mapping from FITS pixel coordinates to SpecFrame. */
- map = astGetMapping( fs, AST__BASE, AST__CURRENT );
-
-/* Find the bounds of the Spectral axis over the volume of the pixel grid. */
- astMapBox( map, lbnd_p, ubnd_p, 1, iax, &lbnd_s, &ubnd_s,
- NULL, NULL );
-
-/* The Unit attribute of a SpecFrame can be set to arbitrary non-linear
- functions of standard linear spectral units. FITS-WCS paper III requires
- CRVAL etc to be given in linear units. So first we ensure that we have a
- SpecFrame with linear Units. Create a copy of the SpecFrame and clear
- its Unit attribute (this ensures the copy has the default linear units).
- Then find a Mapping from the original spectral units to the default
- linear units. If the conversion is possible, see if the Mapping
- between the units is linear. If it is, then the original Unit attribute
- of the SpecFrame is OK (i.e. the units are linear). If not, clear
- the Unit attribute of the spectral axis in the FrameSet so that it
- uses the default linear units (retaining the original value so that it
- can be re-instated later). Using the clear method on the FrameSet
- pointer rather than the SpecFrame pointer causes the SpecFrame to be
- re-mapped within the FrameSet to maintain its correct relationship with
- the other Frames in the FrameSet. Also update the pixel->spectrum
- Mapping to take account of the change in units and re-calculate the new
- bounds on the spectral axis. Also update any supplied CRVAL value for
- the spectral axis. */
- tfrm = astCopy( specfrm );
- astClearUnit( tfrm, 0 );
- tfs = astConvert( specfrm, tfrm, "" );
- tfrm = astAnnul( tfrm );
- if( tfs ) {
- crval = crvals ? crvals[ iax ] : AST__BAD;
- tmap1 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
- tfs = astAnnul( tfs );
- if( !IsMapLinear( tmap1, &lbnd_s, &ubnd_s, 0, status ) ) {
- astClear( fs, unit_attr );
- (void) astAnnul( map );
- map = astGetMapping( fs, AST__BASE, AST__CURRENT );
- astMapBox( map, lbnd_p, ubnd_p, 1, iax, &lbnd_s, &ubnd_s,
- NULL, NULL );
- astTran1( tmap1, 1, &crval, 1, &crval );
- }
- tmap1 = astAnnul( tmap1 );
-
-/* Note the linear spectral Unit currently in use. */
- cval = astGetUnit( specfrm, 0 );
- if( cval ) strcpy( lin_unit, cval );
-
-/* For some of the algorithms, the reference value CRVAL is arbitrary.
- For these algorithms we choose to use the supplied default CRVAL value.
- If no default CRVAL value was suppllied, we use the mid spectral value
- if the size of the spectral axis was given, or the lower bound (i.e.
- pixel 1) if the size of the spectral axis was not given. */
- if( crval == AST__BAD ) {
- if( dim[ iax ] != AST__BAD ) {
- crval = 0.5*( lbnd_s + ubnd_s );
- } else {
- crval = lbnd_s;
- }
- }
-
-/* Modify this crval value so that it correpsonds to an integer pixel
- coordinate. */
- crval = NearestPix( map, crval, iax, status );
-
-/* We now check to see if the Mapping from pixel coords -> linear spectral
- coords corresponds to one of the algorithms supported in FITS-WCS paper
- III. First check for the "linear" algorithm in which the linear spectral
- coordinate given by the SpecFrame is related linearly to the pixel
- coords. */
- ctype[ 0 ] = 0;
- if( IsMapLinear( map, lbnd_p, ubnd_p, iax, status ) ) {
-
-/* The CTYPE value is just the spectral system. */
- strcpy( ctype, orig_system );
-
-/* Create the Mapping which defines the spectral IWC axis. This is
- initially the Mapping from WCS to IWCS - it subtracts the CRVAL value
- from the spectral WCS value to get the spectral IWC value (other
- non-spectral axes are left unchanged by this Mapping). This results
- in the spectral IWC axis having the same axis index as the spectral
- WCS axis. */
- crval = -crval;
- tmap0 = (AstMapping *) astShiftMap( 1, &crval, "", status );
- crval = -crval;
- axmap = AddUnitMaps( tmap0, iax, nwcs, status );
- tmap0 = astAnnul( tmap0 );
- }
-
-/* If the "linear" algorithm above is inappropriate, see if the "non-linear"
- algorithm defined in FITS-WCS paper III can be used, in which pixel
- coords are linearly related to some spectral system (called "X") other
- than the one represented by the supplied SpecFrame (called "S"). */
- if( !ctype[ 0 ] ) {
-
-/* Loop round each of the 4 allowed X systems. All other spectral systems
- are linearly related to one of these 4 systems and so do not need to be
- tested. */
- for( ix = 0; ix < 4 && !ctype[ 0 ]; ix++ ) {
-
-/* Set the system of the spectral WCS axis to the new trial X system. Clear
- the Unit attribute to ensure we are using the default linear units.
- Using the FrameSet pointer "fs" ensures that the Mappings within the
- FrameSet are modified to maintain the correct inter-Frame relationships. */
- astSetC( fs, system_attr, x_sys[ ix ] );
- astClear( fs, unit_attr );
-
-/* Now we check to see if the current X system is linearly related to
- pixel coordinates. */
- tmap3 = astGetMapping( fs, AST__BASE, AST__CURRENT );
- if( IsMapLinear( tmap3, lbnd_p, ubnd_p, iax, status ) ) {
-
-/* CTYPE: First 4 characters specify the "S" system. */
- strcpy( ctype, orig_system );
-
-/* The non-linear algorithm code to be appended to the "S" system is of the
- form "-X2P" ("P" is the system which is linearly related to "S"). */
- if( !strcmp( x_sys[ ix ], "FREQ" ) ) {
- strcpy( ctype + 4, "-F2" );
- } else if( !strcmp( x_sys[ ix ], "WAVE" ) ) {
- strcpy( ctype + 4, "-W2" );
- } else if( !strcmp( x_sys[ ix ], "AWAV" ) ) {
- strcpy( ctype + 4, "-A2" );
- } else {
- strcpy( ctype + 4, "-V2" );
- }
- if( !strcmp( orig_system, "FREQ" ) ||
- !strcmp( orig_system, "ENER" ) ||
- !strcmp( orig_system, "WAVN" ) ||
- !strcmp( orig_system, "VRAD" ) ) {
- strcpy( ctype + 7, "F" );
- } else if( !strcmp( orig_system, "WAVE" ) ||
- !strcmp( orig_system, "VOPT" ) ||
- !strcmp( orig_system, "ZOPT" ) ) {
- strcpy( ctype + 7, "W" );
- } else if( !strcmp( orig_system, "AWAV" ) ) {
- strcpy( ctype + 7, "A" );
- } else {
- strcpy( ctype + 7, "V" );
- }
-
-/* Create a Mapping which gives S as a function of X. */
- tfrm = astCopy( specfrm );
- astSetC( tfrm, "System(1)", orig_system );
- astSetC( tfrm, "Unit(1)", lin_unit );
- tfs = astConvert( specfrm, tfrm, "" );
- tmap5 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
- tfs = astAnnul( tfs );
- tfrm = astAnnul( tfrm );
-
-/* Use the inverse of this Mapping to get the X value at the reference S
- value. */
- astTran1( tmap5, 1, &crval, 0, &xval );
-
-/* Also use it to get the rate of change of S with respect to X at the
- reference point. */
- dsbydx = astRate( tmap5, &xval, 0, 0 );
-
-/* Create the Mapping which defines the spectral IWC axis. This is the
- Mapping from WCS to IWC - it first converts from S to X, then subtracts
- the X reference value value, and then scales the axis to ensure that
- the rate of change of S with respect to IWC is unity (as required by
- FITS-WCS paper III). Other non-spectral axes are left unchanged by
- the Mapping. The spectral IWC axis has the same axis index as the
- spectral WCS axis. */
- xval = -xval;
- tmap2 = (AstMapping *) astShiftMap( 1, &xval, "", status );
- astInvert( tmap5 );
- tmap0 = (AstMapping *) astCmpMap( tmap5, tmap2, 1, "", status );
- tmap5 = astAnnul( tmap5 );
- tmap2 = astAnnul( tmap2 );
- tmap2 = (AstMapping *) astZoomMap( 1, dsbydx, "", status );
- tmap1 = (AstMapping *) astCmpMap( tmap0, tmap2, 1, "", status );
- tmap0 = astAnnul( tmap0 );
- tmap2 = astAnnul( tmap2 );
- axmap = AddUnitMaps( tmap1, iax, nwcs, status );
- tmap1 = astAnnul( tmap1 );
- }
- tmap3 = astAnnul( tmap3 );
-
-/* Re-instate the original system and unit attributes for the spectral axis. */
- astSetC( fs, system_attr, orig_system );
- astSetC( fs, unit_attr, lin_unit );
- }
- }
-
-/* If the "non-linear" algorithm above is inappropriate, see if the
- "log-linear" algorithm defined in FITS-WCS paper III can be used, in
- which the spectral axis is logarithmically spaced in the spectral
- system given by the SpecFrame. */
- if( !ctype[ 0 ] ) {
-
-/* If the "log-linear" algorithm is appropriate, the supplied SpecFrame (s)
- is related to pixel coordinate (p) by s = Sr.EXP( a*p - b ). If this
- is the case, then the log of s will be linearly related to pixel
- coordinates. Test this. If the test is passed a Mapping is returned from
- WCS to IWC. */
- axmap = LogAxis( map, iax, nwcs, lbnd_p, ubnd_p, crval, status );
-
-/* If the axis is logarithmic... */
- if( axmap ) {
-
-/* CTYPE: First 4 characters specify the "S" system. */
- strcpy( ctype, orig_system );
-
-/* The rest is "-LOG". */
- strcpy( ctype + 4, "-LOG" );
- }
- }
-
-/* If the "log-linear" algorithm above is inappropriate, see if the "grism"
- algorithm defined in FITS-WCS paper III can be used, in which pixel
- coords are related to wavelength using a grism dispersion function,
- implemented in AST by a GrismMap. GrismMaps produce either vacuum
- wavelength or air wavelength as output. Temporarily set the SpecFrame
- to these two systems in turn before we do the check for a GrismMap. */
- for( ix = 0; ix < 2 && !ctype[ 0 ]; ix++ ) {
- astSetC( fs, system_attr, ( ix == 0 ) ? "WAVE" : "AWAV" );
- astSetC( fs, unit_attr, "m" );
-
-/* Get the simplified Mapping from pixel to wavelength. If the Mapping is
- a CmpMap containing a GrismMap, and if the output of the GrismMap is
- scaled by a neighbouring ZoomMap (e.g. into different wavelength units),
- then the GrismMap will be modified to incorporate the effect of the
- ZoomMap, and the ZoomMap will be removed. */
- tmap2 = astGetMapping( fs, AST__BASE, AST__CURRENT );
- tmap1 = astSimplify( tmap2 );
- tmap2 = astAnnul( tmap2 );
-
-/* Analyse this Mapping to see if the iax'th output is created diretcly by a
- GrismMap (i.e. the output of theGrismMap must not subsequently be
- modified by some other Mapping). If so, ExtractGrismMap returns a pointer
- to the GrismMap as its function value, and also returns "tmap2" as a copy
- of tmap1 in which the GrismMap has been replaced by a UnitMap. */
- gmap = ExtractGrismMap( tmap1, iax, &tmap2, status );
- if( gmap ) {
-
-/* The Mapping without the GrismMap must be linear on the spectral axis. */
- if( IsMapLinear( tmap2, lbnd_p, ubnd_p, iax, status ) ) {
-
-/* Get the reference wavelength (in "m") stored in the GrismMap. */
- crval = astGetGrismWaveR( gmap );
-
-/* Save a copy of the current Wavelength (in "m") SpecFrame. */
- tfrm1 = astCopy( specfrm );
-
-/* Re-instate the original System and Unit attributes for the SpecFrame. */
- astSetC( fs, system_attr, orig_system );
- astSetC( fs, unit_attr, lin_unit );
-
-/* Find the Mapping from the original "S" system to wavelength (in "m"). */
- tfs = astConvert( specfrm, tfrm1, "" );
- tfrm1 = astAnnul( tfrm1 );
- if( tfs ) {
- tmap3 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
- tfs = astAnnul( tfs );
-
-/* Use the inverse of this Mapping to convert the reference value from
- wavelength to the "S" system. */
- astTran1( tmap3, 1, &crval, 0, &crval );
-
-/* Concatenate the "S"->wavelength Mapping with the inverse GrismMap (from
- wavelength to grism parameter), to get the "S" -> "grism parameter"
- Mapping. */
- astInvert( gmap );
- tmap4 = (AstMapping *) astCmpMap( tmap3, gmap, 1, "", status );
- tmap3 = astAnnul( tmap3 );
-
-/* Use this Mapping to find the grism parameter at the reference point. */
- astTran1( tmap4, 1, &crval, 1, &gval );
-
-/* Also use it to find the rate of change of grism parameter with respect
- to "S" at the reference point. */
- dgbyds = astRate( tmap4, &crval, 0, 0 );
-
-/* FITS-WCS paper III required ds/dw to be unity at the reference point.
- Therefore the rate of change of grism parameter with respect to IWC ("w")
- is equal to the rate of change of grism parameter with respect to "S"
- (at the reference point). The mapping from "w" to grism parameter is a
- ZoomMap which scales "w" by "dgbyds" followed by a ShiftMap which adds
- on "gval". */
- tmap5 = (AstMapping *) astZoomMap( 1, dgbyds, "", status );
- tmap6 = (AstMapping *) astShiftMap( 1, &gval, "", status );
- tmap3 = (AstMapping *) astCmpMap( tmap5, tmap6, 1, "", status );
- tmap5 = astAnnul( tmap5 );
- tmap6 = astAnnul( tmap6 );
-
-/* Create the Mapping which defines the spectral IWC axis. This is the
- Mapping from WCS "S" to IWCS "w", formed by combining the Mapping from
- "S" to grism parameter (tmap4), with the Mapping from grism parameter to
- "w" (inverse of tmap3). Other non-spectral axes are left unchanged by the
- Mapping. The spectral IWC axis has the same axis index as the spectral
- WCS axis. */
- astInvert( tmap3 );
- tmap5 = (AstMapping *) astCmpMap( tmap4, tmap3, 1, "", status );
- tmap3 = astAnnul( tmap3 );
- tmap4 = astAnnul( tmap4 );
- axmap = AddUnitMaps( tmap5, iax, nwcs, status );
- tmap5 = astAnnul( tmap5 );
-
-/* CTYPE: First 4 characters specify the "S" system. */
- strcpy( ctype, orig_system );
-
-/* Last 4 characters are "-GRA" or "-GRI". */
- strcpy( ctype + 4, ( ix == 0 ) ? "-GRI" : "-GRA" );
-
-/* Store values for the projection parameters in the FitsStore. Ignore
- parameters which are set to the default values defined in FITS-WCS
- paper III. */
- pv = astGetGrismG( gmap );
- if( pv != 0 ) SetItem( &(store->pv), fits_i, 0, s, pv, status );
- pv = (double) astGetGrismM( gmap );
- if( pv != 0 ) SetItem( &(store->pv), fits_i, 1, s, pv, status );
- pv = astGetGrismAlpha( gmap );
- if( pv != 0 ) SetItem( &(store->pv), fits_i, 2, s, pv*AST__DR2D, status );
- pv = astGetGrismNR( gmap );
- if( pv != 1.0 ) SetItem( &(store->pv), fits_i, 3, s, pv, status );
- pv = astGetGrismNRP( gmap );
- if( pv != 0 ) SetItem( &(store->pv), fits_i, 4, s, pv, status );
- pv = astGetGrismEps( gmap );
- if( pv != 0 ) SetItem( &(store->pv), fits_i, 5, s, pv*AST__DR2D, status );
- pv = astGetGrismTheta( gmap );
- if( pv != 0 ) SetItem( &(store->pv), fits_i, 6, s, pv*AST__DR2D, status );
- }
- }
-
-/* Release resources. */
- tmap2 = astAnnul( tmap2 );
- gmap = astAnnul( gmap );
- }
-
-/* Release resources. */
- tmap1 = astAnnul( tmap1 );
-
-/* Re-instate the original System and Unit attributes for the SpecFrame. */
- astSetC( fs, system_attr, orig_system );
- astSetC( fs, unit_attr, lin_unit );
- }
-
-/* If none of the above algorithms are appropriate, we must resort to
- using the -TAB algorithm, in which the Mapping is defined by a look-up
- table. Check the TabOK attribute to see -TAB is to be supported. */
- extver = astGetTabOK( this );
- if( !ctype[ 0 ] && extver > 0 ) {
-
-/* Get any pre-existing FitsTable from the FitsStore. This is the table
- in which the tabular data will be stored (if the Mapping can be expressed
- in -TAB form). */
- if( !astMapGet0A( store->tables, AST_TABEXTNAME, &table ) ) table = NULL;
-
-/* See if the Mapping can be expressed in -TAB form. */
- tmap0 = IsMapTab1D( map, 1.0, NULL, wcsfrm, dim, iax, fits_i, &table,
- &icolmain, &icolindex, &interp, status );
- if( tmap0 ) {
-
-/* CTYPE: First 4 characters specify the "S" system. Last 4 characters are
- "-TAB". */
- strcpy( ctype, orig_system );
- strcpy( ctype + 4, "-TAB" );
-
-/* The values stored in the table index vector are GRID coords. So we
- need to ensure that IWC are equivalent to GRID coords. So set CRVAL
- to zero. First store the original CRVAL value (which gives the
- observation centre) in AXREF. */
- SetItem( &(store->axref), fits_i, 0, s, crval, status );
- crval = 0.0;
-
-/* Store TAB-specific values in the FitsStore. First the name of the
- FITS binary table extension holding the coordinate info. */
- SetItemC( &(store->ps), fits_i, 0, s, AST_TABEXTNAME, status );
-
-/* Next the table version number. This is the set (positive) value for the
- TabOK attribute. */
- SetItem( &(store->pv), fits_i, 1, s, extver, status );
-
-/* Also store the table version in the binary table header. */
- astSetFitsI( table->header, "EXTVER", extver,
- "Table version number", 0 );
-
-/* Next the name of the table column containing the main coords array. */
- SetItemC( &(store->ps), fits_i, 1, s,
- astColumnName( table, icolmain ), status );
-
-/* Next the name of the column containing the index array */
- if( icolindex >= 0 ) SetItemC( &(store->ps), fits_i, 2, s,
- astColumnName( table, icolindex ), status );
-
-/* The interpolation method (an AST extension to the published -TAB
- algorithm, communicated through the QVi_4a keyword). */
- SetItem( &(store->pv), fits_i, 4, s, interp, status );
-
-/* Also store the FitsTable itself in the FitsStore. */
- astMapPut0A( store->tables, AST_TABEXTNAME, table, NULL );
-
-/* Create the WCS -> IWC Mapping (AST uses grid coords as IWC coords for
- the -TAB algorithm). First, get a Mapping that combines the TAB axis
- Mapping( tmap0) in parallel with one or two UnitMaps in order to put
- the TAB axis at the required index. */
- tmap1 = AddUnitMaps( tmap0, iax, nwcs, status );
-
-/* Now get a PermMap that permutes the WCS axes into the FITS axis order. */
- inperm = astMalloc( sizeof( double )*nwcs );
- outperm = astMalloc( sizeof( double )*nwcs );
- if( astOK ) {
- for( j = 0; j < nwcs; j++ ) {
- inperm[ j ] = wperm[ j ];
- outperm[ wperm[ j ] ] = j;
- }
- }
- pm = astPermMap( nwcs, inperm, nwcs, outperm, NULL, "",
- status );
-
-/* Combine these two Mappings in series, to get the Mapping from WCS to
- IWC. */
- axmap = (AstMapping *) astCmpMap( pm, tmap1, 1, " ",
- status );
-
-/* Free resources. */
- inperm = astFree( inperm );
- outperm = astFree( outperm );
- pm = astAnnul( pm );
- tmap0 = astAnnul( tmap0 );
- tmap1 = astAnnul( tmap1 );
- }
- if( table ) table = astAnnul( table );
- }
-
-/* If this axis is a usable spectral axis... */
- if( ctype[ 0 ] ) {
-
-/* Add the Mapping for this axis in series with any existing result Mapping. */
- if( ret ) {
- tmap0 = (AstMapping *) astCmpMap( ret, axmap, 1, "", status );
- (void) astAnnul( ret );
- ret = tmap0;
- } else {
- ret = astClone( axmap );
- }
- axmap = astAnnul( axmap );
-
-/* Store values for CTYPE, CRVAL and CUNIT in the FitsStore. */
- SetItemC( &(store->ctype), fits_i, 0, s, ctype, status );
- SetItem( &(store->crval), fits_i, 0, s, crval, status );
- SetItemC( &(store->cunit), fits_i, 0, s, lin_unit, status );
-
-/* If the axis label has been set, use it as the CTYPE comment and CNAME
- value. */
- if( astTestLabel( specfrm, 0 ) ) {
- cname = (char *) astGetLabel( specfrm, 0 );
- SetItemC( &(store->ctype_com), fits_i, 0, s, cname, status );
- SetItemC( &(store->cname), fits_i, 0, s, cname, status );
- }
-
-/* Store values for the other FITS-WCS keywords which describe the
- spectral system. Only store values which have been explicitly set in
- the SpecFrame, which are different to the default values defined by
- FITS-WCS paper III (if any), and which are not bad. */
- if( astTestObsLon( specfrm ) && astTestObsLat( specfrm ) &&
- s == ' ' ) {
- geolon = astGetObsLon( specfrm );
- geolat = astGetObsLat( specfrm );
- h = astGetObsAlt( specfrm );
- if( geolat != AST__BAD && geolon != AST__BAD && h != AST__BAD ) {
- eraGd2gc( 1, geolon, geolat, h, xyz );
- SetItem( &(store->obsgeox), 0, 0, ' ', xyz[0], status );
- SetItem( &(store->obsgeoy), 0, 0, ' ', xyz[1], status );
- SetItem( &(store->obsgeoz), 0, 0, ' ', xyz[2], status );
- }
- }
- if( astTestRestFreq( specfrm ) ) {
- restfreq = astGetRestFreq( specfrm );
- if( restfreq != AST__BAD ) {
- if( !strcmp( orig_system, "WAVE" ) ||
- !strcmp( orig_system, "VOPT" ) ||
- !strcmp( orig_system, "ZOPT" ) ||
- !strcmp( orig_system, "AWAV" ) ) {
- SetItem( &(store->restwav), 0, 0, s, AST__C/restfreq, status );
- } else {
- SetItem( &(store->restfrq), 0, 0, s, restfreq, status );
- }
- }
- if( astIsADSBSpecFrame( specfrm ) ) {
- imagfreq = astGetImagFreq( (AstDSBSpecFrame *) specfrm );
- if( imagfreq != AST__BAD ) {
- SetItem( &(store->imagfreq), 0, 0, s, imagfreq, status );
- }
- }
- }
- cval = GetFitsSor( astGetC( specfrm, "StdOfRest" ), status );
- if( cval ) SetItemC( &(store->specsys), 0, 0, s, cval, status );
- if( astTestSourceVel( specfrm ) ) {
- vsource = astGetSourceVel( specfrm );
- if( vsource != AST__BAD && fabs( vsource ) < AST__C ) {
- zsource = sqrt( (AST__C + vsource)/
- (AST__C - vsource) ) - 1.0;
- SetItem( &(store->zsource), 0, 0, s, zsource, status );
- cval = GetFitsSor( astGetC( specfrm, "SourceVRF" ), status );
- if( cval ) SetItemC( &(store->ssyssrc), 0, 0, s, cval, status );
- }
- } else {
- vsource = AST__BAD;
- }
-
-/* Store the VELOSYS value (not strictly needed since it can be
- determined from the other values, but FITS-WCS paper III says it can be
- useful). We temporarily change the source velocity to be zero m/s
- in the main rest frame (StdOfRest) (unless the main rest frame is
- already the source rest frame). We then change the source rest
- frame to topocentric and get the source velocity (i.e. the velocity of
- the main rest Frame) in the topocentric system. We then re-instate the
- original attribute values if they were set. */
- if( astGetStdOfRest( specfrm ) != AST__SCSOR ) {
- sourcevrf = astGetSourceVRF( specfrm );
- astSetSourceVRF( specfrm, astGetStdOfRest( specfrm ) );
- astSetSourceVel( specfrm, 0.0 );
- } else {
- vsource = AST__BAD;
- sourcevrf = AST__NOSOR;
- }
- astSetSourceVRF( specfrm, AST__TPSOR );
- SetItem( &(store->velosys), 0, 0, s,
- astGetSourceVel( specfrm ), status );
- if( vsource != AST__BAD ){
- astSetSourceVRF( specfrm, sourcevrf );
- astSetSourceVel( specfrm, vsource );
- }
-
-/* Indicate that this axis has been described. */
- axis_done[ iax ] = 1;
- }
-
-/* Release resources. */
- map = astAnnul( map );
- }
- }
- pframe = astAnnul( pframe );
- }
-
-/* Release resources. */
- lbnd_p = astFree( lbnd_p );
- ubnd_p = astFree( ubnd_p );
- wcsfrm = astAnnul( wcsfrm );
-
-/* If we have a Mapping to return, simplify it. Otherwise, create
- a UnitMap to return. */
- if( ret ) {
- tmap0 = ret;
- ret = astSimplify( tmap0 );
- tmap0 = astAnnul( tmap0 );
- } else {
- ret = (AstMapping *) astUnitMap( nwcs, "", status );
- }
-
-/* Return the result. */
- return ret;
-}
-
-static AstFitsChan *SpecTrans( AstFitsChan *this, int encoding,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* SpecTrans
-
-* Purpose:
-* Translated non-standard WCS FITS headers into equivalent standard
-* ones.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstFitsChan *SpecTrans( AstFitsChan *this, int encoding,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function checks the supplied FitsChan for selected
-* non-standard WCS keywords and, if found, stores equivalent
-* standard keywords in a newly created FitsChan which is returned as
-* the function value. All the original keywords are marked
-* as having been used, so that they are not written out when the
-* FitsChan is deleted.
-*
-
-* At the moment, the non-standard keywords checked for are:
-*
-* 1) RADECSYS is renamed as RADESYS
-*
-* 2) LONGPOLE is renamed as LONPOLE
-*
-* 3) CDjjjiii and CDj_i are converted to PCi_j (with unit CDELT)
-*
-* 4) CROTAj are converted to PCi_j
-*
-* 5) PROJPi are converted to PV<axlat>_i
-*
-* 6) CmVALi are converted to CRVALis (s=A,B,,, for m=1,2...). This
-* is also done for CmPIXi, CmYPEi, and CmNITi. CmELTi is converted
-* to a CDj_is array.
-*
-* 7) EQUINOX keywords with string values equal to a date preceded
-* by the letter B or J (eg "B1995.0"). These are converted to the
-* corresponding Julian floating point value without any epoch
-* specifier.
-*
-* 8) EPOCH values are converted into Julian EQUINOX values (but only
-* if the FitsChan does not already contain an EQUINOX value).
-*
-* 9) DATE-OBS values are converted into MJD-OBS values (but only
-* if the FitsChan does not already contain an MJD-OBS value).
-*
-* 10) EQUINOX or EPOCH keywords with value zero are converted to
-* B1950.
-*
-* 11) The AIPS NCP and GLS projections are converted into equivalent SIN
-* or SFL projections.
-*
-* 12) The IRAF "ZPX" projection. If the last 4 chacaters of CTYPEi
-
-* (i = 1, naxis) are "-ZPX", then:
-* - "ZPX" is replaced by "ZPN" within the CTYPEi value
-* - A distortion code of "-ZPX" is appended to the end of the CTYPEi
-* value (this is used later by the DistortMaps function).
-* - If the FitsChan contains no PROJP keywords, then projection
-* parameter valus are read from any WATi_nnn keywords, and
-* corresponding PV keywords are added to the FitsChan.
-*
-* 13) The IRAF "TNX" projection. If the last 4 chacaters of CTYPEi
-
-* (i = 1, naxis) are "-TNX", then:
-* - "TNX" is replaced by "TAN" within the CTYPEi value (the distorted
-* TAN projection included in a pre-final version of FITS-WCS is still
-* supported by AST using the WcsMap AST__TPN projection).
-* - If the FitsChan contains no PROJP keywords, then projection
-* parameter valus are read from any WATi_nnn keywords, and
-* corresponding PV keywords are added to the FitsChan.
-* - If the TNX projection cannot be converted exactly into a TAN
-* projection, ASTWARN keywords are added to the FitsChan
-* containing a warning message. The calling application can (if it
-* wants to) check for this keyword, and report its contents to the
-* user.
-*
-* 14) Keywords relating to the IRAF "mini-WCS" system are removed.
-* This is the IRAF equivalent of the AST native encoding. Mini-WCS
-* keywords are removed in order to avoid confusion arising between
-* potentially inconsistent encodings.
-*
-* 15) "QV" parameters for TAN projections (as produced by AUTOASTROM)
-* or "-TAB" (as produced by FitsChan) are renamed to "PV".
-*
-* 16) RESTFREQ is converted to RESTFRQ.
-*
-* 17) the "-WAV", "-FRQ" and "-VEL" CTYPE algorithms included in an
-* early draft of FITS-WCS paper III are translated to the
-* corresponding modern "-X2P" form.
-*
-* 18) AIPS spectral CTYPE values are translated to FITS-WCS paper III
-* equivalents.
-*
-* 19) AIPS spectral keywords OBSRA and OBSDEC are used to create a
-* pair of celestial axes with reference point at the specified
-* (OBSRA,OBSDEC) position. This is only done if the header does not
-* already contain a pair of celestial axes.
-*
-* 20) Common case insensitive CUNIT values: "Hz", "Angstrom", "km/s",
-* "M/S"
-*
-* 21) Various translations specific to the FITS-CLASS encoding.
-*
-* 22) SAO distorted TAN projections (uses COi_j keywords to store
-* polynomial coefficients) are converted to TPN projections.
-
-* 23) CTYPE == "LAMBDA" changed to CTYPE = "WAVE"
-*
-* 24) if the projection is TAN and the PolyTan attribute is non-zero,
-* or if the projection is TPV (produced by SCAMP), the projection is
-* changed to TPN (the AST code for the draft FITS-WCS paper II
-* conventions for a distorted TAN projection).
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* encoding
-* The FitsChan encoding in use.
-* method
-* Pointer to string holding name of calling method.
-* class
-* Pointer to a string holding the name of the supplied object class.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the new FitsChan containing the keywords which
-* constitute the standard equivalents to any non-standard keywords in
-* the supplied FitsChan. A NULL pointer is returned if there are no
-* non-standard keywords in the supplied FitsChan.
-*/
-
-/* Local Variables: */
- AstFitsChan *ret; /* The returned FitsChan */
- char *assys; /* AIPS standad of rest type */
- char *astype; /* AIPS spectral type */
- char *comm; /* Pointer to comment string */
- char *cval; /* Pointer to character string */
- char *start; /* Pointer to start of projp term */
- char *watmem; /* Pointer to total WAT string */
- char bj; /* Besselian/Julian indicator */
- char format[ 50 ]; /* scanf format string */
- char keyname[ FITSNAMLEN + 5 ];/* General keyword name + formats */
- char lattype[MXCTYPELEN]; /* CTYPE value for latitude axis */
- char lontype[MXCTYPELEN]; /* CTYPE value for longitude axis */
- char prj[6]; /* Spatial projection string */
- char s; /* Co-ordinate version character */
- char spectype[MXCTYPELEN]; /* CTYPE value for spectral axis */
- char sprj[6]; /* Spectral projection string */
- char ss; /* Co-ordinate version character */
- char template[ FITSNAMLEN + 1 ];/* General keyword name template */
- double *cvals; /* PVi_m values for TPN projection */
- double cdelti; /* CDELT for longitude axis */
- double cdeltj; /* CDELT for latitude axis */
- double cosrota; /* Cos( CROTA ) */
- double crota; /* CROTA Value */
- double dval; /* General floating value */
- double lambda; /* Ratio of CDELTs */
- double projp; /* Projection parameter value */
- double rowsum2; /* Sum of squared CDi_j row elements */
- double sinrota; /* Sin( CROTA ) */
- double sinval; /* Sin( dec ref ) */
- int *mvals; /* "m" index of each PVi_m value */
- int axlat; /* Index of latitude axis */
- int axlon; /* Index of longitude axis */
- int diag; /* Sign of diagonal CDi_j element */
- int dim; /* Length of pixel axis */
- int gotpcij; /* Does FitsChan contain any PCi_j keywords? */
- int i,j; /* Indices */
- int iaxis; /* Axis index */
- int icoeff; /* Index of next PVi_m value */
- int iproj; /* Projection parameter index */
- int jhi; /* Highest axis index */
- int jlo; /* Lowest axis index */
- int lbnd[ 2 ]; /* Lower index bounds */
- int m; /* Co-ordinate version index */
- int naxis; /* Number of axes */
- int nc; /* Length of string */
- int ncoeff; /* Number of PVi_m values */
- int ok; /* Can projection be represented in FITS-WCS?*/
- int shifted; /* Non-zero if there is an origin shift */
- int tlbnd[ 2 ]; /* Lower index bounds */
- int tubnd[ 2 ]; /* Upper index bounds */
- int ubnd[ 2 ]; /* Upper index bounds */
- int use_projp; /* Use PROJP keywors in favour of PV keywords? */
- size_t size; /* Length of string value */
-
-/* Check the global error status. */
- if ( !astOK ) return NULL;
-
-/* Initialise to avoid compiler warnings. */
- size = 0;
- prj[ 0 ] = 0;
-
-/* Create the returned FitsChan. */
- ret = astFitsChan( NULL, NULL, "", status );
-
-/* Loop round all axis descriptions, starting with primary (' '). */
- for( s = 'A' - 1; s <= 'Z' && astOK; s++ ){
- if( s == 'A' - 1 ) s = ' ';
-
-/* Find the number of axes by finding the highest axis number in any
- CRPIXi keyword name. Pass on if there are no axes for this axis
- description. */
- if( s != ' ' ) {
- sprintf( template, "CRPIX%%d%c", s );
- } else {
- strcpy( template, "CRPIX%d" );
- }
- if( !astKeyFields( this, template, 1, &naxis, lbnd ) ) {
- if( s == ' ' ) s = 'A' - 1;
- continue;
- }
-
-/* Find the longitude and latitude axes by examining the CTYPE values.
- They are marked as read. Such markings are only provisional, and they
- can be read again any number of times until the current astRead
- operation is completed. Also note the projection type. */
- j = 0;
- axlon = -1;
- axlat = -1;
- while( j < naxis && astOK ){
- if( GetValue2( ret, this, FormatKey( "CTYPE", j + 1, -1, s, status ),
- AST__STRING, (void *) &cval, 0, method,
- class, status ) ){
- nc = strlen( cval );
- if( !strncmp( cval, "RA--", 4 ) ||
- !strncmp( cval, "AZ--", 4 ) ||
- ( nc > 1 && !strncmp( cval + 1, "LON", 3 ) ) ||
- ( nc > 2 && !strncmp( cval + 2, "LN", 2 ) ) ) {
- axlon = j;
- strncpy( prj, cval + 4, 4 );
- strncpy( lontype, cval, 10 );
- prj[ 4 ] = 0;
- } else if( !strncmp( cval, "DEC-", 4 ) ||
- !strncmp( cval, "EL--", 4 ) ||
- ( nc > 1 && !strncmp( cval + 1, "LAT", 3 ) ) ||
- ( nc > 2 && !strncmp( cval + 2, "LT", 2 ) ) ) {
- axlat = j;
- strncpy( prj, cval + 4, 4 );
- strncpy( lattype, cval, 10 );
- prj[ 4 ] = 0;
-
-/* Check for spectral algorithms from early drafts of paper III */
- } else {
- sprj[ 0 ] = '-';
- if( ( nc > 4 && !strncmp( cval + 4, "-WAV", 4 ) ) ) {
- sprj[ 1 ] = 'W';
- } else if( ( nc > 4 && !strncmp( cval + 4, "-FRQ", 4 ) ) ) {
- sprj[ 1 ] = 'F';
- } else if( ( nc > 4 && !strncmp( cval + 4, "-VEL", 4 ) ) ) {
- sprj[ 1 ] = 'V';
- } else {
- sprj[ 0 ] = 0;
- }
- if( *sprj ) {
- sprj[ 2 ] = '2';
- if( !strncmp( cval, "WAVE", 4 ) ) {
- sprj[ 3 ] = 'W';
- } else if( !strncmp( cval, "FREQ", 4 ) ) {
- sprj[ 3 ] = 'F';
- } else if( !strncmp( cval, "VELO", 4 ) ) {
- sprj[ 3 ] = 'V';
- } else if( !strncmp( cval, "VRAD", 4 ) ) {
- sprj[ 3 ] = 'F';
- } else if( !strncmp( cval, "VOPT", 4 ) ) {
- sprj[ 3 ] = 'W';
- } else if( !strncmp( cval, "ZOPT", 4 ) ) {
- sprj[ 3 ] = 'W';
- } else if( !strncmp( cval, "ENER", 4 ) ) {
- sprj[ 3 ] = 'F';
- } else if( !strncmp( cval, "WAVN", 4 ) ) {
- sprj[ 3 ] = 'F';
- } else if( !strncmp( cval, "BETA", 4 ) ) {
- sprj[ 3 ] = 'V';
- } else {
- sprj[ 0 ] = 0;
- }
- }
- if( *sprj ) {
- strcpy( spectype, cval );
- if( sprj[ 1 ] == sprj[ 3 ] ) {
- strcpy( sprj, strlen( cval ) > 8 ? "----" : " " );
- } else {
- sprj[ 4 ] = 0;
- }
- strncpy( spectype + 4, sprj, 4 );
- cval = spectype;
- SetValue( ret, FormatKey( "CTYPE", j + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- }
- }
- j++;
- } else {
- break;
- }
- }
-
-/* RADECSYS keywords
- ----------------- */
- if( s == ' ' ) {
- if( GetValue2( ret, this, "RADECSYS", AST__STRING, (void *) &cval, 0, method,
- class, status ) ){
- if( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ){
- SetValue( ret, "RADESYS", (void *) &cval, AST__STRING,
- CardComm( this, status ), status );
- }
- }
-
-/* LONGPOLE keywords
- ----------------- */
- if( GetValue2( ret, this, "LONGPOLE", AST__FLOAT, (void *) &dval, 0, method,
- class, status ) ){
- if( encoding == FITSPC_ENCODING || encoding == FITSIRAF_ENCODING ){
- SetValue( ret, "LONPOLE", (void *) &dval, AST__FLOAT,
- CardComm( this, status ), status );
- }
- }
- }
-
-/* Zero CDELT values.
- ----------------- */
-
-/* Check there are some CDELT keywords... */
- if( s != ' ' ) {
- sprintf( template, "CDELT%%d%c", s );
- } else {
- strcpy( template, "CDELT%d" );
- }
- if( astKeyFields( this, template, 0, NULL, NULL ) ){
-
-/* Do each row in the matrix. */
- for( j = 0; j < naxis; j++ ){
-
-/* Get the CDELT value for this row. */
- GetValue2( ret, this, FormatKey( "CDELT", j + 1, -1, s, status ), AST__FLOAT,
- (void *) &cdeltj, 0, method, class, status );
-
-/* If CDELT is zero, use 1.0E-6 of the corresponding CRVAL value
- instead, or 1.0 if CRVAL is zero. Otherwise, the zeros could cause the
- matrix to be non-invertable. The Mapping could then not be simplified
- or used by a Plot. CDELT values of zero are usually used to indicate
- "redundant" axes. For instance, a 2D image may be stored as a 3D cube
- with a single plane with the "redundant" 3rd axis used to specify the
- wavelength of the filter. The actual value used for CDELT shouldn't
- matter since the axis only spans a single pixel anyway. */
- if( cdeltj == 0.0 ){
- GetValue2( ret, this, FormatKey( "CDELT", j + 1, -1, s, status ), AST__FLOAT,
- (void *) &dval, 1, method, class, status );
- cdeltj = 1.0E-6*dval;
- if( cdeltj == 0.0 ) cdeltj = 1.0;
- SetValue( ret, FormatKey( "CDELT", j + 1, -1, s, status ), (void *) &cdeltj,
- AST__FLOAT, NULL, status );
- }
- }
- }
-
-/* Following conversions produce PCi_j keywords. Only do them if there
- are currently no PCi_j keywords in the header. */
- if( s != ' ' ) {
- sprintf( template, "PC%%d_%%d%c", s );
- } else {
- strcpy( template, "PC%d_%d" );
- }
- gotpcij = astKeyFields( this, template, 0, NULL, NULL );
- if( !gotpcij ){
-
-/* CDjjjiii
- -------- */
- if( s == ' ' && astKeyFields( this, "CD%3d%3d", 0, NULL, NULL ) ){
-
-/* Do each row in the matrix. */
- for( j = 0; j < naxis; j++ ){
-
-/* Do each column in the matrix. */
- for( i = 0; i < naxis; i++ ){
-
-/* Get the CDjjjiii matrix element */
- sprintf( keyname, "CD%.3d%.3d", j + 1, i + 1 );
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0,
- method, class, status ) ){
-
-/* If found, save it with name PCj_i, and ensure the default value of 1.0
- is used for CDELT. */
- if( encoding == FITSIRAF_ENCODING ){
- SetValue( ret, FormatKey( "PC", j + 1, i + 1, ' ', status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- dval = 1.0;
- SetValue( ret, FormatKey( "CDELT", j + 1, -1, s, status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- gotpcij = 1;
- }
- }
- }
- }
- }
-
-/* CDj_i
- ---- */
- if( s != ' ' ) {
- sprintf( template, "CD%%d_%%d%c", s );
- } else {
- strcpy( template, "CD%d_%d" );
- }
- if( !gotpcij && astKeyFields( this, template, 0, NULL, NULL ) ){
-
-/* Do each row in the matrix. */
- for( j = 0; j < naxis; j++ ){
-
-/* First find the sum of the squared elements in the row. and note the
- sign of the diagonal element. */
- rowsum2 = 0.0;
- diag = +1;
- for( i = 0; i < naxis; i++ ){
- if( GetValue2( ret, this, FormatKey( "CD", j + 1, i + 1, s, status ),
- AST__FLOAT, (void *) &dval, 0, method, class, status ) ){
- rowsum2 += dval*dval;
- if( i == j ) diag = ( dval >= 0.0 ) ? +1 : -1;
- }
- }
-
-/* The CDELT value for this row will be the length of the row vector. This means that
- each row will be a unit vector when converted to PCi_j form, and the CDELT will
- give a real indication of the pixel size. Ensure that the diagonal
- PCi+j element has a positive sign. */
- cdelti = sqrt( rowsum2 )*diag;
- SetValue( ret, FormatKey( "CDELT", j + 1, -1, s, status ),
- (void *) &cdelti, AST__FLOAT, NULL, status );
-
-/* Do each column in the matrix. */
- for( i = 0; i < naxis; i++ ){
-
-/* Get the CDj_i matrix element (note default value for all CD elements
- is zero (even diagonal elements!). */
- if( !GetValue2( ret, this, FormatKey( "CD", j + 1, i + 1, s, status ),
- AST__FLOAT, (void *) &dval, 0, method, class, status ) ){
- dval = 0.0;
- }
-
-/* Divide by the rows cdelt value and save it with name PCj_i. */
- if( cdelti != 0.0 ) dval /= cdelti;
- SetValue( ret, FormatKey( "PC", j + 1, i + 1, s, status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- gotpcij = 1;
- }
- }
- }
-
-/* PCjjjiii and CROTAi keywords
- ---------------------------- */
-
-/* Check there are some CDELT keywords... */
- if( s != ' ' ) {
- sprintf( template, "CDELT%%d%c", s );
- } else {
- strcpy( template, "CDELT%d" );
- }
- if( !gotpcij && astKeyFields( this, template, 0, NULL, NULL ) ){
-
-/* See if there is a CROTA keyword. Try to read values for both axes
- since they are sometimes both included. This ensures they will not be
- included in the output when the FitsChan is deleted. Read the latitude
- axis second in order to give it priority in cases where both are
- present. */
- crota = AST__BAD;
- GetValue2( ret, this, FormatKey( "CROTA", axlon + 1, -1, s, status ),
- AST__FLOAT, (void *) &crota, 0, method, class, status );
- GetValue2( ret, this, FormatKey( "CROTA", axlat + 1, -1, s, status ),
- AST__FLOAT, (void *) &crota, 0, method, class, status );
-
-/* If there are any PCjjjiii keywords, rename them as PCj_i. */
- if( s == ' ' && astKeyFields( this, "PC%3d%3d", 0, NULL, NULL ) ){
-
-/* Do each row in the matrix. */
- for( j = 0; j < naxis; j++ ){
-
-/* Do each column in the matrix. */
- for( i = 0; i < naxis; i++ ){
-
-/* Get the PCiiijjj matrix element */
- sprintf( keyname, "PC%.3d%.3d", j + 1, i + 1 );
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0,
- method, class, status ) ){
- } else if( i == j ) {
- dval = 1.0;
- } else {
- dval = 0.0;
- }
-
-/* Store it as PCi_j */
- SetValue( ret, FormatKey( "PC", j + 1, i + 1, ' ', status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- gotpcij = 1;
- }
- }
-
-/* If there is a CROTA value and no PCjjjii keywords, create a PCj_i
- matrix from the CROTA values. We need to have latitude and longitude
- axes for this. */
- } else if( s == ' ' && axlat != -1 && axlon != -1 && crota != AST__BAD ){
-
-/* Get the sin and cos of CROTA */
- cosrota = cos( crota*AST__DD2R );
- sinrota = sin( crota*AST__DD2R );
-
-/* Get the CDELT values for the longitude and latitude axes. */
- if( GetValue2( ret, this, FormatKey( "CDELT", axlat + 1, -1, ' ', status ),
- AST__FLOAT, (void *) &cdeltj, 1, method,
- class, status ) &&
- GetValue2( ret, this, FormatKey( "CDELT", axlon + 1, -1, ' ', status ),
- AST__FLOAT, (void *) &cdelti, 1, method,
- class, status ) ){
-
-/* Save the ratio, needed below. */
- lambda = cdeltj/cdelti;
-
-/* Save a corresponding set of PCi_j keywords in the FitsChan. First do
- the diagonal terms. */
- for( i = 0; i < naxis; i++ ){
- if( i == axlat ) {
- dval = cosrota;
- } else if( i == axlon ) {
- dval = cosrota;
- } else {
- dval = 1.0;
- }
- SetValue( ret, FormatKey( "PC", i + 1, i + 1, ' ', status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- gotpcij = 1;
- }
-
-/* Now do the non-zero off-diagonal terms. */
- dval = sinrota/lambda;
- SetValue( ret, FormatKey( "PC", axlat + 1, axlon + 1, ' ', status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- dval = -sinrota*lambda;
- SetValue( ret, FormatKey( "PC", axlon + 1, axlat + 1, ' ', status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- }
- }
- }
- }
-
-/* Conversion of old PROJP, etc, is done once on the "primary" pass. */
- if( s == ' ' ) {
-
-/* PROJP keywords
- -------------- */
- if( astKeyFields( this, "PROJP%d", 1, ubnd, lbnd ) && axlat != -1 ) {
-
-/* Some people produce headers with both PROJP and PV. Even worse, the
- PROJP and PV values are sometimes inconsistent. In this case we trust
- the PV values rather than the PROJP values, but only if the PV values
- are not obviously incorrect for some reason. In particularly, we check
- that, *if* either PVi_1 or PVi_2 (where i=longitude axis) is present,
- then PVi_0 is also present. Conversely we check that if PVi_0 is
- present then at least one of PVi_1 or PVi_2 is present. */
- use_projp = 1;
- if( axlat != -1 &&
- astKeyFields( this, "PV%d_%d", 2, tubnd, tlbnd ) ){
- use_projp = 0;
-
-/* Are there any PV values for the longitude axis? */
- if( tlbnd[ 0 ] <= axlon + 1 && axlon + 1 <= tubnd[ 0 ] ) {
-
-/* Are either PVi_1 or PVi_2 available? */
- if( HasCard( this, FormatKey( "PV", axlon + 1, 1, ' ', status ),
- method, class, status ) ||
- HasCard( this, FormatKey( "PV", axlon + 1, 2, ' ', status ),
- method, class, status ) ) {
-
-/* If so use PROJP if PVi_0 is not also available. */
- if( !HasCard( this, FormatKey( "PV", axlon + 1, 0, ' ', status ),
- method, class, status ) ) use_projp = 1;
-
-/* If neither PVi_1 or PVi_2 are available, use PROJP if PVi_0 is
- available. */
- } else if( HasCard( this, FormatKey( "PV", axlon + 1, 0, ' ', status ),
- method, class, status ) ) {
- use_projp = 1;
- }
- }
- }
-
-/* Translate PROJP to PV if required. */
- if( use_projp ) {
- for( i = lbnd[ 0 ]; i <= ubnd[ 0 ]; i++ ){
- if( GetValue2( ret, this, FormatKey( "PROJP", i, -1, ' ', status ),
- AST__FLOAT, (void *) &dval, 0, method, class, status ) &&
- ( encoding == FITSPC_ENCODING ||
- encoding == FITSIRAF_ENCODING ) ){
- SetValue( ret, FormatKey( "PV", axlat + 1, i, ' ', status ),
- (void *) &dval, AST__FLOAT, CardComm( this, status ), status );
- }
- }
- }
- }
-
-/* CmVALi keywords
- --------------- */
- if( astKeyFields( this, "C%1dVAL%d", 2, ubnd, lbnd ) ){
- ss = 'A';
- for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){
- for( i = lbnd[ 1 ]; i <= ubnd[ 1 ]; i++ ){
- sprintf( keyname, "C%dVAL%d", m, i );
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0,
- method, class, status ) &&
- ( encoding == FITSPC_ENCODING ||
- encoding == FITSIRAF_ENCODING ) ){
- sprintf( keyname, "CRVAL%d%c", i, ss );
- SetValue( ret, keyname, (void *) &dval, AST__FLOAT,
- CardComm( this, status ), status );
- }
- }
- ss++;
- }
- }
-
-/* CmPIXi keywords
- --------------- */
- if( astKeyFields( this, "C%1dPIX%d", 2, ubnd, lbnd ) ){
- ss = 'A';
- for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){
- for( i = lbnd[ 1 ]; i <= ubnd[ 1 ]; i++ ){
- sprintf( keyname, "C%dPIX%d", m, i );
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0,
- method, class, status ) &&
- ( encoding == FITSPC_ENCODING ||
- encoding == FITSIRAF_ENCODING ) ){
- sprintf( keyname, "CRPIX%d%c", i, ss );
- SetValue( ret, keyname, (void *) &dval, AST__FLOAT,
- CardComm( this, status ), status );
- }
- }
- ss++;
- }
- }
-
-/* CmYPEi keywords
- --------------- */
- if( astKeyFields( this, "C%1dYPE%d", 2, ubnd, lbnd ) ){
- ss = 'A';
- for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){
- for( i = lbnd[ 1 ]; i <= ubnd[ 1 ]; i++ ){
- sprintf( keyname, "C%dYPE%d", m, i );
- if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0,
- method, class, status ) &&
- ( encoding == FITSPC_ENCODING ||
- encoding == FITSIRAF_ENCODING ) ){
- sprintf( keyname, "CTYPE%d%c", i, ss );
- SetValue( ret, keyname, (void *) &cval, AST__STRING,
- CardComm( this, status ), status );
- }
- }
- ss++;
- }
- }
-
-/* CmNITi keywords
- --------------- */
- if( astKeyFields( this, "C%1dNIT%d", 2, ubnd, lbnd ) ){
- ss = 'A';
- for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){
- for( i = lbnd[ 1 ]; i <= ubnd[ 1 ]; i++ ){
- sprintf( keyname, "C%dNIT%d", m, i );
- if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0,
- method, class, status ) &&
- ( encoding == FITSPC_ENCODING ||
- encoding == FITSIRAF_ENCODING ) ){
- sprintf( keyname, "CUNIT%d%c", i, ss );
- SetValue( ret, keyname, (void *) &cval, AST__STRING,
- CardComm( this, status ), status );
- }
- }
- ss++;
- }
- }
-
-/* CmELTi keywords
- --------------- */
- if( astKeyFields( this, "C%1dELT%d", 2, ubnd, lbnd ) ){
- ss = 'A';
- for( m = lbnd[ 0 ]; m <= ubnd[ 0 ]; m++ ){
-
-/* Create a PCj_is matrix by copying the PCjjjiii values and rename CmELTi as
- CDELTis. */
-
-/* Do each row in the matrix. */
- for( j = 0; j < naxis; j++ ){
-
-/* Get the CDELT value for this row. Report an error if not present. */
- sprintf( keyname, "C%dELT%d", m, j + 1 );
- GetValue2( ret, this, keyname, AST__FLOAT, (void *) &cdeltj, 1,
- method, class, status );
-
-/* If CDELT is zero, use one hundredth of the corresponding CRVAL value
- instead, or 1.0 if CRVAL is zero. Otherwise, the zeros could cause the
- matrix to be non-invertable. The Mapping could then not be simplified
- or used by a Plot. CDELT values of zero are usually used to indicate
- "redundant" axes. For instance, a 2D image may be stored as a 3D cube
- with a single plane with the "redundant" 3rd axis used to specify the
- wavelength of the filter. The actual value used for CDELT shouldn't
- matter since the axis only spans a single pixel anyway. */
- if( cdeltj == 0.0 ){
- GetValue2( ret, this, FormatKey( "CRVAL", j + 1, -1, ss, status ), AST__FLOAT,
- (void *) &dval, 1, method, class, status );
- cdeltj = 0.01*dval;
- if( cdeltj == 0.0 ) cdeltj = 1.0;
- }
-
-/* Save it as CDELTis */
- sprintf( keyname, "CDELT%d%c", j + 1, ss );
- SetValue( ret, keyname, (void *) &cdeltj, AST__FLOAT,
- CardComm( this, status ), status );
-
-/* Do each column in the matrix. */
- for( i = 0; i < naxis; i++ ){
-
-/* Get the PCiiijjj matrix element */
- sprintf( keyname, "PC%.3d%.3d", j + 1, i + 1 );
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0,
- method, class, status ) ){
- } else if( i == j ) {
- dval = 1.0;
- } else {
- dval = 0.0;
- }
-
-/* Store it as PCi_js. */
- SetValue( ret, FormatKey( "PC", j + 1, i + 1, ss, status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- }
- }
- ss++;
- }
- }
-
-/* EPOCH keywords
- ------------ */
-
-/* Get any EPOCH card, marking it as read. */
- if( GetValue2( ret, this, "EPOCH", AST__FLOAT, (void *) &dval, 0, method,
- class, status ) ){
-
-/* Convert values of zero to B1950. */
- if( dval == 0.0 ) dval = 1950.0;
-
-/* Save a new EQUINOX card in the FitsChan, so long as there is not
- already one there. */
- if( !GetValue2( ret, this, "EQUINOX", AST__STRING, (void *) &cval, 0,
- method, class, status ) ){
- SetValue( ret, "EQUINOX", (void *) &dval, AST__FLOAT,
- "Reference equinox", status );
- }
- }
-
-/* String EQUINOX values
- ---------------------
- If found, EQUINOX will be used in favour of any EPOCH value found
- above. */
- if( GetValue2( ret, this, "EQUINOX", AST__STRING, (void *) &cval, 0, method,
- class, status ) ){
-
-/* Note the first character. */
- bj = cval[ 0 ];
-
-/* If it is "B" or "J", read a floating value from the rest */
- if( bj == 'B' || bj == 'J' ) {
- if( 1 == astSscanf( cval + 1, " %lf ", &dval ) ){
-
-/* If it is a Besselian epoch, convert to Julian. */
- if( bj == 'B' ) dval = palEpj( palEpb2d( dval ) );
-
-/* Replace the original EQUINOX card. */
- SetValue( ret, "EQUINOX", (void *) &dval, AST__FLOAT,
- CardComm( this, status ), status );
- }
- }
- }
-
-/* EQUINOX = 0.0 keywords
- ---------------------- */
- if( GetValue2( ret, this, "EQUINOX", AST__FLOAT, (void *) &dval, 0, method,
- class, status ) ){
- if( dval == 0.0 ){
- dval = 1950.0;
- SetValue( ret, "EQUINOX", (void *) &dval, AST__FLOAT,
- CardComm( this, status ), status );
- }
- }
- }
-
-/* DATE-OBS keywords
- ---------------- */
-
-/* Read any DATE-OBS card. This prevents it being written out when the
- FitsChan is deleted. */
- if( s == ' ' ) {
- strcpy( keyname, "DATE-OBS" );
- if( GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0, method,
- class, status ) ){
-
-/* Ignore DATE-OBS values if the header contains an MJD-OBS value */
- strcpy( keyname, "MJD-OBS" );
- if( !GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0,
- method, class, status ) ){
-
-/* Get the corresponding mjd-obs value, checking that DATE-OBS is valid. */
- dval = DateObs( cval, status );
- if( dval != AST__BAD ){
- SetValue( ret, keyname, (void *) &dval, AST__FLOAT,
- "Date of observation", status );
- }
- }
- }
- }
-
-/* Things specific to the CLASS encoding
- ------------------------------------- */
- if( encoding == FITSCLASS_ENCODING ) ClassTrans( this, ret, axlat,
- axlon, method, class, status );
-
-/* Convert SAO distorted TAN headers to TPN distorted TAN headers.
- -------------------------------------------------------------- */
- if( s == ' ' && !Ustrcmp( prj, "-TAN", status ) ){
-
-/* Translate the COi_m keywords into PV i+m keywords. */
- if( SAOTrans( this, ret, method, class, status ) ) {
-
-/* Change the CTYPE projection form TAN to TPV. */
- strcpy( prj, "-TPN" );
- strcpy( lontype + 4, "-TPN" );
- cval = lontype;
- SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- strcpy( lattype + 4, "-TPN" );
- cval = lattype;
- SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- }
- }
-
-/* AIPS "NCP" projections
- --------------------- */
-
-/* Compare the projection type with "-NCP" */
- if( !Ustrcmp( prj, "-NCP", status ) ) {
-
-/* Get the latitude reference value, and take is cot. */
- GetValue2( ret, this, FormatKey( "CRVAL", axlat + 1, -1, s, status ),
- AST__FLOAT, (void *) &dval, 1, method, class, status );
- sinval = sin( dval*AST__DD2R );
- if( sinval != 0.0 ) {
- dval = cos( dval*AST__DD2R )/sinval;
-
-/* Replace NCP with SIN in the CTYPE values. */
- strcpy( lontype + 4, "-SIN" );
- cval = lontype;
- SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- strcpy( lattype + 4, "-SIN" );
- cval = lattype;
- SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
-
-/* Store the new projection parameters using names suitable to FITS_WCS
- encoding. */
- SetValue( ret, FormatKey( "PV", axlat + 1, 2, s, status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- dval = 0.0;
- SetValue( ret, FormatKey( "PV", axlat + 1, 1, s, status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- }
- }
-
-/* CLASS "ATF" projections
- ---------------------- */
-
-/* Replace ATF with AIT in the CTYPE values. */
- if( !Ustrcmp( prj, "-ATF", status ) ) {
- strcpy( lontype + 4, "-AIT" );
- cval = lontype;
- SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- strcpy( lattype + 4, "-AIT" );
- cval = lattype;
- SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- }
-
-/* AIPS "GLS" projections
- --------------------- */
-
-/* Compare the projection type with "-GLS" */
- if( !Ustrcmp( prj, "-GLS", status ) ) {
-
-/* Convert to "-SFL" */
- strcpy( lontype + 4, "-SFL" );
- cval = lontype;
- SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- strcpy( lattype + 4, "-SFL" );
- cval = lattype;
- SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
-
-/* FITS-WCS paper 2 (sec. 6.1.4) describes how to handle AIPS GLS
- projections, but requires that the axes are not rotated. Instead, we
- modify the native latitude at the fiducial point, theta_0, as is done
- in wcslib function celfix in file wcsfix.c (see also FITS-WCS paper
- II sec. 2.5). We only need to change theta_0 if the CRVAL position is
- not the celestial origin. */
- shifted = 0;
- sprintf( keyname, "CRVAL%d", axlon + 1 );
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0,
- method, class, status ) ){
- if( dval != 0.0 ) shifted = 1;
- }
- sprintf( keyname, "CRVAL%d", axlat + 1 );
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0,
- method, class, status ) ){
- if( dval != 0.0 ) shifted = 1;
- }
-
- if( 0 && shifted ) {
- SetValue( ret, FormatKey( "PV", axlon + 1, 2, s, status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- dval = 0.0;
- SetValue( ret, FormatKey( "PV", axlon + 1, 1, s, status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- dval = 1.0;
- SetValue( ret, FormatKey( "PV", axlon + 1, 0, s, status ),
- (void *) &dval, AST__FLOAT, NULL, status );
- }
- }
-
-/* Rename any "QV" projection parameters to "PV" (such as used by
- -TAB to indicate the interpolation method, or by the internal
- -TPN projection to indicate distortion coefficients).
- ------------------------------------------------------------ */
-
-/* Rewind the FitsChan. */
- astClearCard( this );
-
-/* Search the FitsChan for QV cards. */
- if( s != ' ' ) {
- sprintf( template, "QV%%d_%%d%c", s );
- } else {
- strcpy( template, "QV%d_%d" );
- }
- while( FindKeyCard( this, template, method, class, status ) && astOK ) {
-
-/* If the projection name is "TAN", replace TAN with TPN in the CTYPE values. */
- if( !Ustrcmp( prj, "-TAN", status ) ){
- strcpy( prj, "-TPN" );
- strcpy( lontype + 4, "-TPN" );
- cval = lontype;
- SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- strcpy( lattype + 4, "-TPN" );
- cval = lattype;
- SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- }
-
-/* Indicate that the QV card has been consumed. */
- MarkCard( this, status );
-
-/* Get the keyword name and change it from QV to PV. */
- strcpy( keyname, CardName( this, status ) );
- keyname[ 0 ] ='P';
-
-/* Store the new PV card so long as there it is not already present in the
- FitsChan. */
- if( !GetValue2( ret, this, keyname, AST__FLOAT, (void *) &cval, 0,
- method, class, status ) ){
- SetValue( ret, keyname, CardData( this, &size, status ), AST__FLOAT,
- CardComm( this, status ), status );
- }
-
-/* Move on to the next card. */
- MoveCard( this, 1, method, class, status );
- }
-
-
-
-/* Change any TAN projection to TPN projection if the PolyTan attribute
- is non-zero. Also change any TPV projection to TPN projection.
- --------------------------------------------------- */
- if( ( !Ustrcmp( prj, "-TAN", status ) &&
- GetUsedPolyTan( this, ret, axlat + 1, axlon + 1, s, method, class, status ) ) ||
- !Ustrcmp( prj, "-TPV", status ) ){
- strcpy( prj, "-TPN" );
- strcpy( lontype + 4, "-TPN" );
- cval = lontype;
- SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- strcpy( lattype + 4, "-TPN" );
- cval = lattype;
- SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- }
-
-
-
-/* IRAF "ZPX" projections
- --------------------- */
- if( s == ' ' && !Ustrcmp( prj, "-ZPX", status ) ) {
-
-/* Replace "ZPX" with "ZPN-ZPX" (i.e. ZPN projection with ZPX distortion
- code) in the CTYPE values. */
- strcpy( lontype + 4, "-ZPN-ZPX" );
- cval = lontype;
- SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, ' ', status ),
- (void *) &cval, AST__STRING, NULL, status );
- strcpy( lattype + 4, "-ZPN-ZPX" );
- cval = lattype;
- SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, ' ', status ),
- (void *) &cval, AST__STRING, NULL, status );
-
-/* Check latitude then longitude axes */
- for( i = 0; i < 2; i++ ){
- iaxis = i ? axlat : axlon;
-
-/* Concatenate all the IRAF "WAT" keywords together for this axis. These
- keywords are marked as having been used, so that they are not written
- out when the FitsChan is deleted. */
- watmem = ConcatWAT( this, iaxis, method, class, status );
-
-/* Search the total WAT string for any projp terms. */
- if( watmem ){
- for( iproj = 0; iproj < 10 && astOK; iproj++ ) {
- sprintf( format, "projp%d=", iproj );
- start = strstr( watmem, format );
- if( start ) {
- sprintf( format, "projp%d=%%lf", iproj );
- if( astSscanf( start, format, &projp ) ){
- SetValue( ret, FormatKey( "PV", axlat + 1, iproj, ' ', status ),
- (void *) &projp, AST__FLOAT,
- "ZPN projection parameter", status );
- }
- }
- }
-
-/* Release the memory used to hold the concatenated WAT keywords. */
- watmem = (char *) astFree( (void *) watmem );
- }
- }
-
-/* IRAF "TNX" projections
- --------------------- */
- } else if( s == ' ' && !Ustrcmp( prj, "-TNX", status ) ) {
-
-/* Replace TNX with TPN in the CTYPE values. */
- strcpy( lontype + 4, "-TPN" );
- cval = lontype;
- SetValue( ret, FormatKey( "CTYPE", axlon + 1, -1, ' ', status ),
- (void *) &cval, AST__STRING, NULL, status );
- strcpy( lattype + 4, "-TPN" );
- cval = lattype;
- SetValue( ret, FormatKey( "CTYPE", axlat + 1, -1, ' ', status ),
- (void *) &cval, AST__STRING, NULL, status );
-
-/* Check latitude then longitude axes */
- for( i = 0; i < 2; i++ ){
- iaxis = i ? axlat : axlon;
-
-/* Concatenate all the IRAF "WAT" keywords together for this axis. These
- keywords are marked as having been used, so that they are not written
- out when the FitsChan is deleted. */
- watmem = ConcatWAT( this, iaxis, method, class, status );
-
-/* Extract the polynomial coefficients from the concatenated WAT string.
- These are returned in the form of a list of PVi_m values for a TPN
- projection. */
- ncoeff = WATCoeffs( watmem, i, &cvals, &mvals, &ok, status );
-
-/* If we can handle the TNX projection, store the PV values in the FitsChan. */
- if( ok ) {
- for( icoeff = 0; icoeff < ncoeff; icoeff++ ) {
- SetValue( ret, FormatKey( "PV", iaxis + 1, mvals[ icoeff ],
- ' ', status ),
- (void *) (cvals + icoeff), AST__FLOAT,
- "TAN projection parameter", status );
- }
-
-/* If the TNX cannot be represented in FITS-WCS (within our restrictions), add
- warning keywords to the FitsChan. */
- } else {
- Warn( this, "tnx", "This FITS header includes, or was "
- "derived from, a TNX projection which requires "
- "unsupported IRAF-specific corrections. The WCS "
- "information may therefore be incorrect.", method, class, status );
- }
-
-/* Release the memory used to hold the concatenated WAT keywords. */
- watmem = (char *) astFree( (void *) watmem );
- }
- }
-
-/* MSX CAR projections.
- ------------------- */
- if( !Ustrcmp( prj, "-CAR", status ) && !astGetCarLin( this ) ) {
-
-/* The CAR projection has valid projection plane points only for native
- longitudes in the range [-180,+180]. The reference pixel (CRPIX) is at
- native longitude zero. We need to check that the reference point is not
- so far outside the image that the entire image lies outside the range
- [-180,+180]. If it is, we modify the CRPIX value by the number of
- pixels corresponding to 360 degres of longitude in order to bring the
- array into the valid domain ([-180,+180]) of the projection. */
- if( GetValue2( ret, this, FormatKey( "CDELT", axlon + 1, -1, s, status ),
- AST__FLOAT, (void *) &cdelti, 1, method, class, status ) &&
- GetValue2( ret, this, FormatKey( "CRPIX", axlon + 1, -1, s, status ),
- AST__FLOAT, (void *) &dval, 0, method, class, status ) ) {
-
-/* We check if the mid point of the array is in the valiud longitude range. Use the
- bottom left corner as a fallback if the image size is unknown. */
- if( !GetValue( this, FormatKey( "NAXIS", axlon + 1, -1, ' ', status ),
- AST__INT, &dim, 0, 0, method, class, status ) ) {
- dim = 0;
- }
-
- if( cdelti != 0.0 ) {
- double offset = 0.5*( dim + 1 );
- dval = offset + AST__DR2D*palDrange( AST__DD2R*( dval - offset )*cdelti )/cdelti;
- SetValue( ret, FormatKey( "CRPIX", axlon + 1, -1, s, status ),
- (void *) &dval, AST__FLOAT, CardComm( this, status ), status );
- }
- }
- }
-
-/* Replace RESTFREQ by RESTFRQ.
- ---------------------------- */
-
-/* Get any RESTFREQ card, marking it as read. */
- if( s != ' ' ) {
- sprintf( keyname, "RESTFREQ%c", s );
- } else {
- strcpy( keyname, "RESTFREQ" );
- }
- if( GetValue2( ret, this, keyname, AST__FLOAT, (void *) &dval, 0, method,
- class, status ) ){
-
-/* Look for "MHz" and "GHz" within the comment. If found scale the value
- into Hz. */
- comm = CardComm( this, status );
- if( comm ) {
- if( strstr( comm, "GHz" ) ) {
- dval *= 1.0E9;
- comm = "[Hz] Rest Frequency";
- } else if( strstr( comm, "MHz" ) ) {
- dval *= 1.0E6;
- comm = "[Hz] Rest Frequency";
- }
- }
-
-/* Save a new RESTFRQ card in the FitsChan, so long as there is not
- already one there. */
- if( s != ' ' ) {
- sprintf( keyname, "RESTFRQ%c", s );
- } else {
- strcpy( keyname, "RESTFRQ" );
- }
- if( !GetValue2( ret, this, keyname, AST__STRING, (void *) &cval, 0,
- method, class, status ) ){
- SetValue( ret, keyname, (void *) &dval, AST__FLOAT, comm, status );
- }
- }
-
-/* Translate AIPS spectral CTYPE values to FITS-WCS paper III equivalents.
- These are of the form AAAA-BBB, where "AAAA" can be "FREQ", "VELO" (=VRAD!)
- or "FELO" (=VOPT-F2W), and BBB can be "LSR", "LSD", "HEL" (=*Bary*centric!)
- or "GEO". Also convert "LAMBDA" to "WAVE". */
- for( j = 0; j < naxis; j++ ) {
- if( GetValue2( ret, this, FormatKey( "CTYPE", j + 1, -1, s, status ),
- AST__STRING, (void *) &cval, 0, method,
- class, status ) ){
- if( IsAIPSSpectral( cval, &astype, &assys, status ) ) {
- SetValue( ret, FormatKey( "CTYPE", j + 1, -1, s, status ),
- (void *) &astype, AST__STRING, NULL, status );
- SetValue( ret, "SPECSYS", (void *) &assys, AST__STRING, NULL, status );
- break;
- } else if( !strcmp( cval, "LAMBDA " ) ) {
- cval = "WAVE";
- SetValue( ret, FormatKey( "CTYPE", j + 1, -1, s, status ),
- (void *) &cval, AST__STRING, NULL, status );
- break;
- }
- }
- }
-
-/* Common case insensitive CUNIT values: "Hz", "Angstrom", "km/s", "M/S" */
- if( s != ' ' ) {
- sprintf( template, "CUNIT%%d%c", s );
- } else {
- strcpy( template, "CUNIT%d" );
- }
- if( astKeyFields( this, template, 1, &jhi, &jlo ) ){
-
-/* Convert keyword indices from 1-based to 0-base, and loop round them all. */
- jhi--;
- jlo--;
- for( j = jlo; j <= jhi; j++ ){
- char *keynam;
- keynam = FormatKey( "CUNIT", j + 1, -1, s, status );
- if( GetValue2( ret, this, keynam, AST__STRING, (void *) &cval, 0,
- method, class, status ) ){
- size_t nc = astChrLen( cval );
- if( nc == 0 ) {
- cval = NULL;
- } else if( !Ustrcmp( cval, "Hz", status ) ) {
- cval = "Hz";
- } else if( !Ustrcmp( cval, "Angstrom", status ) ) {
- cval = "Angstrom";
- } else if( !Ustrcmp( cval, "km/s", status ) ) {
- cval = "km/s";
- } else if( !Ustrcmp( cval, "m/s", status ) ) {
- cval = "m/s";
- } else {
- cval = NULL;
- }
- if( cval ) SetValue( ret, keynam, (void *) &cval, AST__STRING, NULL, status );
- }
- }
- }
-
-/* After doing the primary axis descriptions, prepare to do the "A"
- description. */
- if( s == ' ' ) s = 'A' - 1;
- }
-
-/* IRAF mini-WCS keywords
- ---------------------- */
-
-/* Rewind the FitsChan to search from the first card. */
- astClearCard( this );
-
-/* Search forward through until all cards have been checked. */
- while( !astFitsEof( this ) && astOK ){
-
-/* Check to see if the keyword name from the current card matches
- any of the known mini-WCS keywords. If so, mark the card as read. */
- if( Match( CardName( this, status ), "WAT%d_%d", 0, NULL, &m, method, class, status ) ||
- Match( CardName( this, status ), "LTM%d_%d", 0, NULL, &m, method, class, status ) ||
- Match( CardName( this, status ), "LTV%d", 0, NULL, &m, method, class, status ) ||
- Match( CardName( this, status ), "WSV%d_LEN", 0, NULL, &m, method, class, status ) ||
- Match( CardName( this, status ), "WSV%d_%d", 0, NULL, &m, method, class, status ) ){
- MarkCard( this, status );
- }
-
-/* Now move the current card on to the next card. */
- MoveCard( this, 1, method, class, status );
- }
-
-/* Delete the returned FitsChan if it is empty. */
- if( ret && !astGetNcard( ret ) ) ret = (AstFitsChan *) astDelete( ret );
-
-/* Return. */
- return ret;
-}
-
-int Split( AstFitsChan *this, const char *card, char **name, char **value,
- char **comment, const char *method, const char *class, int *status ){
-/*
-* Name:
-* Split
-
-* Purpose:
-* Extract the keyword name, value and comment from a FITS header card.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int Split( AstFitsChan *this, const char *card, char **name, char **value,
-* char **comment, const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* The name, value and comment (if present) are extracted from the
-* supplied card text and returned.
-
-* Parameters:
-* this
-* Pointer to the FitsCHan.
-* card
-* Pointer to a string holding the FITS header card.
-* name
-* Pointer to a location at which to return the pointer to a string
-* holding the keyword name.
-* value
-* Pointer to a location at which to return the pointer to a string
-* holding the keyword value.
-* comment
-* Pointer to a location at which to return the pointer to a string
-* holding the keyword comment.
-* 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:
-* - An integer identifying the data type of the keyword value. This
-* will be one of the values AST__UNDEF, AST__COMMENT, AST__INT,
-* AST__STRING, AST__CONTINUE, AST__FLOAT, AST__COMPLEXI or AST__COMPLEXF
-* defined in fitschan.h.
-
-* Notes:
-* - If the keyword value is a string, then the returned value does not
-* include the delimiting quotes, and pairs of adjacent quotes within the
-* string are replaced by single quotes.
-* - A maximum of 80 characters are read from the supplied card, so the
-* string does not need to be null terminated unless less than 80
-* characters are to be read.
-* - The memory holding the three strings "name", "value" and "comment"
-* should be released when no longer needed using astFree.
-* - NULL pointers and a data type of AST__COMMENT are returned if an
-* error has already occurred, or if this function fails for any reason.
-*/
-
-/* Local Variables: */
- char *c; /* Pointer to returned comment string */
- char *dd; /* Pointer to intermediate character */
- char *slash; /* Pointer to comment character */
- char *v; /* Pointer to returned value string */
- char buf[255]; /* Buffer for warning text */
- const char *d; /* Pointer to first comment character */
- const char *v0; /* Pointer to first non-blank value character */
- double fi, fr; /* Values read from value string */
- int badval; /* Is the keyword value illegal? */
- int blank_name; /* Is keyword name blank? */
- int cont; /* Is this a continuation card? */
- int i; /* Character index */
- int ii, ir; /* Values read from value string */
- int iopt; /* Index of option within list */
- int len; /* Used length of value string */
- int lq; /* Was previous character an escaping quote? */
- int nch; /* No. of characters used */
- int ndig; /* No. of digits in the formatted integer */
- int type; /* Keyword data type */
- size_t nc; /* Number of character in the supplied card */
- size_t ncc; /* No. of characters in the comment string */
- size_t ncv; /* No. of characters in the value string */
-
-/* Initialise the returned pointers. */
- *name = NULL;
- *value = NULL;
- *comment = NULL;
- type = AST__COMMENT;
-
-/* Check the global status. */
- if( !astOK ) return type;
-
-/* Assume initially that the keyword value is legal. */
- badval = 0;
-
-/* Store the number of characters to be read from the supplied card. This
- is not allowed to be more than the length of a FITS header card. */
- nc = 0;
- while( nc < AST__FITSCHAN_FITSCARDLEN && card[ nc ] ) nc++;
-
-/* Reduce the number of characters to read so that any non-printing
- characters such as new-lines at the end of the string are ignored. */
- while( nc > 0 && !isprint( card[ nc - 1 ] ) ) nc--;
-
-/* Allocate memory for a copy of the keyword name plus a terminating
- null character. */
- *name = (char *) astMalloc( ( 1 + FITSNAMLEN )*sizeof(char) );
-
-/* Check the pointer can be used. */
- if( astOK ){
-
-/* Initialise the name string by filling it with spaces, and terminating it. */
- for( i = 0; i < FITSNAMLEN; i++ ) (*name)[ i ] = ' ';
- (*name)[ FITSNAMLEN ] = 0;
-
-/* Copy the the keyword name, ensuring that no more than FITSNAMLEN (8)
- characters are copied. */
- strncpy( *name, card, ( nc > FITSNAMLEN ) ? FITSNAMLEN : nc );
-
-/* If there is no keyword name, flag that we have a blank name which will
- be treated as a comment card. */
- if( strspn( *name, " " ) == strlen( *name ) ){
- blank_name = 1;
-
-/* If the card contains a keyword name, replace any white space with
- nulls. */
- } else {
- blank_name = 0;
- dd = *name + strlen( *name ) - 1;
- while( isspace( *dd ) ) *(dd--) = 0;
- }
-
-/* Check the keyword name is legal. */
- CheckFitsName( this, *name, method, class, status );
-
-/* Allocate memory to hold the keyword value and comment strings. */
- *value = (char *) astMalloc( sizeof(char)*( 2 + nc ) );
- *comment = (char *) astMalloc( sizeof(char)*( 1 + nc ) );
-
-/* Check the pointers can be used. */
- if( astOK ){
-
-/* Check for CONTINUE cards. These have keyword CONTINUE but have a space
- instead of an equals sign in column 9. They must also have a single quote
- in column 11. */
- cont = ( !Ustrcmp( *name, "CONTINUE", status ) &&
- nc > FITSNAMLEN + 3 &&
- card[ FITSNAMLEN ] == ' ' &&
- card[ FITSNAMLEN + 2 ] == '\'' );
-
-/* If column 9 does not contain an equals sign (but is not a CONTINUE card), or if
- the keyword is "HISTORY", "COMMENT" or blank, then columns 9 to the end are
- comment characters, and the value string is null. */
- if( ( nc <= FITSNAMLEN || card[ FITSNAMLEN ] != '='
- || !Ustrcmp( *name, "HISTORY", status )
- || !Ustrcmp( *name, "COMMENT", status )
- || blank_name ) && !cont ){
- (*value)[ 0 ] = 0;
- if( nc > FITSNAMLEN ){
- (void) strncpy( *comment, card + FITSNAMLEN,
- nc - FITSNAMLEN );
- (*comment)[ nc - FITSNAMLEN ] = 0;
- } else {
- (*comment)[ 0 ] = 0;
- }
-
-/* Otherwise there is a value field. */
- } else {
-
-/* Find the first non-blank character in the value string. */
- v0 = card + FITSNAMLEN + 1;
- while( (size_t)(v0 - card) < nc &&
- isspace( (int) *v0 ) ) v0++;
-
-/* Store pointers to the start of the returned value and comment strings. */
- v = *value;
- c = *comment;
-
-/* If the first character in the value string is a single quote, the value is
- a string. In this case the value ends at the first non-escaped single
- quote. */
- if( *v0 == '\''){
- type = cont ? AST__CONTINUE : AST__STRING;
-
-/* We want to copy the string value, without the delimiting quotes, to the
- returned value string. Single quotes within the string are represented
- by two adjacent quotes, so we also need to check for these and replace
- them by one quote in the returned string. First initialise a pointer
- to the first character after the opening quote, and set a flag
- indicating that (for the purposes of identifying pairs of adjacent
- quotes within the string) the previous character was not a quote. */
- d = v0 + 1;
- lq = 0;
-
-/* Loop round each remaining character in the supplied card. */
- while( (size_t)(d - card) < nc ){
-
-/* If the current character is a single quote... */
- if( *d == '\'' ){
-
-/* If the previous character was also a single quote then the quote does
- not mark the end of the string, but is a quote to be included literally
- in the value. Copy the quote to the returned string and clear the flag
- to indicate that the pair of adjacent quotes is now complete. */
- if( lq ){
- *(v++) = '\'';
- lq = 0;
-
-/* If the last character was not a quote, then set the flag for the next
- pass through the loop, but do not copy the quote to the returned string
- since it will either be a quote escaping a following adjacent quote, or
- a quote to mark the end of the string. */
- } else {
- lq = 1;
- }
-
-/* If the current character is not a quote... */
- } else {
-
-/* If the previous character was a quote, then we have found a single
- isolated quote which therefore marks the end of the string value.
- The pointer "d" is left pointing to the first character
- after the terminating quote. */
- if( lq ){
- break;
-
-/* If the last character was not a quote, copy it to the returned string. */
- } else {
- *(v++) = *d;
- }
- }
- d++;
- }
-
-/* Terminate the returned value string. */
- *v = 0;
-
-/* Now deal with logical and numerical values. */
- } else {
-
-/* The end of the value field is marked by the first "/". Find the number
- of characters in the value field. Pointer "d" is left pointing to the
- first character in the comment (if any). Only use "/" characters which
- occur within the first nc characters, and do not occur wiuthin the
- keyword name (not strictly legal, but a warning will have been issued
- by CheckFitsName in such cases). */
- d = strchr( card + FITSNAMLEN, '/' );
- if( !d || ( d - card ) >= nc ){
- ncv = nc - FITSNAMLEN - 1;
- d = NULL;
- } else {
- ncv = (size_t)( d - card ) - FITSNAMLEN - 1;
- }
-
-/* Copy the value string to the returned string. */
- if( ncv == 0 ){
- *v = 0;
- } else {
- strncpy( v, card + FITSNAMLEN + 1, ncv );
- v[ ncv ] = ' ';
- v[ ncv + 1 ] = 0;
- }
-
-/* Find the first non-blank character in the value string. */
- v0 = v;
- while( *v0 && isspace( (int) *v0 ) ) v0++;
-
-/* See if the value string is one of the following strings (optionally
- abbreviated and case insensitive): YES, NO, TRUE, FALSE. */
- iopt = FullForm( "YES NO TRUE FALSE", v0, 1, status );
-
-/* Return the single character "T" or "F" at the start of the value string
- if the value matches one of the above strings. */
- if( iopt == 0 || iopt == 2 ) {
- type = AST__LOGICAL;
- strcpy ( v, "T" );
- } else if( iopt == 1 || iopt == 3 ) {
- type = AST__LOGICAL;
- strcpy ( v, "F" );
-
-/* If it does not match, see if the value is numerical. */
- } else {
-
-/* Save the length of the value string excluding trailing blanks. */
- len = ChrLen( v, status );
-
-/* If the entire string is blank, the value type is UNDEF. */
- if( len == 0 ) {
- type = AST__UNDEF;
-
-/* If there are no dots (decimal points) or exponents (D or E) in the value... */
- } else if( !strpbrk( v, ".EeDd" ) ){
-
-/* First attempt to read two integers from the string (separated by white
- space). */
- if( nch = 0,
- ( 2 == astSscanf( v, " %d %d%n", &ir, &ii, &nch ) ) &&
- ( nch >= len ) ) {
- type = AST__COMPLEXI;
-
-/* If that failed, attempt to read a single integer from the string. */
- } else if( nch = 0,
- ( 1 == astSscanf( v, " %d%n", &ir, &nch ) ) &&
- ( nch >= len ) ) {
- type = AST__INT;
- }
-
-/* If there are dots (decimal points) in the value... */
- } else {
-
-/* First attempt to read two doubles from the string (separated by white
- space). */
- if( nch = 0,
- ( 2 == astSscanf( v, " %lf %lf%n", &fr, &fi, &nch ) ) &&
- ( nch >= len ) ) {
- type = AST__COMPLEXF;
-
-/* If that failed, attempt to read a single double from the string. */
- } else if( nch = 0,
- ( 1 == astSscanf( v, " %lf%n", &fr, &nch ) ) &&
- ( nch >= len ) ) {
- type = AST__FLOAT;
- }
-
-/* If both the above failed, it could be because the string contains a
- "D" exponent (which is probably valid FITS) instead of an "E" exponent.
- Replace any "D" in the string with "e" and try again. */
- if( type == AST__COMMENT && astOK ) {
-
-/* Replace "d" and "D" by "e" (if this doesn't produce a readable floating
- point value then the value string will not be used, so it is safe to
- do the replacement in situ). */
- for( i = 0; i < len; i++ ) {
- if( v[ i ] == 'd' || v[ i ] == 'D' ) v[ i ] = 'e';
- }
-
-/* Attempt to read two doubles from the edited string (separated by white
- space). */
- if( nch = 0,
- ( 2 == astSscanf( v, " %lf %lf%n", &fr, &fi, &nch ) ) &&
- ( nch >= len ) ) {
- type = AST__COMPLEXF;
-
-/* If that failed, attempt to read a single double from the edited string. */
- } else if( nch = 0,
- ( 1 == astSscanf( v, " %lf%n", &fr, &nch ) ) &&
- ( nch >= len ) ) {
- type = AST__FLOAT;
- }
- }
- }
- }
-
-/* If the value type could not be determined, indicate that a warning
- should be issued. */
- if( type == AST__COMMENT && astOK ) {
- badval = 1;
- (*value)[ 0 ] = 0;
- (*comment)[ 0 ] = 0;
- d = NULL;
- }
- }
-
-/* Find the number of characters in the comment. Pointer "d" should point to
- the first character following the value string. */
- if( d ){
- ncc = nc - (size_t)( d - card );
- } else {
- ncc = 0;
- }
-
-/* Copy the remainder of the card to the returned comment string. */
- if( astOK && ncc > 0 ){
- strncpy( c, d, ncc );
- c[ ncc ] = 0;
-
-/* Find the start of the comment (indicated by the first "/" after the
- value string). */
- slash = strchr( c, '/' );
-
-/* Temporarily terminate the string at the slash. */
- if( slash ) *slash = 0;
-
-/* Shuffle the characters following the slash down to the
- start of the returned string. */
- if( slash ){
- ncc -= (size_t)( slash - c ) + 1;
- d = slash + 1;
- for( i = 0; i < 1 + (int) ncc; i++ ) *(c++) = *(d++);
- }
-
-/* If there is no comment string, return a null string. */
- } else {
- *c = 0;
- }
- }
- }
- }
-
-/* Truncate the returned string to avoid wasting space. */
- if( *name ) *name = (char *) astRealloc( (void *) *name, strlen( *name ) + 1 );
- if( *comment ) *comment = (char *) astRealloc( (void *) *comment, strlen( *comment ) + 1 );
- if( *value ) *value = (char *) astRealloc( (void *) *value, strlen( *value ) + 1 );
-
-/* If the value is deemed to be integer, check that the number of digits
- in the formatted value does not exceed the capacity of an int. This may
- be the case if there are too many digits in the integer for an "int" to
- hold. In this case, change the data type to float. */
- if( *value && type == AST__INT ) {
- ndig = 0;
- c = *value;
- while( *c ) {
- if( isdigit( *(c++) ) ) ndig++;
- }
- if( ndig >= int_dig ) type = AST__FLOAT;
- }
-
-/* If an error occurred, free the returned strings and issue a context message. */
- if( !astOK ){
- *name = (char *) astFree( (void *) *name );
- *value = (char *) astFree( (void *) *value );
- *comment = (char *) astFree( (void *) *comment );
- type = AST__COMMENT;
- astError( astStatus, "%s(%s): Unable to store the following FITS "
- "header card:\n%.*s\n", status, method, class,
- AST__FITSCHAN_FITSCARDLEN, card );
-
-/* If a bad keyword value was encountered, issue a warning. Remember that
- "card" may not be null terminated, so ensure that only one header is
- included from "card". */
- } else if( badval ){
- snprintf( buf, sizeof(buf), "The keyword value is illegal in "
- "'%.*s'", AST__FITSCHAN_FITSCARDLEN, card );
- Warn( this, "badkeyvalue", buf, method, class, status );
- }
-
-/* Return the data type. */
- return type;
-}
-
-static int SplitMap( AstMapping *map, int invert, int ilon, int ilat,
- AstMapping **map1, AstWcsMap **map2, AstMapping **map3, int *status ){
-/*
-* Name:
-* SplitMap
-
-* Purpose:
-* Locate a WCS projection within a Mapping.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int SplitMap( AstMapping *map, int invert, int ilon, int ilat,
-* AstMapping **map1, AstWcsMap **map2, AstMapping **map3, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* If possible, the supplied Mapping is decomposed into three component
-* mappings to be compounded in series. To be acceptable, the second of
-* these three Mappings must be an inverted WcsMap with a non-zero
-* FITSProj attribute value, and there must not be such a WcsMap in
-* either of the other two Mappings. If it is not possible to produce
-* such a group of three Mappings, then a zero function value is returned,
-* together with three NULL Mapping pointers. All the mappings before the
-* WcsMap are compounded together and returned as "map1". The inverse of
-* the WcsMap itself is returned as "map2", and any remaining Mappings
-* are compounded together and returned as "map3".
-*
-* The search algorithm allows for an arbitrary combination of series and
-* parallel CmpMaps.
-
-* Parameters:
-* map
-* A pointer to the Mapping from pixel to physical coordinates.
-* invert
-* The value of the Invert attribute to use with "map" (the value
-* returned by astGetInvert is not used).
-* ilon
-* Index of mapping output which is connected to the longitude axis.
-* ilat
-* Index of mapping output which is connected to the latitude axis.
-* map1
-* A location at which to return a pointer to the Mapping from pixel
-* to intermediate world coordinates.
-* map2
-* A location at which to return a pointer to the Mapping from
-* intermediate world coordinates to native spherical coordinates. This
-* will be an inverted WcsMap with non-zero FITSProj attribute value.
-* map3
-* A location at which to return a pointer to the Mapping from
-* native spherical coordinates to physical coordinates.
-* dep
-* The address of an integer holding the current depth of recursion
-* into this function.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* One if a suitable WcsMap was found, zero otherwise.
-
-* Notes:
-* - The returned Mappings contain independant copies of the relevant
-* components of the supplied Mapping and can be modified without
-* changing the supplied Mapping.
-* - NULL pointers will be returned for all Mappings if no WcsMap
-* can be found in the supplied Mapping.
-* - A pointer to a UnitMap will be returned for map1 if no mappings
-* exist before the WcsMap.
-* - A pointer to a UnitMap will be returned for map3 if no mappings
-* exist after the WcsMap.
-* - NULL pointers will be returned for all Mappings and a function
-* value of zero will be returned if an error has occurred, or if this
-* function should fail for any reason.
-*/
-
-/* Local Variables */
- AstFitsChan *fc; /* Pointer to temporary FitsChan */
- AstFrameSet *tfs; /* Temporary FrameSet */
- AstMapping *mapa; /* Pre-wcs Mapping */
- AstMapping *mapc; /* Post-wcs Mapping */
- AstMapping *tmap1; /* Temporary Mapping */
- AstMapping *tmap2; /* Temporary Mapping */
- AstPointSet *pset1; /* Pixel positions */
- AstPointSet *pset2; /* WCS positions */
- AstWcsMap *mapb; /* WcsMap */
- char card[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Buffer for header card */
- double **ptr1; /* Pointer to pixel axis values */
- double **ptr2; /* Pointer to WCS axis values */
- double *iwc_origin; /* Array holding IWC at pixel origin */
- double *pix_origin; /* Array holding pixel coords at pixel origin */
- double *w1; /* Pointer to work space */
- int i; /* Loop index */
- int npix; /* Number of pixel axes */
- int nwcs; /* Number of WCS axes */
- int ret; /* Was a non-linear Mapping found? */
-
-/* Initialise */
- *map1 = NULL;
- *map2 = NULL;
- *map3 = NULL;
- ret = 0;
-
-/* Check the global status. */
- if( !astOK ) return ret;
-
-/* Call SplitMap2 to do the work. SplitMap2 does not check that the
- WcsMap is an *inverted* WcsMap, neither does it check that there
- are no WcsMaps in either map1 or map3. */
- if( SplitMap2( map, invert, map1, map2, map3, status ) ) {
-
-/* Check that the WcsMap is inverted. */
- if( astGetInvert( *map2 ) ) {
-
-/* Check that map 1 does not contain a WcsMap with non-zero FITSProj
- attribute. */
- if( !SplitMap2( *map1, astGetInvert( *map1 ), &mapa, &mapb, &mapc,
- status ) ) {
-
-/* Check that map 3 does not contain a WcsMap with non-zero FITSProj
- attribute. */
- if( !SplitMap2( *map3, astGetInvert( *map3 ), &mapa, &mapb, &mapc,
- status ) ) {
-
-/* If so, the three Mappings are OK. */
- ret = 1;
- } else {
- mapa = astAnnul( mapa );
- mapb = astAnnul( mapb );
- mapc = astAnnul( mapc );
- }
- } else {
- mapa = astAnnul( mapa );
- mapb = astAnnul( mapb );
- mapc = astAnnul( mapc );
- }
- }
- }
-
-/* If the above failed to find a suitable WcsMap, we now consider cases
- where the pixel->WCS mapping is linear. We can invent a CAR projection
- WcsMap for such cases. We use a ShiftMap to move the origin of the
- longitude IWC axis to a sensible value (it is left at zero otherwise).
- We cannot do this with the latitude axis since pre-FITS-WCS fits
- readers could not handle the resulting rotation from native to celestial
- coords. */
- if( !ret && astGetIsLinear( map ) ) {
- nwcs = astGetNout( map );
- npix = astGetNin( map );
- iwc_origin = astMalloc( sizeof( double )*nwcs );
- pix_origin = astMalloc( sizeof( double )*npix );
- if( astOK ) {
- for( i = 0; i < npix; i++ ) pix_origin[ i ] = 0.0;
- astTranN( map, 1, npix, 1, pix_origin, 1, nwcs, 1, iwc_origin );
- for( i = 0; i < nwcs; i++ ) {
- if( i != ilon ) {
- iwc_origin[ i ] = 0.0;
- } else {
- iwc_origin[ i ] *= -1;
- }
- }
- mapa = (AstMapping *) astShiftMap( nwcs, iwc_origin, "", status );
- *map1 = (AstMapping *) astCmpMap( map, mapa, 1, "", status );
- *map2 = astWcsMap( nwcs, AST__CAR, ilon + 1, ilat + 1, "Invert=1", status );
- astInvert( mapa );
- *map3 = astClone( mapa );
- mapa = astAnnul( mapa );
- ret = 1;
- }
- iwc_origin = astFree( iwc_origin );
- pix_origin = astFree( pix_origin );
- }
-
-/* If the above failed to find a suitable WcsMap, we now consider cases
- where the output (long,lat) values are constants supplied by a
- final PermMap. We can invent a WcsMap for such cases. */
- if( !ret ) {
-
-/* Transform two arbitrary pixel positions into the WCS Frame. */
- npix = astGetNin( map );
- nwcs = astGetNout( map );
- pset1 = astPointSet( 2, npix, "", status );
- pset2 = astPointSet( 2, nwcs, "", status );
- ptr1 = astGetPoints( pset1 );
- ptr2 = astGetPoints( pset2 );
- w1 = astMalloc( sizeof( double )*(size_t) nwcs );
- if( astOK ) {
- for( i = 0; i < npix; i++ ) {
- ptr1[ i ][ 0 ] = 1.0;
- ptr1[ i ][ 1 ] = 1000.0;
- }
- (void) astTransform( map, pset1, 1, pset2 );
-
-/* If the two wcs positions have equal longitude and latitude values,
- assume that the output longitude and latitude axes are assigned
- constant values by the Mapping. */
- if( ptr2[ ilon ][ 0 ] == ptr2[ ilon ][ 1 ] &&
- ptr2[ ilon ][ 0 ] != AST__BAD &&
- ptr2[ ilat ][ 0 ] == ptr2[ ilat ][ 1 ] &&
- ptr2[ ilat ][ 0 ] != AST__BAD ) {
-
-/* Create a set of Mappings to return, including a WcsMap, which result in
- these constant latitude and longitude values. We do this by creating a
- FITS-WCS header and reading the FrameSet from it. Keywords which are not
- important to the final mappings are given arbitrary values. */
- fc = astFitsChan( NULL, NULL, "", status );
- for( i = 0; i < nwcs; i++ ) {
- sprintf( card, "CRPIX%d = 0", i + 1 );
- astPutFits( fc, card, 0 );
- sprintf( card, "CDELT%d = 0.0003", i + 1 );
- astPutFits( fc, card, 0 );
- if( i == ilon ) {
- sprintf( card, "CTYPE%d = 'RA---TAN'", i + 1 );
- } else if( i == ilat ) {
- sprintf( card, "CTYPE%d = 'DEC--TAN'", i + 1 );
- } else {
- sprintf( card, "CTYPE%d = 'DUMMY'", i + 1 );
- }
- astPutFits( fc, card, 0 );
- if( i == ilon ) {
- sprintf( card, "CRVAL%d = %.*g", i + 1, DBL_DIG, AST__DR2D*ptr2[ ilon ][ 0 ] );
- } else if( i == ilat ) {
- sprintf( card, "CRVAL%d = %.*g", i + 1, DBL_DIG, AST__DR2D*ptr2[ ilat ][ 0 ] );
- } else {
- sprintf( card, "CRVAL%d = 0.0", i + 1 );
- }
- astPutFits( fc, card, 0 );
- }
- astClearCard( fc );
- tfs = astRead( fc );
- if( tfs ) {
-
-/* Use SplitMap to get the required Mapings from the FrameSet. */
- tmap2 = astGetMapping( tfs, AST__BASE, AST__CURRENT );
- SplitMap( tmap2, astGetInvert( tmap2 ), 0, 1, &tmap1, map2,
- map3, status );
- tmap1 = astAnnul( tmap1 );
- tmap2 = astAnnul( tmap2 );
-
-/* Create a ShiftMap which subtract the constant longitude and latitude
- values off the inputs. */
- for( i = 0; i < nwcs; i++ ) w1[ i ] = 0.0;
- w1[ ilon ] = -ptr2[ ilon ][ 0 ];
- w1[ ilat ] = -ptr2[ ilat ][ 0 ];
- tmap1 = (AstMapping *) astShiftMap( nwcs, w1, "", status );
-
-/* Compose this with the supplied Mapping. This results in the celestial
- outputs being zero. This gives the required "map1". */
- *map1 = (AstMapping *) astCmpMap( map, tmap1, 1, "", status );
-
-/* Indicate success.*/
- ret = 1;
-
-/* Free resources. */
- tmap1 = astAnnul( tmap1 );
- tfs = astAnnul( tfs );
- }
- fc = astAnnul( fc );
- }
- }
-
-/* Free resources */
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
- w1 = astFree( w1 );
- }
- if( !ret ) {
- if( *map1 ) *map1 = astAnnul( *map1 );
- if( *map2 ) *map2 = astAnnul( *map2 );
- if( *map3 ) *map3 = astAnnul( *map3 );
- }
- return ret;
-}
-
-static int SplitMap2( AstMapping *map, int invert, AstMapping **map1,
- AstWcsMap **map2, AstMapping **map3, int *status ){
-/*
-* Name:
-* SplitMap2
-
-* Purpose:
-* Locate a WCS projection within a Mapping.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int SplitMap2( AstMapping *map, int invert, AstMapping **map1,
-* AstWcsMap **map2, AstMapping **map3, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* If possible, the supplied Mapping is decomposed into three component
-* mappings to be compounded in series. To be acceptable, the second of
-* these three Mappings must be a WcsMap with a non-zero FITSProj value.
-* If it is not possible to produce such a group of three Mappings, then a
-* zero function value is returned, together with three NULL Mapping
-* pointers. All the mappings before the WcsMap are compounded together
-* and returned as "map1". The WcsMap itself is returned as "map2", and
-* any remaining Mappings are compounded together and returned as "map3".
-*
-* The search algorithm allows for an arbitrary combination of series and
-* parallel CmpMaps.
-
-* Parameters:
-* map
-* A pointer to the Mapping from pixel to physical coordinates.
-* invert
-* The value of the Invert attribute to use with "map" (the value
-* returned by astGetInvert is not used).
-* map1
-* A location at which to return a pointer to the Mapping from pixel
-* to intermediate world coordinates.
-* map2
-* A location at which to return a pointer to the Mapping from relative
-* physical coordinates to native spherical coordinates. This will
-* be a WcsMap, and it will have a non-zero FITSProj value.
-* map3
-* A location at which to return a pointer to the Mapping from
-* native spherical coordinates to physical coordinates.
-* dep
-* The address of an integer holding the current depth of recursion
-* into this function.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* One if a suitable WcsMap was found, zero otherwise.
-
-* Notes:
-* - The returned Mappings contain independant copies of the relevant
-* components of the supplied Mapping and can be modified without
-* changing the supplied Mapping.
-* - NULL pointers will be returned for all Mappings if no WcsMap
-* with anon-zero FITSProj value can be found in the supplied Mapping.
-* - A pointer to a UnitMap will be returned for map1 if no mappings
-* exist before the WcsMap.
-* - A pointer to a UnitMap will be returned for map3 if no mappings
-* exist after the WcsMap.
-* - NULL pointers will be returned for all Mappings and a function
-* value of zero will be returned if an error has occurred, or if this
-* function should fail for any reason.
-* - "*map1" and "*map3" may contain WcsMaps, but they will have zero
-* values for their FITSProj values.
-*/
-
-/* Local Variables */
- AstMapping **map_list; /* Mapping array pointer */
- AstMapping *mapa; /* Pre-wcs Mapping */
- AstWcsMap *mapb; /* WcsMap */
- AstMapping *mapc; /* Post-wcs Mapping */
- AstMapping *temp; /* Intermediate Mapping */
- const char *class; /* Pointer to class of supplied Mapping */
- double pv; /* Projection parameter value */
- int *invert_list; /* Invert array pointer */
- int axis; /* No. of axes in whole Mapping */
- int axlat; /* Index of latitude axis */
- int axlon; /* Index of longitude axis */
- int haswcs; /* Was a usable inverted WcsMap found? */
- int imap; /* Index of current Mapping in list */
- int i; /* axis index */
- int m; /* Parameter index */
- int nax; /* No. of axes in Mapping */
- int nmap; /* Number of Mappings in the list */
- int ret; /* Was a non-linear Mapping found? */
- int wcsaxis; /* Index of first WcsMap axis */
-
-/* Initialise */
- *map1 = NULL;
- *map2 = NULL;
- *map3 = NULL;
- ret = 0;
-
-/* Check the global status. */
- if( !astOK ) return ret;
-
-/* Get the class of the Mapping. */
- class = astGetClass( map );
-
-/* If the supplied Mapping is a CmpMap... */
- wcsaxis = -1;
- if( !strcmp( class, "CmpMap" ) ){
-
-/* Decompose the Mapping into a sequence of Mappings to be applied in
- series and an associated list of Invert flags. */
- map_list = NULL;
- invert_list = NULL;
- nmap = 0;
- astMapList( map, 1, invert, &nmap, &map_list, &invert_list );
-
-/* If there is more than one Mapping, this must be a series CmpMap. */
- if( nmap > 1 && astOK ){
-
-/* Initialise the returned pre-wcs Mapping to be a UnitMap. */
- if( invert == astGetInvert( map ) ){
- *map1 = (AstMapping *) astUnitMap( astGetNin( map ), "", status );
- } else {
- *map1 = (AstMapping *) astUnitMap( astGetNout( map ), "", status );
- }
-
-/* Indicate we have not yet found a WcsMap. */
- ret = 0;
-
-/* Process each series Mapping. */
- for( imap = 0; imap < nmap; imap++ ){
-
-/* If we have not yet found a WcsMap... */
- if( !ret ){
-
-/* Search this Mapping for a WcsMap. */
- ret = SplitMap2( map_list[ imap ], invert_list[ imap ], &mapa,
- map2, map3, status );
-
-/* If no WcsMap was found, use the whole mapping as part of the
- pre-wcs Mapping. */
- if( !ret ){
- mapa = astCopy( map_list[ imap ] );
- astSetInvert( mapa, invert_list[ imap ] );
- }
-
-/* Add the pre-wcs mapping to the cumulative pre-wcs CmpMap. */
- temp = (AstMapping *) astCmpMap( *map1, mapa, 1, "", status );
- *map1 = astAnnul( *map1 );
- mapa = astAnnul( mapa );
- *map1 = temp;
-
-/* If we have previously found a WcsMap, use the whole mapping
- as part of the post-wcs mapping. */
- } else {
- mapc = astCopy( map_list[ imap ] );
- astSetInvert( mapc, invert_list[ imap ] );
- temp = (AstMapping *) astCmpMap( *map3, mapc, 1, "", status );
- *map3 = astAnnul( *map3 );
- mapc = astAnnul( mapc );
- *map3 = temp;
- }
- }
-
-/* If there is only one Mapping, this must be a parallel CmpMap. */
- } else {
-
-/* Annul the Mapping pointer in the series list created above, and free the
- dynamic arrays. */
- map_list[ 0 ] = astAnnul( map_list[ 0 ] );
- map_list = astFree( map_list );
- invert_list = astFree( invert_list );
- nmap = 0;
-
-/* Decompose the Mapping into a sequence of Mappings to be applied in
- parallel and an associated list of Invert flags. */
- astMapList( map, 0, invert, &nmap, &map_list, &invert_list );
-
-/* Process each parallel Mapping. */
- axis = 0;
- for( imap = 0; imap < nmap && astOK; imap++ ){
-
-/* See if this Mapping contains a usable WcsMap. Only do the search
- if no such WcsMap has already been found, since only the first is usable. */
- if( !ret ) {
-
-/* Search this Mapping for a WcsMap. */
- haswcs = SplitMap2( map_list[ imap ], invert_list[ imap ], &mapa,
- &mapb, &mapc, status );
-
-/* Note if we have found a usable WcsMap, and its first axis index. */
- if( haswcs ){
- ret = 1;
- wcsaxis = axis;
- }
-
-/* If a WcsMap has already been found, the mapping cannot contain a
- usable WcsMap. */
- } else {
- haswcs = 0;
- }
-
-/* If the Mapping did not contain a usable WcsMap, use the whole mapping as
- part of the pre-wcs Mapping, and create a UnitMap as part of the post-wcs
- mapping. */
- if( !haswcs ){
- mapa = astCopy( map_list[ imap ] );
- astSetInvert( mapa, invert_list[ imap ] );
- nax = astGetNout( mapa );
- mapc = (AstMapping *) astUnitMap( nax, "", status );
- }
-
-/* Increment the index of the first axis in the next Mapping. */
- axis += astGetNout( mapa );
-
-/* Add the pre-wcs mapping in parallel with the cumulative pre-wcs CmpMap. */
- if( *map1 ){
- temp = (AstMapping *) astCmpMap( *map1, mapa, 0, "", status );
- *map1 = astAnnul( *map1 );
- mapa = astAnnul( mapa );
- *map1 = temp;
- } else {
- *map1 = mapa;
- }
-
-/* Add the post-wcs mapping in parallel with the cumulative post-wcs CmpMap. */
- if( *map3 ){
- temp = (AstMapping *) astCmpMap( *map3, mapc, 0, "", status );
- *map3 = astAnnul( *map3 );
- mapc = astAnnul( mapc );
- *map3 = temp;
- } else {
- *map3 = mapc;
- }
- }
-
-/* If a usable WcsMap was found, create a new one which has all the same
- properties, but with enough axes to join the pre and post wcs Mappings
- together. Ensure the correct axes are used for longitude and latitude,
- and copy the projection parameters. */
- if( ret ){
- axlat = astGetWcsAxis( mapb, 1 );
- axlon = astGetWcsAxis( mapb, 0 );
- *map2 = astWcsMap( axis, astGetWcsType( mapb ),
- axlon + wcsaxis + 1,
- axlat + wcsaxis + 1, "", status );
- for( i = 0; i < astGetNin( mapb ); i++ ){
- for( m = 0; m < WCSLIB_MXPAR; m++ ){
- if( astTestPV( mapb, i, m ) ) {
- pv = astGetPV( mapb, i, m );
- if( pv != AST__BAD ) astSetPV( *map2, i + wcsaxis, m, pv );
- }
- }
- }
- astInvert( *map2 );
- mapb = astAnnul( mapb );
- }
- }
-
-/* Loop to annul all the Mapping pointers in the list. */
- for ( imap = 0; imap < nmap; imap++ ) map_list[ imap ] = astAnnul( map_list[ imap ] );
-
-/* Free the dynamic arrays. */
- map_list = astFree( map_list );
- invert_list = astFree( invert_list );
-
-/* If the supplied Mapping is not a CmpMap, see if it is a WcsMap with a
- non-zero FITSProj value. If so, take a copy and set its invert attribute
- correctly. Also create UnitMaps for the pre and post wcs mappings. */
- } else if( astOK && !strcmp( class, "WcsMap" ) && astGetFITSProj( map ) ){
- ret = 1;
- nax = astGetNin( map );
- *map1 = (AstMapping *) astUnitMap( nax, "", status );
- *map2 = astCopy( map );
- astSetInvert( *map2, invert );
- *map3 = (AstMapping *) astUnitMap( nax, "", status );
- }
-
-/* If an error has occurred, or if no suitable WcsMap was found, annul any
- Mappings. */
- if( !astOK || !ret ){
- ret = 0;
- if( *map1 ) *map1 = astAnnul( *map1 );
- if( *map2 ) *map2 = astAnnul( *map2 );
- if( *map3 ) *map3 = astAnnul( *map3 );
- }
-
-/* Return the answer. */
- return ret;
-}
-
-static int SplitMat( int naxis, double *matrix, double *cdelt, int *status ){
-/*
-* Name:
-* SplitMat
-
-* Purpose:
-* Factorises a single "CD"-style matrix into a diagonal CDELT matrix
-* and a "PC"-style matrix.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int SplitMat( int naxis, double *matrix, double *cdelt, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function splits up the supplied CD matrix into separate PC and
-* CDELT matrices. The product of the returned matrices (CDELT.PC)
-* equals the supplied CD matrix. The CDELT values are chosen so that
-* the corresponding row of the PC matrix represents a unit vector.
-* The signs of the CDELT values are chosen so that the diagonal terms
-* of the PC matrix are all positive.
-*
-
-* Parameters:
-* naxis
-* The number of axes.
-* matrix
-* A pointer to an array of naxis*naxis elements. On entry this holds
-* the "CD" matrix. On exit, it is modified to represent the "PC"
-* matrix.
-* cdelt
-* A pointer to an array of naxis elements. On exit this holds the CDELT
-* values for each axis (i.e. the diagonal terms of the CDELT matrix).
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero is returned if any bad values are found in the supplied
-* matrix, or if an error has already occurred. One is returned otherwise.
-*/
-
-/* Local Variables: */
- int i;
- int j;
- int ok;
- double *a;
- int dineg;
- double s2;
- double cdlt;
-
-/* Check the inherited status. */
- if( !astOK ) return 0;
-
-/* Assume success. */
- ok = 1;
-
-/* Loop round every row in the matrix. Get a pointer to the first element
- in the row. */
- for( i = 0; i < naxis; i++ ){
- a = matrix + i*naxis;
-
-/* Note the sign of the diagonal term (i.e. the i'th element) of this row. */
- dineg = ( a[ i ] < 0.0 );
-
-/* Get the magnitude of the vector represented by this row. This is the
- CDELT value for the row. BAD values cause the whole function to return. */
- s2 = 0.0;
- for( j = 0; j < naxis; j++ ){
- if( *a == AST__BAD ) {
- ok = 0;
- break;
- }
- s2 += (*a)*(*a);
- a++;
- }
- if( !ok ) break;
- cdlt = sqrt( astMAX( 0.0, s2 ) );
-
-/* If the diagonal term for this row of the matrix is negative, make
- the CDELT value negative instead. This means that the diagonal term in
- the final PC matrix will be positive. */
- if( dineg ) cdlt = -cdlt;
-
-/* Store the CDELT value. */
- cdelt[ i ] = cdlt;
-
-/* The row of the PC matrix is obtained by dividing the original row by
- the CDELT value. Set to zero any PC values which are less than 1.0E-7
- (such values may be produced by rounding errors). */
- a = matrix + i*naxis;
- for( j = 0; j < naxis; j++ ) {
- if( cdlt != 0.0 ){
- *a /= cdlt;
- if( fabs( *a ) < 1.E-7 ) *a = 0.0;
- } else {
- *a = 0.0;
- }
- a++;
- }
- }
- return ok;
-}
-static void TableSource( AstFitsChan *this,
- void (* tabsource)( AstFitsChan *, const char *,
- int, int, int * ),
- int *status ){
-
-/*
-*++
-* Name:
-c astTableSource
-f AST_TABLESOURCE
-
-* Purpose:
-c Register a source function for accessing tables in FITS files.
-f Register a source routine for accessing tables in FITS files.
-
-* Type:
-* Public function.
-
-* Synopsis:
-c #include "fitschan.h"
-c void astTableSource( AstFitsChan *this,
-c void (* tabsource)( AstFitsChan *, const char *,
-c int, int, int * ) )
-f CALL AST_TABLESOURCE( THIS, TABSOURCE, STATUS )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-c This function can be used to register a call-back function
-f This routine can be used to register a call-back routine
-* with a FitsChan. The registered
-c function
-f routine
-* is called when-ever the FitsChan needs to read information from a
-* binary table contained within a FITS file. This occurs if the
-c astRead
-f AST_READ
-* function is invoked to read a FrameSet from a set of FITS headers
-* that use the "-TAB" algorithm to describe one or more axes. Such
-* axes use a FITS binary table to store a look-up table of axis values.
-* The FitsChan will fail to read such axes unless the "TabOK" attribute
-* is set to a non-zero positive integer value. The table containing the
-* axis values must be made available to the FitsChan either by storing
-* the table contents in the FitsChan (using
-c astPutTables or astPutTable) prior to invoking astRead
-f AST_PUTTABLES or AST_PUTTABLE) prior to invoking AST_READ
-* or by registering a call-back
-c function using astTableSource.
-f routine using AST_TABLESOURCE.
-* The first method is possibly simpler, but requires that the name of
-* the extension containing the table be known in advance. Since the
-* table name is embedded in the FITS headers, the name is often not
-* known in advance. If a call-back is registered, the FitsChan will
-* determine the name of the required table and invoke the call-back
-c function
-f routine
-* to supply the table at the point where it is needed (i.e. within
-c the astRead method).
-f the AST_READ method).
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c tabsource
-f TABSOURCE = SUBROUTINE (Given)
-c Pointer to the table source function to use.
-f The table source routine to use.
-* It takes five arguments - the first is a pointer to the
-* FitsChan, the second is a string holding the name of the
-* FITS extension containing the required binary table ("EXTNAME"),
-* the third is the integer FITS "EXTVER" header value for the
-* required extension, the fourth is the integer FITS "EXTLEVEL"
-* header value for the required extension, and the fifth is
-c a pointer to
-* the inherited integer status value.
-*
-* The call-back should read the entire contents (header and data)
-* of the binary table in the named extension of the external FITS
-* file, storing the contents in a newly created FitsTable object. It
-* should then store this FitsTable in the FitsChan using the
-c astPutTables or astPutTable
-f AST_PUTTABLES or AST_PUTTABLE
-* method, and finally annull its local copy of the FitsTable pointer.
-* If the table cannot be read for any reason, or if any other
-* error occurs, it should return a non-zero integer for the final
-* (third) argument.
-*
-c If "tabsource" is NULL,
-f If TABSOURCE is AST_NULL,
-* any registered call-back function will be removed.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-c - Application code can pass arbitrary data (such as file
-c descriptors, etc) to the table source function using the
-c astPutChannelData function. The source function should use
-c the astChannelData macro to retrieve this data.
-f - The name of the routine supplied for the TABSOURCE
-f argument should appear in an EXTERNAL statement in the Fortran
-f routine which invokes AST_TABLESOURCE. However, this is not generally
-f necessary for the null routine AST_NULL (so long as the AST_PAR
-f include file has been used).
-f - Note that the null routine AST_NULL (one underscore) is
-f different to AST__NULL (two underscores), which is the null Object
-f pointer.
-*--
-*/
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Register the supplied source function, using the wrapper function
- appropriate for calling C table source functions. */
- astSetTableSource( this, (void (*)( void )) tabsource, TabSourceWrap );
-}
-
-static AstMapping *TabMapping( AstFitsChan *this, FitsStore *store, char s,
- int **tabaxis, const char *method,
- const char *class, int *status ) {
-
-/*
-* Name:
-* TabMapping
-
-* Purpose:
-* Create a Mapping that performs any -TAB look-ups for all WCS axes.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstMapping *TabMapping( AstFitsChan *this, FitsStore *store, char s,
-* int **tabaxis, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function returns a Mapping that has "nwcs" inputs and outputs,
-* where "nwcs" is the number of FITS WCS axes defined in the supplied
-* FitsStore. The inputs and outputs are in the same order as the
-* CTYPEi keywords in the FitsStore. The forward transformation of the
-* Mapping converts positions from the axes defined by the CRVALi keywords
-* to the WCS axes. This transformation will be a UnitMap except for
-* any axes that are described using the "-TAB" algorithm. For "-TAB"
-* axes, the transformation will implement the relevant coordinate
-* look-up function.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore structure holding the values to use for
-* the WCS keywords.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* tabaxis
-* Address of a location at which to store a pointer to an array of
-* flags, one for each output of the returned Mapping. A flag will
-* be non-zero if the corresponding output of the returned Mapping
-* corresponds to a -TAB axis. A NULL pointer is returned if the
-* returned Mapping is NULL.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to a Mapping. A NULL pointer is returned if the FitsChan does
-* not support the -TAB algorithm (i.e. if the value of the TabOK
-* attribute is zero or negative), or if no axes use the "-TAB" algorithm.
-*/
-
-/* Local Variables: */
- AstFitsTable *table;
- AstKeyMap *used_tables;
- AstMapping *tmap1;
- AstMapping *tmap2;
- AstMapping *indexmap;
- AstMapping *tmap0;
- AstMapping *ret;
- AstPermMap *pm;
- char name[21];
- const char *indexcol;
- const char *extname;
- const char *cval;
- const char *ctype;
- const char *coordscol;
- double dval;
- int *marray;
- int *permin;
- int *permout;
- int extlevel;
- int extver;
- int iaxis;
- int iiaxis;
- int ikey;
- int interp;
- int ival;
- int maxis;
- int mdim;
- int nkey;
- int nperm;
- int unit;
- int wcsaxes;
-
-/* Initialise */
- ret = NULL;
- *tabaxis = NULL;
- extname = NULL;
- tmap0 = NULL;
- tmap2 = NULL;
-
-/* Check the global status. */
- if( !astOK ) return ret;
-
-/* Obtain the number of physical axes in the header. If the WCSAXES header
- was specified, use it. Otherwise assume it is the same as the number
- of pixel axes. */
- dval = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status );
- if( dval != AST__BAD ) {
- wcsaxes = (int) dval + 0.5;
- } else {
- wcsaxes = store->naxis;
- }
-
-/* If the FitsChan does not support the -TAB algorithm, return a NULL
- pointer. */
- if( astGetTabOK( this ) > 0 ) {
-
-/* Create a KeyMap to hold a list of the used extension names. */
- used_tables = astKeyMap( " ", status );
-
-/* Allocate memory to indicate if each WCS axis is described by a -TAB
- algorithm or not. Initialiss it to zero. */
- *tabaxis = astCalloc( wcsaxes, sizeof( int ) );
-
-/* Allocate memory to hold the FITS-WCS axis index corresponding to each
- input of the "tmap0" Mapping. Indicate that as yet, not values are
- stored in this array. Also allocate memory for the inverse of this
- permutation array. */
- permout = astMalloc( wcsaxes*sizeof( int ) );
- permin = astMalloc( wcsaxes*sizeof( int ) );
- nperm = 0;
- if( astOK ) {
-
-/* Initialise the permutation arrays. */
- for( iaxis = 0; iaxis < wcsaxes; iaxis++ ) {
- permout[ iaxis ] = permin[ iaxis ] = -1;
- }
-
-/* Otherwise, loop round all FITS WCS axis indices present in the FitsStore. */
- for( iaxis = 0; iaxis < wcsaxes; iaxis++ ) {
-
-/* If the current FITS WCS axis is already included in the returned
- Mapping, skip it. This will be the case if the axis uses the same
- coordinate array as an earlier axis since all FITS WCS axes associated
- with a coordinate array are processed together. */
- if( permin[ iaxis ] == -1 ) {
-
-/* See if this WCS axis uses the -TAB algorithm. */
- ctype = GetItemC( &(store->ctype), iaxis, 0, s, NULL, method,
- class, status );
- if( ctype && strlen(ctype) > 4 && !strncmp( ctype + 4, "-TAB", 4 ) ) {
-
-/* Get the name of the FITS binary table extension holding the coordinate
- info. No default, so report an error if not present. */
- sprintf( name, "PS%d_0%c", iaxis + 1, s );
- extname = GetItemC( &(store->ps), iaxis, 0, s, name, method,
- class, status );
-
-/* Get the extension version and level. */
- dval = GetItem( &(store->pv), iaxis, 1, s, NULL, method,
- class, status );
- extver = ( dval != AST__BAD ) ? (int) dval : 1;
- dval = GetItem( &(store->pv), iaxis, 2, s, NULL, method,
- class, status );
- extlevel = ( dval != AST__BAD ) ? (int) dval : 1;
-
-/* Get the FITS binary table. This will invoke any supplied table source
- function, and put a copy of the table into the FitsChan structure.
- Report an error if the table can not be obtained. */
- table = GetNamedTable( this, extname, extver, extlevel, 1,
- method, status );
-
-/* Add this extension name to a list of used extensions. */
- astMapPut0I( used_tables, extname, 1, NULL );
-
-/* Get the name of the table column containing the main coords array. No
- default so report error if not present. Report an error if the column
- is not present in the table. */
- sprintf( name, "PS%d_1%c", iaxis + 1, s );
- coordscol = GetItemC( &(store->ps), iaxis, 1, s, name, method,
- class, status );
- if( !astHasColumn( table, coordscol ) && astOK ) {
- astError( AST__BADTAB, "%s(%s): Unable to find the "
- "coordinate array for FITS-WCS axis %d (type %s): "
- "column '%s' cannot be found in table '%s'.", status,
- method, class, iaxis + 1, ctype, coordscol, extname );
- }
-
-/* Get the number of dimensions spanned by the coordinate array. Report
- an error if the coordinate array has only one axis (FITS-WCS paper III
- requires it to have at leats two axes). */
- mdim = astGetColumnNdim( table, coordscol );
- if( mdim == 1 && astOK ) {
- astError( AST__BADTAB, "%s(%s): Unable to use the "
- "coordinate array for FITS-WCS axis %d (type %s): "
- "column '%s' in table '%s' has one axis but at "
- "least two are required.", status, method, class,
- iaxis + 1, ctype, coordscol, extname );
- }
-
-/* Allocate memory to hold the FITS-WCS axis corresponding to each dimension
- of the coordinate array. Initialise it to hold -1 (i.e. "no matching
- FITS-WCS axis yet found") at every element. */
- marray = astMalloc( mdim*sizeof( int ) );
- if( astOK ) {
- for( maxis = 0; maxis < mdim; maxis++ ) {
- marray[ maxis ] = -1;
- }
-
-/* Loop round each dimension of the coordinate array, storing the index
- of the corresponding FITS-WCS axis in "marray". We omit the first axis
- (axis 0) since FITS-WCS Paper III defines it is a "conventional" axis
- used to enumerate the planes of coordinate values. */
- for( maxis = 1; maxis < mdim && astOK ; maxis++ ) {
-
-/* Each axis of the coordinate array (except axis 0) must have one, and only
- one, corresponding FITS-WCS axis. Check each FITS-WCS axis to find one
- that uses the same table and column as the "iaxis" axis, and which
- corresponds to axis "maxis" of the coordinate array. */
- for( iiaxis = 0; iiaxis < wcsaxes; iiaxis++ ) {
- cval = GetItemC( &(store->ps), iiaxis, 0, s, NULL,
- method, class, status );
- if( cval && !strcmp( cval, extname ) ) {
- cval= GetItemC( &(store->ps), iiaxis, 1, s, NULL,
- method, class, status );
- if( cval && !strcmp( cval, coordscol ) ) {
- dval = GetItem( &(store->pv), iiaxis, 3, s,
- NULL, method, class, status );
- if( dval != AST__BAD ) {
- ival = (int)( dval + 0.5 );
- } else {
- ival = 1;
- }
- if( ival == maxis ) {
-
-/* Arrive here if the "iiaxis" FITS-WCS axis uses the same table and column
- as "iaxis", and corresponds to the "maxis" axis in the coordinate
- array. If this is the first matching FITS-WCS axis, store its index. */
- if( marray[ maxis ] == -1 ) {
- marray[ maxis ] = iiaxis;
-
-/* If a matching FITS-WCS axis has already been found, report an error. */
- } else if( astOK ) {
- astError( AST__BADTAB, "%s(%s): Unable to use "
- "the coordinate array for FITS-WCS "
- "axis %d (type %s): more than one "
- "intermediate WCS axis is mapped onto "
- " dimension %d of the coordinate "
- "array in column '%s' of table '%s'.",
- status, method, class, iaxis + 1,
- ctype, maxis, coordscol, extname );
- }
- }
- }
- }
- }
- }
-
-/* Check that every dimension of the coordinate array (except the first) has
- a corresponding FITS-WCS axis. */
- for( maxis = 1; maxis < mdim && astOK ; maxis++ ) {
- if( marray[ maxis ] == -1 ) {
- astError( AST__BADTAB, "%s(%s): Unable to use the "
- "coordinate array for FITS-WCS axis %d (type "
- "%s): no intermediate WCS axis is mapped onto "
- " dimension %d of the coordinate array in column "
- " '%s' of table '%s'.", status, method, class,
- iaxis + 1, ctype, maxis, coordscol, extname );
- }
- }
-
-/* Now we know which FITS-WCS axis corresponds to each dimension of the
- coordinate array. We now need to form a parallel CmpMap (compound Mapping)
- by gathering together the indexing vectors for each dimension of the
- coordinates array. Each indexing vector is represented by an inverted
- 1D LutMap - dimensions that do not have an indexing vector are
- represented using a UnitMap. */
- indexmap = NULL;
- unit = 1;
- for( maxis = 1; maxis < mdim && astOK ; maxis++ ) {
-
-/* Get the name of the column containing the index array. Defaults is to
- use a unit index, so do not report an error if not present. */
- indexcol = GetItemC( &(store->ps), marray[ maxis ], 2,
- s, NULL, method, class, status );
-
-/* If the table contains an index vector, create a LutMap from it, then
- invert it. */
- if( indexcol ) {
- tmap1 = MakeColumnMap( table, indexcol, 1, 0,
- method, class, status );
- astInvert( tmap1 );
- unit = 0;
-
-/* If the table does not contain an index vector, use a UnitMap. */
- } else {
- tmap1 = (AstMapping *) astUnitMap( 1, " ", status );
- }
-
-/* Combine the index Mapping for this dimension in parallel with the
- Mapping for all earlier dimensions. */
- if( indexmap ) {
- tmap2 = (AstMapping *) astCmpMap( indexmap, tmap1,
- 0, " ", status );
- indexmap = astAnnul( indexmap );
- tmap1 = astAnnul( tmap1 );
- indexmap = tmap2;
- } else {
- indexmap = tmap1;
- }
- }
-
-/* Get the interpolation method to use for the main coordinate array.
- This is an extension to the published -TAB algorithm in which the
- QVi_4a keyword is assumed to hold zero for linear interpolation (the
- default) and non-zero for nearest neighbour interpolation. The QVi_4a
- keyword will be translated to PVi_4a by the SpecTrans function. */
- dval = GetItem( &(store->pv), iaxis, 4, s,
- NULL, method, class, status );
- if( dval != AST__BAD ) {
- interp = (int)( dval + 0.5 );
- } else {
- interp = 0;
- }
-
-/* Make a Mapping from the main coordinate array, and then if required
- append it in series to the end of the index Mapping created above. */
- tmap1 = MakeColumnMap( table, coordscol, 0, interp,
- method, class, status );
- if( ! unit ) {
- tmap2 = (AstMapping *) astCmpMap( indexmap, tmap1, 1,
- " ", status );
- } else {
- tmap2 = astClone( tmap1 );
- }
- indexmap = astAnnul( indexmap );
- tmap1 = astAnnul( tmap1 );
-
-/* Extend the array that holds the zero-based FITS-WCS axis index
- corresponding to each input of the extended "tmap0" mapping. Also create
- the inverse permutation (i.e. zero-based "tmap0" input indexed by
- zero-based FITS-WCS axis index). */
- for( maxis = 1; maxis < mdim; maxis++ ) {
- permout[ nperm ] = marray[ maxis ];
- permin[ marray[ maxis ] ] = nperm++;
- }
-
-/* Free resources. */
- marray = astFree( marray );
- }
-
-/* Annul the table pointer. */
- table = astAnnul( table );
-
-/* Clear the CTYPE algorithm code to indicate that the axis should be
- considered to be linear from now on. This means that the following
- functions will create a Mapping from pixel to psi (the system in which
- the CRVAL values are defined when using -TAB). The psi axes will then
- be mapping into the CS axes using the Mappign returned by this function. */
- strncpy( name, ctype, 4 );
- strcpy( name + 4, ctype + 8 );
- SetItemC( &(store->ctype), iaxis, 0, s, name, status );
-
-/* Set the returned flag for this axis. */
- (*tabaxis)[ iaxis ] = 1;
-
-/* If the FITS WCS axis "iaxis" does not use a -TAB algorithm, describe
- it in the returned Mapping using a 1D UnitMap. */
- } else {
- tmap2 = (AstMapping *) astUnitMap( 1, " ", status );
-
-/* Extend the array that holds the zero-based FITS-WCS axis index
- corresponding to each input of the extended "tmap0" mapping. Also create
- the inverse permutation (i.e. zero-based "tmap0" input indexed by
- zero-based FITS-WCS axis index). */
- permout[ nperm ] = iaxis;
- permin[ iaxis ] = nperm++;
- }
-
-/* Append the Mapping describing the FITS WCS axis "iaxis" in parallel to any
- Mappings created for earlier "iaxis" axes. */
- if( tmap0 ) {
- tmap1 = (AstMapping *) astCmpMap( tmap0, tmap2, 0, " ", status );
- tmap0 = astAnnul( tmap0 );
- tmap2 = astAnnul( tmap2 );
- tmap0 = tmap1;
- } else {
- tmap0 = tmap2;
- }
- }
- }
-
-/* If no -TAB axes were found, just return a NULL pointer. */
- if( extname && astOK ) {
-
-/* Do a sanity check on the permutation arrays. */
- for( iaxis = 0; iaxis < wcsaxes; iaxis++ ) {
- if( permin[ iaxis ] < 0 || permin[ iaxis ] >= wcsaxes ||
- permout[ permin[ iaxis ] ] != iaxis ) {
- astError( AST__INTER, "%s(%s): Invalid permutation "
- "arrays in function TabMapping (internal AST "
- "progranmming error).", status, method, class );
- break;
- }
- }
-
-/* Sandwich the "tmap0" Mapping in series between two PermMaps to create a
- Mapping in which the inputs and outputs correspond to FITS WCS axis
- numbering. */
- pm = astPermMap( wcsaxes, permin, wcsaxes, permout, NULL, " ",
- status );
- tmap1 = (AstMapping *) astCmpMap( pm, tmap0, 1, " ", status );
- astInvert( pm );
- tmap2 = (AstMapping *) astCmpMap( tmap1, pm, 1, " ", status );
- pm = astAnnul( pm );
- tmap1 = astAnnul( tmap1 );
-
-/* Simplify the returned Mapping. */
- ret = astSimplify( tmap2 );
- tmap2 = astAnnul( tmap2 );
- }
-
-/* Free remaining resources */
- tmap0 = astAnnul( tmap0 );
- }
- permout = astFree( permout );
- permin = astFree( permin );
-
-/* Remove all used tables from the FitsChan now that they have been used. */
- nkey = astMapSize( used_tables );
- for( ikey = 0; ikey < nkey; ikey++ ) {
- astRemoveTables( this, astMapKey( used_tables, ikey ) );
- }
-
-/* Delete the KeyMap holding the used table names. */
- used_tables = astAnnul( used_tables );
-
-/* If we are not returning a Mapping, ensure we do not return any axis
- flags either. */
- if( !ret ) *tabaxis = astFree( *tabaxis );
- }
-
-/* Return the result */
- return ret;
-}
-static void TabSourceWrap( void (*tabsource)( void ),
- AstFitsChan *this, const char *extname,
- int extver, int extlevel, int *status ){
-
-/*
-* Name:
-* TabSourceWrap
-
-* Purpose:
-* Wrapper function to invoke the C table source function.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void TabSourceWrap( void (*tabsource)( void ),
-* AstFitsChan *this, const char *extname,
-* int extver, int extlevel, int *status )
-
-* Class Membership:
-* Channel member function.
-
-* Description:
-* This function invokes the table source function whose pointer is
-* supplied in order to read a named FITS binary table from an external
-* FITS file.
-
-* Parameters:
-* tabsource
-* Pointer to the C tab source function.
-* this
-* Pointer to the FitsChan. The reference count for the FitsChan is
-* decremented by this function (this behaviour is imposed by
-* restrictions in the equivalent Fortran wrapper function).
-* extname
-* Pointer to the string holding the name of the FITS extension
-* from which a table is to be read.
-* extver
-* The integer "EXTVER" value for the required extension.
-* extlevel
-* The integer "EXTLEVEL" value for the required extension.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- AstFitsChan *this_id;
- int lstat;
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get an external identifier for the FitsChan. Could use astClone here
- to avoid this function anulling the supplied pointer, but the F77 wrapper
- cannot use the protected version of astClone, so for consistency we do
- not use it here either. */
- this_id = astMakeId( this );
-
-/* Invoke the table source function (casting it to the C API first) to
- read the table, and store it in the FitsChan. */
- ( *( void (*)( struct AstFitsChan *, const char *, int, int, int * ) )tabsource )( this_id, extname, extver, extlevel, &lstat );
-
-/* Free the FitsChan identifier (this annuls the supplied "this" pointer). */
- this_id = astAnnulId( this_id );
-
-/* Report an error if the source function failed. */
- if( !lstat ) {
- astError( AST__NOTAB, "astRead(%s): The table source function failed to read "
- "a binary table from extension %s in an external FITS file.",
- status, astGetClass( this ), extname );
- }
-}
-
-static double TDBConv( double mjd, int timescale, int fromTDB,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* TDBConv
-
-* Purpose:
-* Convert an MJD between the TDB time scale and another timescale.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* double TDBConv( double mjd, int timescale, int fromTDB,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function converts the supplied mjd value to or from the TDB
-* timescale.
-
-* Parameters:
-* mjd
-* The input MJD value.
-* timescale
-* The other timescale.
-* fromTDB
-* Indicates the direction of the required conversion. If non-zero,
-* the supplied "mjd" value should be in the TDB timescale, and the
-* returned value will be in the timescale specified by "timescale".
-* If zero, the supplied "mjd" value should be in the timescale
-* specified by "timescale", and the returned value will be in the
-* TDB timescale.
-* method
-* The calling method. Used only in error messages.
-* class
-* The object class. Used only in error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The converted MJD value, or AST__BAD if an error occurs.
-*/
-
-/* Local Variables: */
- AstFrameSet *fs; /* Mapping from supplied timescale to TDB */
- double ret; /* The returned value */
-
-/* Initialise */
- ret = AST__BAD;
-
-/* Check inherited status and supplied TDB value. */
- if( !astOK || mjd == AST__BAD ) return ret;
-
-/* Return the supplied value if no conversion is needed. */
- if( timescale == AST__TDB ) {
- ret = mjd;
-
-/* Otherwise, do the conversion. */
- } else {
-
-/* Lock the timeframes for use by the current thread, waiting if they are
- currently locked by another thread. */
- astManageLock( timeframe, AST__LOCK, 1, NULL );
- astManageLock( tdbframe, AST__LOCK, 1, NULL );
-
-/* Set the required timescale. */
- astSetTimeScale( timeframe, timescale );
-
-/* Get the Mapping between the two timescales, and use it to convert the
- suipplied value. */
- fs = astConvert( tdbframe, timeframe, "" );
- astTran1( fs, 1, &mjd, fromTDB, &ret );
- fs = astAnnul( fs );
-
-/* Unlock the timeframes. */
- astManageLock( timeframe, AST__UNLOCK, 1, NULL );
- astManageLock( tdbframe, AST__UNLOCK, 1, NULL );
- }
-
-/* Return the result */
- return ret;
-}
-
-static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
-/*
-* Name:
-* TestAttrib
-
-* Purpose:
-* Test if a specified attribute value is set for a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int TestAttrib( AstObject *this, const char *attrib, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the astTestAttrib protected
-* method inherited from the Channel class).
-
-* Description:
-* This function returns a boolean result (0 or 1) to indicate whether
-* a value has been set for one of a FitsChan's attributes.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* 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:
-* - 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: */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- int result; /* Result value to return */
-
-/* Initialise. */
- result = 0;
-
-/* Check the global error status. */
- if ( !astOK ) return result;
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_object;
-
-/* Card. */
-/* ----- */
- if ( !strcmp( attrib, "card" ) ) {
- result = astTestCard( this );
-
-/* Encoding. */
-/* --------- */
- } else if ( !strcmp( attrib, "encoding" ) ) {
- result = astTestEncoding( this );
-
-/* FitsAxisOrder. */
-/* -------------- */
- } else if ( !strcmp( attrib, "fitsaxisorder" ) ) {
- result = astTestFitsAxisOrder( this );
-
-/* FitsDigits. */
-/* ----------- */
- } else if ( !strcmp( attrib, "fitsdigits" ) ) {
- result = astTestFitsDigits( this );
-
-/* DefB1950. */
-/* --------- */
- } else if ( !strcmp( attrib, "defb1950" ) ) {
- result = astTestDefB1950( this );
-
-/* TabOK. */
-/* ------ */
- } else if ( !strcmp( attrib, "tabok" ) ) {
- result = astTestTabOK( this );
-
-/* CDMatrix. */
-/* --------- */
- } else if ( !strcmp( attrib, "cdmatrix" ) ) {
- result = astTestCDMatrix( this );
-
-/* CarLin. */
-/* --------- */
- } else if ( !strcmp( attrib, "carlin" ) ) {
- result = astTestCarLin( this );
-
-/* PolyTan */
-/* ------- */
- } else if ( !strcmp( attrib, "polytan" ) ) {
- result = astTestPolyTan( this );
-
-/* Iwc. */
-/* ---- */
- } else if ( !strcmp( attrib, "iwc" ) ) {
- result = astTestIwc( this );
-
-/* Clean. */
-/* ------ */
- } else if ( !strcmp( attrib, "clean" ) ) {
- result = astTestClean( this );
-
-/* Warnings. */
-/* -------- */
- } else if ( !strcmp( attrib, "warnings" ) ) {
- result = astTestWarnings( this );
-
-/* If the name is not recognised, test if it matches any of the
- read-only attributes of this class. If it does, then return
- zero. */
- } else if ( !strcmp( attrib, "ncard" ) ||
- !strcmp( attrib, "nkey" ) ||
- !strcmp( attrib, "cardtype" ) ||
- !strcmp( attrib, "cardcomm" ) ||
- !strcmp( attrib, "cardname" ) ||
- !strcmp( attrib, "allwarnings" ) ){
- result = 0;
-
-/* If the attribute is still 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 int TestCard( AstFitsChan *this, int *status ){
-
-/*
-*+
-* Name:
-* astTestCard
-
-* Purpose:
-* Test the Card attribute.
-
-* Type:
-* Protected virtual function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int astTestCard( AstFitsChan *this )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function tests the Card attribute for the supplied FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-
-* Returned Value:
-* If the Card attribute has its "cleared" value (i.e. if the first card
-* in the FitsChan will be the next one to be read), then zero is returned,
-* otherwise 1 is returned.
-*-
-*/
-
-/* Local Variables: */
- int card; /* The original value of Card */
- int ret; /* The returned flag */
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Get the current value of Card. */
- card = astGetCard( this );
-
-/* Temporarily clear Card. */
- astClearCard( this );
-
-/* See if the original Card is equal to the cleared card, and set the
- returned flag appropriately. Re-instate the original value of card is
- required.*/
- if( astGetCard( this ) == card ) {
- ret = 0;
- } else {
- astSetCard( this, card );
- ret = 1;
- }
-
-/* Return the flag. */
- return ret;
-}
-
-static int TestFits( AstFitsChan *this, const char *name, int *there,
- int *status ){
-
-/*
-*++
-* Name:
-c astTestFits
-f AST_TESTFITS
-
-* Purpose:
-* See if a named keyword has a defined value in a FitsChan.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-
-c int astTestFits( AstFitsChan *this, const char *name, int *there )
-f RESULT = AST_TESTFITS( THIS, NAME, THERE, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-* This function serches for a named keyword in a FitsChan. If found,
-* and if the keyword has a value associated with it, a
-c non-zero
-f .TRUE.
-* value is returned. If the keyword is not found, or if it does not
-* have an associated value, a
-c zero
-f .FALSE.
-* value is returned.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-c name
-f NAME = CHARACTER * ( * ) (Given)
-c Pointer to a null-terminated character string
-f A character string
-* containing the FITS keyword name. This may be a complete FITS
-* header card, in which case the keyword to use is extracted from
-* it. No more than 80 characters are read from this string.
-c there
-f THERE = LOGICAL (Returned)
-c Pointer to an integer which will be returned holding a non-zero
-c value if the keyword was found in the header, and zero otherwise.
-f A value of .TRUE. will be returned if the keyword was found in the
-f header, and .FALSE. otherwise.
-* This parameter allows a distinction to be made between the case
-* where a keyword is not present, and the case where a keyword is
-* present but has no associated value.
-c A NULL pointer may be supplied if this information is not
-c required.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astTestFits()
-f AST_TESTFITS = LOGICAL
-* A value of zero
-f .FALSE.
-* is returned if the keyword was not found in the FitsChan or has
-* no associated value. Otherwise, a value of
-c one
-f .TRUE.
-* is returned.
-
-* Notes:
-* - The current card is left unchanged by this function.
-* - The card following the current card is checked first. If this is
-* not the required card, then the rest of the FitsChan is searched,
-* starting with the first card added to the FitsChan. Therefore cards
-* should be accessed in the order they are stored in the FitsChan (if
-* possible) as this will minimise the time spent searching for cards.
-* - An error will be reported if the keyword name does not conform
-* to FITS requirements.
-c - Zero
-f - .FALSE.
-* is returned as the function value if an error has already occurred,
-* or if this function should fail for any reason.
-*--
-*/
-
-/* Local Variables: */
- const char *class; /* Object class */
- const char *method; /* Calling method */
- char *lcom; /* Supplied keyword comment */
- char *lname; /* Supplied keyword name */
- char *lvalue; /* Supplied keyword value */
- int icard; /* Current card index on entry */
- int ret; /* The returned value */
-
-/* Initialise */
- if( there ) *there = 0;
-
-/* Check the global error status. */
- if ( !astOK ) return 0;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Store the calling method and object class. */
- method = "astTestFits";
- class = astGetClass( this );
-
-/* Initialise the returned value. */
- ret = 0;
-
-/* Extract the keyword name from the supplied string. */
- (void) Split( this, name, &lname, &lvalue, &lcom, method, class, status );
-
-/* Store the current card index. */
- icard = astGetCard( this );
-
-/* Attempt to find a card in the FitsChan refering to this keyword,
- and make it the current card. Only proceed if a card was found. */
- if( SearchCard( this, lname, method, class, status ) ){
-
-/* Indicate the card has been found. */
- if( there ) *there = 1;
-
-/* If the cards data type is no undefined, return 1. */
- if( CardType( this, status ) != AST__UNDEF ) ret = 1;
- }
-
-/* Re-instate the original current card index. */
- astSetCard( this, icard );
-
-/* Release the memory used to hold keyword name, value and comment strings. */
- lname = (char *) astFree( (void *) lname );
- lvalue = (char *) astFree( (void *) lvalue );
- lcom = (char *) astFree( (void *) lcom );
-
-/* Return the answer. */
- return ret;
-}
-
-static void TidyOffsets( AstFrameSet *fset, int *status ) {
-/*
-* Name:
-* TidyOffsets
-
-* Purpose:
-* Remove un-needed offset coordinate Frames.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void TidyOffsets( AstFrameSet *fset, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FITS header stores offset sky coordinates as two alternaive axis
-* descriptions - one giving the offset axes and one giving the absolute
-* axes. But AST can hold both forms in a single SkyFrame. This function
-* removes the FITS Frames describing offset axes from the FrameSet.
-* The remaining absolute Frame is then used to describe both absolute
-* and offset.
-
-* Parameters:
-* fset
-* A FrameSet holding the Frames read from a FITS-WCS Header.
-* status
-* Pointer to the inherited status variable.
-*/
-
-/* Local Variables: */
- AstFrame *frm;
- AstFrame *pfrm;
- const char *dom;
- const char *skyrefis;
- int hasabs;
- int hasoff;
- int iax;
- int icurr;
- int icurr_is_offset;
- int ifrm;
- int nax;
- int nfrm;
- int pax;
- int remove;
-
-/* Check the inherited status. */
- if( !astOK ) return;
-
-/* Note the original current Frame index. */
- icurr = astGetCurrent( fset );
-
-/* Assume the current Frame is not an offset frame until proven
- otherwise. */
- icurr_is_offset = 0;
-
-/* Does the FrameSet contain any Frames holding sky offsets? Such Frames
- should have been given a Domain of SKY_OFFSETS within function
- WcsSkyFrame. Loop round all Frames, checking each one. Also note if
- the FrameSet contains any (absolute) SKY frames. Also set the SkyRefIs
- attribute for any absolute SkyFrames that were marked with domains
- SKY_POLE or SKY_OFFSET in WcsSkyFrame. */
- hasabs = 0;
- hasoff = 0;
- nfrm = astGetNframe( fset );
- for( ifrm = 1; ifrm <= nfrm; ifrm++ ){
- skyrefis = NULL;
- frm = astGetFrame( fset, ifrm );
- nax = astGetNaxes( frm );
- for( iax = 0; iax < nax; iax++ ) {
- astPrimaryFrame( frm, iax, &pfrm, &pax );
- if( IsASkyFrame( pfrm ) ) {
- dom = astGetDomain( pfrm );
- if( dom ) {
- if( !strcmp( dom, "SKY_OFFSETS" ) ){
- hasoff = 1;
- if( ifrm == icurr ) icurr_is_offset = 1;
- iax = nax;
- } else if( !strcmp( dom, "SKY" ) ){
- hasabs = 1;
- iax = nax;
- } else if( !strcmp( dom, "SKY_POLE" ) ){
- hasabs = 1;
- skyrefis = "POLE";
- iax = nax;
- } else if( !strcmp( dom, "SKY_ORIGIN" ) ){
- hasabs = 1;
- skyrefis = "ORIGIN";
- iax = nax;
- }
- }
- }
- pfrm = astAnnul( pfrm );
- }
- frm = astAnnul( frm );
-
- if( skyrefis ) {
- astSetI( fset, "Current", ifrm);
- astSetC( fset, "SkyRefIs", skyrefis );
- astSetI( fset, "Current", icurr );
- }
- }
-
-/* If one or more absolute sky frames were found, then remove any offset
- sky frames. Clear the Ident attribute (that holds the FITS-WCS alternate
- axis description character) for any absoute Frames. */
- if( hasabs && hasoff ) {
-
- for( ifrm = nfrm; ifrm > 0; ifrm-- ) {
- remove = 0;
- frm = astGetFrame( fset, ifrm );
- nax = astGetNaxes( frm );
- for( iax = 0; iax < nax; iax++ ) {
- astPrimaryFrame( frm, iax, &pfrm, &pax );
- if( IsASkyFrame( pfrm ) ) {
- dom = astGetDomain( pfrm );
- if( dom ) {
- if( !strcmp( dom, "SKY_OFFSETS" ) ){
- remove = 1;
- iax = nax;
-
- } else if( !strcmp( dom, "SKY_POLE" ) ||
- !strcmp( dom, "SKY_ORIGIN" ) ){
- astClearIdent( frm );
- astClearDomain( pfrm );
-
-/* If we will be deleting the original current Frame (because it is an
- offset Frame), then mark the first absolute Frame as the new current
- Frame. */
- if( icurr_is_offset ) {
- astSetCurrent( fset, ifrm );
- icurr_is_offset = 0;
- }
- iax = nax;
- }
- }
- }
- pfrm = astAnnul( pfrm );
- }
- frm = astAnnul( frm );
-
- if( remove ) astRemoveFrame( fset, ifrm );
- }
- }
-}
-
-static AstTimeScaleType TimeSysToAst( AstFitsChan *this, const char *timesys,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* TimeSysToAst
-
-* Purpose:
-* Convert a FITS TIMESYS value to an AST TimeFrame timescale value.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstTimeScaleType TimeSysToAst( AstFitsChan *this, const char *timesys,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function returns the value used by the AST TimeFrame class to
-* represent the timescale specified by the "timesys" parameter, which
-* should hold the value of a FITS TIMESYS keyword. The TIMESYS
-* convention was introduced as part of the Y2K DATE-OBS changes, and
-* is not currently part of the published FITS-WCS conventions.
-*
-* If the requested timescale is not supported by AST, then a warning is
-* added to the FitsChan and a value of AST__UTC is returned (but no
-* error is reported).
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* timesys
-* Pointer to the string holding the TIMESYS value. A NULL pointer
-* returns the default timescale of UTC.
-* 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:
-* The equivalent AstTimeScaleType value.
-*/
-
-/* Local Variables: */
- AstTimeScaleType result; /* The returned timescale */
- char buf[ 200 ]; /* Buffer for warning message */
-
-/* Initialise */
- result = AST__UTC;
-
-/* Check the inherited status. */
- if( !astOK ) return result;
- if( !timesys ) {
- result = AST__UTC;
- } else if( !strcmp( timesys, "UTC" ) ) {
- result = AST__UTC;
- } else if( !strcmp( timesys, "UT" ) ) {
- result = AST__UTC;
- Warn( this, "badval", "The original FITS header contained a value of UT "
- "for keyword TIMESYS which is being interpreted as UTC.", method,
- class, status );
- } else if( !strcmp( timesys, "TAI" ) ) {
- result = AST__TAI;
- } else if( !strcmp( timesys, "IAT" ) ) {
- result = AST__TAI;
- } else if( !strcmp( timesys, "ET" ) ) {
- result = AST__TT;
- Warn( this, "badval", "The original FITS header contained a value of ET "
- "for keyword TIMESYS. TT will be used instead.", method, class, status );
- } else if( !strcmp( timesys, "TT" ) ) {
- result = AST__TT;
- } else if( !strcmp( timesys, "TDT" ) ) {
- result = AST__TT;
- } else if( !strcmp( timesys, "TDB" ) ) {
- result = AST__TDB;
- } else if( !strcmp( timesys, "TCG" ) ) {
- result = AST__TCG;
- } else if( !strcmp( timesys, "TCB" ) ) {
- result = AST__TCB;
- } else {
- result = AST__UTC;
- sprintf( buf, "The original FITS header contained a value of %s for "
- "keyword TIMESYS. AST does not support this timescale so "
- "UTC will be used instead.", timesys );
- Warn( this, "badval", buf, method, class, status );
- }
-
-/* Return the result */
- return result;
-}
-
-static char *UnPreQuote( const char *string, int *status ) {
-/*
-* Name:
-* UnPreQuote
-
-* Purpose:
-* Reverse the pre-quoting of FITS character data.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* char *UnPreQuote( const char *string, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function reverses the effect of the PreQuote function on a
-* string (apart from any loss of data due to truncation). It
-* should be used to recover the original character data from the
-* pre-quoted version of a string retrieved from a FITS character
-* value associated with a keyword.
-
-* Parameters:
-* string
-* Pointer to a constant null-terminated string containing the
-* pre-quoted character data.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Pointer to a dynamically allocated null-terminated string
-* containing the un-quoted character data. The memory holding this
-* string should be freed by the caller (using astFree) when no
-* longer required.
-
-* Notes:
-* - A NULL pointer value will be returned if this function is
-* invoked wth the global error status set, or if it should fail
-* for any reason.
-*/
-
-/* Local Variables: */
- char *result; /* Pointer value to return */
- int i1; /* Offset of first useful character */
- int i2; /* Offest of last useful character */
-
-/* Check the global error status. */
- if ( !astOK ) return NULL;
-
-/* Initialise to use the first and last characters in the input
- string. */
- i1 = 0;
- i2 = strlen( string ) - 1;
-
-/* If the string contains at least 2 characters, check if the first
- and last characters are double quotes ("). If so, adjust the
- offsets to exclude them. */
- if ( ( i2 > i1 ) &&
- ( string[ i1 ] == '"' ) && ( string[ i2 ] == '"' ) ) {
- i1++;
- i2--;
- }
-
-/* Make a dynamically allocated copy of the useful part of the
- string. */
- result = astString( string + i1, i2 - i1 + 1 );
-
-/* Return the answer. */
- return result;
-}
-
-static int Use( AstFitsChan *this, int set, int helpful, int *status ) {
-
-/*
-* Name:
-* Use
-
-* Purpose:
-* Decide whether to write a value to a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int Use( AstFitsChan *this, int set, int helpful, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* This function decides whether a value supplied by a class "Dump"
-* function, via a call to one of the astWrite... protected
-* methods, should actually be written to a FitsChan.
-*
-* This decision is based on the settings of the "set" and
-* "helpful" flags supplied to the astWrite... method, plus the
-* attribute settings of the FitsChan.
-
-* Parameters:
-* this
-* A pointer to the FitsChan.
-* set
-* The "set" flag supplied.
-* helpful
-* The "helpful" value supplied.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* One if the value should be written out, otherwise zero.
-
-* Notes:
-* - A value of zero will be returned if this function is invoked
-* with the global error status set or if it should fail for any
-* reason.
-*/
-
-/* Local Variables: */
- int full; /* Full attribute value */
- int result; /* Result value to be returned */
-
-/* Check the global error status. */
- if ( !astOK ) return 0;
-
-/* If "set" is non-zero, then so is the result ("set" values must
- always be written out). */
- result = ( set != 0 );
-
-/* Otherwise, obtain the value of the FitsChan's Full attribute. */
- if ( !set ) {
- full = astGetFull( this );
-
-/* If Full is positive, display all values, if zero, display only
- "helpful" values, if negative, display no (un-"set") values. */
- if ( astOK ) result = ( ( helpful && ( full > -1 ) ) || ( full > 0 ) );
- }
-
-/* Return the result. */
- return result;
-}
-
-static int Ustrcmp( const char *a, const char *b, int *status ){
-/*
-* Name:
-* Ustrcmp
-
-* Purpose:
-* A case blind version of strcmp.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int Ustrcmp( const char *a, const char *b, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns 0 if there are no differences between the two strings, and 1
-* otherwise. Comparisons are case blind.
-
-* Parameters:
-* a
-* Pointer to first string.
-* b
-* Pointer to second string.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero if the strings match, otherwise one.
-
-* Notes:
-* - This function does not consider the sign of the difference between
-* the two strings, whereas "strcmp" does.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- const char *aa; /* Pointer to next "a" character */
- const char *bb; /* Pointer to next "b" character */
- int ret; /* Returned value */
-
-/* Initialise the returned value to indicate that the strings match. */
- ret = 0;
-
-/* Initialise pointers to the start of each string. */
- aa = a;
- bb = b;
-
-/* Loop round each character. */
- while( 1 ){
-
-/* We leave the loop if either of the strings has been exhausted. */
- if( !(*aa ) || !(*bb) ){
-
-/* If one of the strings has not been exhausted, indicate that the
- strings are different. */
- if( *aa || *bb ) ret = 1;
-
-/* Break out of the loop. */
- break;
-
-/* If neither string has been exhausted, convert the next characters to
- upper case and compare them, incrementing the pointers to the next
- characters at the same time. If they are different, break out of the
- loop. */
- } else {
- if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){
- ret = 1;
- break;
- }
- }
- }
-
-/* Return the result. */
- return ret;
-}
-
-static int Ustrncmp( const char *a, const char *b, size_t n, int *status ){
-/*
-* Name:
-* Ustrncmp
-
-* Purpose:
-* A case blind version of strncmp.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int Ustrncmp( const char *a, const char *b, size_t n, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* Returns 0 if there are no differences between the first "n"
-* characters of the two strings, and 1 otherwise. Comparisons are
-* case blind.
-
-* Parameters:
-* a
-* Pointer to first string.
-* b
-* Pointer to second string.
-* n
-* The maximum number of characters to compare.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Zero if the strings match, otherwise one.
-
-* Notes:
-* - This function does not consider the sign of the difference between
-* the two strings, whereas "strncmp" does.
-* - This function attempts to execute even if an error has occurred.
-*/
-
-/* Local Variables: */
- const char *aa; /* Pointer to next "a" character */
- const char *bb; /* Pointer to next "b" character */
- int i; /* Character index */
- int ret; /* Returned value */
-
-/* Initialise the returned value to indicate that the strings match. */
- ret = 0;
-
-/* Initialise pointers to the start of each string. */
- aa = a;
- bb = b;
-
-/* Compare up to "n" characters. */
- for( i = 0; i < (int) n; i++ ){
-
-/* We leave the loop if either of the strings has been exhausted. */
- if( !(*aa ) || !(*bb) ){
-
-/* If one of the strings has not been exhausted, indicate that the
- strings are different. */
- if( *aa || *bb ) ret = 1;
-
-/* Break out of the loop. */
- break;
-
-/* If neither string has been exhausted, convert the next characters to
- upper case and compare them, incrementing the pointers to the next
- characters at the same time. If they are different, break out of the
- loop. */
- } else {
- if( toupper( (int) *(aa++) ) != toupper( (int) *(bb++) ) ){
- ret = 1;
- break;
- }
- }
- }
-
-/* Return the result. */
- return ret;
-}
-
-static void Warn( AstFitsChan *this, const char *condition, const char *text,
- const char*method, const char *class, int *status ){
-/*
-* Name:
-* Warn
-
-* Purpose:
-* Store warning cards in a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int Warn( AstFitsChan *this, const char *condition, const char *text,
-* const char*method, const char *class, int *status );
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* If the Warnings attribute indicates that occurences of the specified
-* condition should be reported, the supplied text is split into lines
-* and stored in the FitsChan as a series of ASTWARN cards, in front
-* of the current card. If the specified condition is not being reported,
-* this function returns without action.
-
-* Parameters:
-* this
-* The FitsChan. If NULL, this function returns without action.
-* condition
-* Pointer to a string holding a lower case condition name.
-* text
-* Pointer to a string holding the text of the warning.
-* 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.
-*/
-
-/* Local Variables: */
- char buff[ AST__FITSCHAN_FITSCARDLEN + 1 ]; /* Buffer for new card text */
- const char *a; /* Pointer to 1st character in next card */
- const char *b; /* Pointer to terminating null character */
- const char *c; /* Pointer to last character in next card */
- int exists; /* Has the supplied warning already been issued? */
- int icard; /* Index of original card */
- int nc; /* No. of characters in next card */
-
-/* Check the inherited status, warning text, FitsChan and Clean attribute. */
- if( !astOK || !text || !text[0] || !this || astGetClean( this ) ) return;
-
-/* Ignore the warning if the supplied condition is not contained within
- the list of conditions to be reported in this way (given by the
- Warnings attribute). */
- if( FullForm( astGetWarnings( this ), condition, 0, status ) >= 0 ){
-
-/* If found, store the warning in the parent Channel structure. */
- astAddWarning( this, 1, "%s", method, status, text );
-
-/* For historical reasons, warnings are also stored in the FitsChan as a
- set of FITS cards... First save the current card index, and rewind the
- FitsChan. */
- icard = astGetCard( this );
- astClearCard( this );
-
-/* Break the supplied text into lines and check the FitsChan to see if
- a block of adjacent ASTWARN cards with these lines already exist
- within the FitsChan. Assume they do until proven otherwise. */
- exists = 1;
- a = text;
- b = a + strlen( text );
- while( a < b ){
-
-/* Each card contains about 60 characters of the text. Get a pointer to
- the nominal last character in the next card. */
- c = a + 60;
-
-/* If this puts the last character beyond the end of the text, use the
- last character before the null as the last character in the card. */
- if( c >= b ) {
- c = b - 1;
-
-/* Otherwise, if the last character is not a space, move the last
- character backwards to the first space. This avoids breaking words
- across cards. */
- } else {
- while( !isspace( *c ) && c > a ) c--;
- }
-
-/* Copy the text into a null terminated buffer. */
- nc = c - a + 1;
- strncpy( buff, a, nc );
- buff[ nc ] = 0;
-
-/* If this is the first line, search the entire FitsChan for an ASTWARN card
- with this text. If not, indiate that the supplied text needs to be
- stored in the FitsChan, and break out of the loop. */
- if( a == text ) {
- exists = 0;
- while( !exists &&
- FindKeyCard( this, "ASTWARN", method, class, status ) ) {
- if( !strcmp( (const char *) CardData( this, NULL, status ), buff ) ) {
- exists = 1;
- }
- MoveCard( this, 1, method, class, status );
- }
- if( !exists ) break;
-
-/* If this is not the first line, see if the next card in the FitsChan is
- an ASTWARN card with this text. If not, indiate that the supplied text
- needs to be stored in the FitsChan, and break out of the loop. */
- } else {
- if( !strcmp( CardName( this, status ), "ASTWARN" ) &&
- !strcmp( (const char *) CardData( this, NULL, status ), buff ) ) {
- MoveCard( this, 1, method, class, status );
- } else {
- exists = 0;
- break;
- }
- }
-
-/* Set the start of the next bit of the text. */
- a = c + 1;
- }
-
-/* Reinstate the original current card index. */
- astSetCard( this, icard );
-
-/* We only add new cards to the FitsChan if they do not already exist. */
- if( !exists ) {
-
-/* Break the text into lines using the same algorithm as above, and store
- each line as a new ASTWARN card. Start with a blank ASTWARN card. */
- astSetFitsS( this, "ASTWARN", " ", NULL, 0 );
-
-/* Loop until the entire text has been written out. */
- a = text;
- b = a + strlen( text );
- while( a < b ){
-
-/* Each card contains about 60 characters of the text. Get a pointer to
- the nominal last character in the next card. */
- c = a + 60;
-
-/* If this puts the last character beyond the end of the text, use the
- last character before the null as the last character in the card. */
- if( c >= b ) {
- c = b - 1;
-
-/* Otherwise, if the last character is not a space, move the last
- character backwards to the first space. This avoids breaking words
- across cards. */
- } else {
- while( !isspace( *c ) && c > a ) c--;
- }
-
-/* Copy the text into a null terminated buffer. */
- nc = c - a + 1;
- strncpy( buff, a, nc );
- buff[ nc ] = 0;
-
-/* Store the buffer as the next card. */
- astSetFitsS( this, "ASTWARN", buff, NULL, 0 );
-
-/* Set the start of the next bit of the text. */
- a = c + 1;
- }
-
-/* Include a final blank card. */
- astSetFitsS( this, "ASTWARN", " ", NULL, 0 );
- }
- }
-}
-
-static int WATCoeffs( const char *watstr, int iaxis, double **cvals,
- int **mvals, int *ok, int *status ){
-/*
-* Name:
-* WATCoeffs
-
-* Purpose:
-* Get the polynomial coefficients from the lngcor or latcor component
-* of an IRAF WAT string.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int WATCoeffs( const char *watstr, int iaxis, double **cvals,
-* int **mvals, int *ok, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function extracts the polynomial coefficients from a supplied
-* string containing the concatenated values of a set of IRAF "WAT"
-* keywords, such as used for the IRAF-specific TNX and ZPX projections.
-* The coefficients are returned in the form of a set of PVi_m values
-* for a TPN projection.
-
-* Parameters:
-* watstr
-* The concatentated WAT keyword values.
-* iaxis
-* Zero based index of the axis to which the WAT keywords refer (0
-* or 1).
-* cvals
-* Location at which to return a pointer to a dynamically allocated
-* list of coefficient values, or NULL if no lngcor/latcor values
-* were found in the WAT string. Free using astFree.
-* mvals
-* Location at which to return a pointer to a dynamically allocated
-* list of coefficient indices, or NULL if no lngcor/latcor values
-* were found in the WAT string. Free using astFree.
-* ok
-* Pointer to an in which is returned set to zero if the polynomial
-* in the supplied WAT string cannot be represented using TPN form.
-* Non-zero otherwise.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The size of the returned cvals and mvals arrays.
-
-*/
-
-/* Local Variables: */
- char **w1;
- char **w2;
- double *coeff;
- double *pc;
- int result;
- double dval;
- double etamax;
- double etamin;
- double ximax;
- double ximin;
- int cheb;
- int etaorder;
- int iword;
- int m;
- int mn;
- int nword;
- int order;
- int porder;
- int xiorder;
- int ires;
-
-/* The number of lngcor/latcor values needed for each order. */
- static const int nab[] = {1,3,6,10,15,21,28,36};
-
-/* Initialise the pointer to the returned Mapping. */
- result = 0;
- *mvals = NULL;
- *cvals = NULL;
- *ok = 1;
-
-/* Other initialisation to avoid compiler warnings. */
- etamin = 0.0;
- etamax = 0.0;
- ximax = 0.0;
- ximin = 0.0;
- order = 0;
-
-/* Check the global status. */
- if ( !astOK || !watstr ) return result;
-
-/* Look for cor = "..." and extract the "..." string. */
- w1 = astChrSplitRE( watstr, "cor *= *\"(.*)\"", &nword, NULL );
- if( w1 ) {
-
-/* Split the "..." string into words. */
- w2 = astChrSplit( w1[ 0 ], &nword );
- if( w2 ) {
-
-/* Initialise flags. */
- cheb = 0;
- xiorder = 0;
- etaorder = 0;
- coeff = NULL;
- porder = -1;
-
-/* Loop round each word. Break early if we find that the projection
- cannot be represented as a TPN projection. */
- for( iword = 0; iword < nword && *ok; iword++ ) {
-
-/* Convert the word to double. */
- dval = astChr2Double( w2[ iword ] );
- if( dval == AST__BAD ) {
- astError( AST__BDFTS, "astRead(FitsChan): Failed to read a "
- "numerical value from sub-string \"%s\" found in "
- "an IRAF \"WAT...\" keyword.", status, w2[ iword ] );
- break;
- }
-
-/* The first value gives the correction surface type. We can only handle type
- 1 (chebyshev) or 3 (simple polynomial). */
- if( iword == 0 ){
- if( dval == 1.0 ) {
- cheb = 1;
- } else if( dval == 2.0 ) {
- *ok = 0;
- }
-
-/* The second and third numbers gives the orders of the polynomial in X
- and Y. We can only handle cases in which the orders are the same on
- both axes, and greater than 0 and less than 8. Store a pointer to the
- first TAN projection parameter index to use. */
- } else if( iword == 1 ){
- order = dval;
- porder = order - 1;
-
- } else if( iword == 2 ){
- if( dval - 1 != porder || dval < 0 || dval > 7 ) *ok = 0;
-
-/* The fourth number defines the type of cross-terms. We can only handle
- type 2 (half-cross terms). */
- } else if( iword == 3 ){
- if( dval != 2.0 ) *ok = 0;
-
-/* We now know the maximum number of co-efficients that may be needed.
- Allocate memory to hold them, and fill it with zeros. They are
- stored in this array as if full cross-terms have been supplied (the
- unspecified coefficients retain their initialised value of zero). */
- coeff = astCalloc( order*order, sizeof( double ) );
- if( !astOK ) break;
-
-/* The next 4 numbers describe the region of validity of the fits in IRAF's
- xi and eta space, e.g. ximin, ximax, etamin, etamax. We only uses
- these if we have a chebyshev polynomial. */
- } else if( iword == 4 ) {
- ximin = dval;
-
- } else if( iword == 5 ) {
- ximax = dval;
-
- } else if( iword == 6 ) {
- etamin = dval;
-
- } else if( iword == 7 ) {
- etamax = dval;
-
-/* The remaining terms are the coefficients of the polynomial terms. */
- } else if( iword > 7 ){
-
-/* Store the coefficient in the array. They are stored so that power of
- xi increases fastest. */
- coeff[ xiorder + order*etaorder ] = dval;
-
-/* Increment the powers of the next coefficient. We know we only have half
- cross-terms, so the maximum power of xi decreases from order to zero
- as we move through the list of coefficients. */
- if( ++xiorder == order - etaorder ) {
- xiorder = 0;
- etaorder++;
- }
- }
- }
-
-/* Check that all the required co-efficients were found */
- if( porder == -1 || nword != 8 + nab[ porder ] ) *ok = 0;
-
-/* If we can handle the projection, proceed. */
- if( *ok && astOK ) {
-
-/* If the coefficients were supplied in chebyshev form, convert to simple
- form. */
- if( cheb ) {
- double *tcoeff = coeff;
- coeff = Cheb2Poly( tcoeff, order, order, ximin,
- ximax, etamin, etamax, status );
- tcoeff = astFree( tcoeff );
- }
-
-/* The polynomials provide a "correction* to be added to the supplied X and
- Y values. Therefore increase the linear co-efficients by 1 on the axis
- that is being calculated. */
- coeff[ iaxis ? order : 1 ] += 1.0;
-
-/* Loop round all coefficients, keeping track of the power of xi and eta
- for the current coefficient. */
- pc = coeff;
- for( etaorder = 0; etaorder < order; etaorder++ ) {
- for( xiorder = 0; xiorder < order; xiorder++,pc++ ) {
-
-/* Skip coefficients that have their default values (zero, except for the
- linear coefficients which default to 1.0). */
- mn = xiorder + etaorder;
- if( *pc != ( mn == 1 ? 1.0 : 0.0 ) ) {
-
-/* Find the "m" index of the PVi_m FITS keyword for the current
- coefficient. */
- m = mn*( 1 + mn )/2 + mn/2;
- m += iaxis ? xiorder : etaorder;
-
-/* Append the PV and m values to the ends of the returned arrays. */
- ires = result++;
- *cvals = astGrow( *cvals, sizeof( double ), result );
- *mvals = astGrow( *mvals, sizeof( int ), result );
- if( astOK ) {
- (*cvals)[ ires ] = *pc;
- (*mvals)[ ires ] = m;
- }
- }
- }
- }
-
-/* Free coefficients arrays */
- coeff = astFree( coeff );
- }
-
-/* Free resources */
- w2 = astFree( w2 );
- }
- w1 = astFree( w1 );
- }
-
-/* Return the result. */
- return result;
-}
-
-static AstMatrixMap *WcsCDeltMatrix( FitsStore *store, char s, int naxes,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* WcsCDeltMatrix
-
-* Purpose:
-* Create a MatrixMap representing the CDELT scaling.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstMatrixMap *WcsCDeltMatrix( FitsStore *store, char s, int naxes,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A diagonal MatrixMap representing the FITS "CDELT" keywords is
-* returned.
-
-* Parameters:
-* store
-* A structure containing values for FITS keywords relating to
-* the World Coordinate System.
-* s
-* A character s identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* naxes
-* The number of intermediate world coordinate axes (WCSAXES).
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the created MatrixMap or a NULL pointer if an
-* error occurred.
-*/
-
-/* Local Variables: */
- AstMatrixMap *new; /* The created MatrixMap */
- double *el; /* Pointer to next matrix element */
- double *mat; /* Pointer to matrix array */
- int i; /* Pixel axis index */
-
-/* Initialise/ */
- new = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return new;
-
-/* Allocate memory for the diagonal matrix elements. */
- mat = (double *) astMalloc( sizeof(double)*naxes );
- if( astOK ){
-
-/* Fill the matrix diagonal with values from the FitsStore. */
- el = mat;
- for( i = 0; i < naxes; i++ ){
-
-/* Get the CDELTi value for this axis. Missing terms can be defaulted so
- do not report an error if the required value is not present in the
- FitsStore. */
- *el = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
-
-/* Missing terms default to to 1.0. */
- if( *el == AST__BAD ) *el = 1.0;
-
-/* Move on to the next matrix element. */
- el++;
- }
-
-/* Create the diagional matrix. */
- new = astMatrixMap( naxes, naxes, 1, mat, "", status );
-
-/* Report an error if the inverse transformation is undefined. */
- if( !astGetTranInverse( new ) && astOK ) {
- astError( AST__BDFTS, "%s(%s): Unusable CDELT values found "
- "in the FITS-WCS header - one or more values are zero.", status, method, class );
- }
-
-/* Release the memory used to hold the matrix. */
- mat = (double *) astFree( (void *) mat );
- }
-
-/* If an error has occurred, attempt to annul the returned MatrixMap. */
- if( !astOK ) new = astAnnul( new );
-
-/* Return the MatrixMap. */
- return new;
-}
-
-static AstMapping *WcsCelestial( AstFitsChan *this, FitsStore *store, char s,
- AstFrame **frm, AstFrame *iwcfrm, double *reflon, double *reflat,
- AstSkyFrame **reffrm, AstMapping **tabmap,
- int *tabaxis, const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* WcsCelestial
-
-* Purpose:
-* Create a Mapping from intermediate world coords to celestial coords
-* as described in a FITS header.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstMapping *WcsCelestial( AstFitsChan *this, FitsStore *store, char s,
-* AstFrame **frm, AstFrame *iwcfrm, double *reflon, double *reflat,
-* AstSkyFrame **reffrm, , AstMapping **tabmap,
-* int *tabaxis, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function interprets the contents of the supplied FitsStore
-* structure, looking for world coordinate axes which describe positions
-* on the sky. If a pair of such longitude/latitude axes is found, a
-* Mapping is returned which transforms the corresponding intermediate
-* world coordinates to celestial world coordinates (this mapping leaves
-* any other axes unchanged). It also, modifies the supplied Frame to
-* describe the axes (again, other axes are left unchanged). If no
-* pair of celestial axes is found, a UnitMap is returned, and the
-* supplied Frame is left unchanged.
-
-* Parameters:
-* this
-* The FitsChan.
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* frm
-* The address of a location at which to store a pointer to the
-* Frame describing the world coordinate axes.
-* iwcfrm
-* A pointer to the Frame describing the intermediate world coordinate
-* axes. The properties of this Frame may be changed on exit.
-* reflon
-* Address of a location at which to return the celestial longitude
-* at the reference point. It is returned as AST__BAD if no
-* celestial coordinate frame is found.
-* reflat
-* Address of a location at which to return the celestial latitude
-* at the reference point. It is returned as AST__BAD if no
-* celestial coordinate frame is found.
-* reffrm
-* Address of a location at which to return a pointer to a SkyFrame
-* which define the reference values returned in reflon and reflat.
-* It is returned as NULL if no celestial coordinate frame is found.
-* tabmap
-* Address of a pointer to a Mapping describing any -TAB
-* transformations to be applied to the results of the Mapping returned
-* by this function. If any celestial axes are found, the supplied
-* Mapping is modified so that the celestial axes produce values in
-* radians rather than degrees. NULL if no axes are described by -TAB.
-* tabaxis
-* Pointer to an array of flags, one for each WCS axis, indicating
-* if the corresponding WCS axis is described by the -TAB algorithm.
-* NULL if no axes are described by -TAB.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the Mapping.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFrame *ofrm; /* Pointer to a Frame */
- AstMapping *map1; /* Pointer to a Mapping */
- AstMapping *map2; /* Pointer to a Mapping */
- AstMapping *map3; /* Pointer to a Mapping */
- AstMapping *map4; /* Pointer to a Mapping */
- AstMapping *ret; /* Pointer to the returned Mapping */
- AstMapping *newmap; /* Modified PIXEL->IWC Mapping */
- AstMapping *shiftmap; /* ShiftMap from IWC to PPC */
- AstSkyFrame *sfrm; /* Pointer to a SkyFrame */
- char *ctype; /* Pointer to CTYPE string */
- char *keyname; /* Pointer to keyword name string */
- char buf[300]; /* Text buffer */
- char latctype[MXCTYPELEN];/* Latitude CTYPE keyword value */
- char latkey[10]; /* Latitude CTYPE keyword name */
- char lattype[4]; /* Buffer for celestial system */
- char lonctype[MXCTYPELEN];/* Longitude CTYPE keyword value */
- char lonkey[10]; /* Longitude CTYPE keyword name */
- char lontype[4]; /* Buffer for celestial system */
- double *shifts; /* Array holding axis shifts */
- double *ina; /* Pointer to memory holding input position A */
- double *inb; /* Pointer to memory holding input position B */
- double *mat; /* Pointer to data for deg->rad scaling matrix */
- double *outa; /* Pointer to memory holding output position A */
- double *outb; /* Pointer to memory holding output position B */
- double latval; /* CRVAL for latitude axis */
- double lonval; /* CRVAL for longitude axis */
- double pv; /* Projection parameter value */
- double x0; /* IWC X at the projection fiducial point */
- double y0; /* IWC Y at the projection fiducial point */
- int *axes; /* Point to a list of axis indices */
- int axlat; /* Index of latitude physical axis */
- int axlon; /* Index of longitude physical axis */
- int carlin; /* Assume native and WCS axes are the same? */
- int ctlen; /* Length of CTYPE string */
- int gotax; /* Celestial axis found? */
- int i; /* Loop count */
- int j; /* Axis index */
- int latprj; /* Latitude projection type identifier */
- int lonprj; /* Longitude projection type identifier */
- int m; /* Parameter index */
- int mxpar_lat; /* Max. projection parameter index on lat axis */
- int mxpar_lon; /* Max. projection parameter index on lon axis */
- int naxes; /* Number of axes */
- int nc; /* String length */
- int np; /* Max parameter index */
- int prj; /* Projection type identifier */
-
-/* Initialise the returned values. */
- ret = NULL;
- *reflon = AST__BAD;
- *reflat = AST__BAD;
- *reffrm = NULL;
-
-/* Other initialisation to avoid compiler warnings. */
- map1 = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return ret;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* Get the number of physical axes. */
- naxes = astGetNaxes( *frm );
-
-/* See if CAR projections should be interpreted in the old fashioned way
- (i.e native coords are always the same as WCS coords, so no need for
- any rotation). */
- carlin = astGetCarLin( this );
-
-/* The first major section sees if the physical axes include a pair of
- longitude/latitude celestial axes.
- ================================================================= */
-
-/* We have not yet found any celestial axes. */
- axlon = -1;
- axlat = -1;
- latprj = AST__WCSBAD;
- lonprj = AST__WCSBAD;
- prj = AST__WCSBAD;
-
-/* First, we examine the CTYPE values in the FitsStore to determine
- which axes are the longitude and latitude axes, and what the celestial
- co-ordinate system and projection are. Loop round the physical axes,
- getting each CTYPE value. */
- for( i = 0; i < naxes && astOK; i++ ){
- keyname = FormatKey( "CTYPE", i + 1, -1, s, status );
- ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
-
-/* Issue a warning if no CTYPE value was found. */
- if( !ctype ) {
- sprintf( buf, "Axis type keywords (CTYPE, etc) were not found "
- "for one or more axes in the original FITS header. These "
- "axes will be assumed to be linear." );
- Warn( this, "noctype", buf, method, class, status );
- } else {
-
-/* See if this is a longitude axis (e.g. if the first 4 characters of CTYPE
- are "RA--" or "xLON" or "yzLN" ). If so, store the value of "x" or "yz"
- (or "EQU" for equatorial coordinates) in variable "type" to indicate which
- coordinate system is being used. */
- nc = strlen( ctype );
- gotax = 0;
- if( !strcmp( ctype, "RA" ) || !strncmp( ctype, "RA--", 4 ) ){
- strcpy( wcscelestial_type, "EQU" );
- gotax = 1;
- } else if( !strcmp( ctype, "AZ" ) || !strncmp( ctype, "AZ--", 4 ) ){
- strcpy( wcscelestial_type, "AZL" );
- gotax = 1;
- } else if( nc > 1 && ( !strcmp( ctype + 1, "LON" ) ||
- !strncmp( ctype + 1, "LON-", 4 ) ) ){
- wcscelestial_type[ 0 ] = ctype[ 0 ];
- wcscelestial_type[ 1 ] = 0;
- gotax = 1;
- } else if( nc > 2 && ( !strcmp( ctype + 2, "LN" ) ||
- !strncmp( ctype + 2, "LN-", 3 ) ) ){
- wcscelestial_type[ 0 ] = ctype[ 0 ];
- wcscelestial_type[ 1 ] = ctype[ 1 ];
- wcscelestial_type[ 2 ] = 0;
- gotax = 1;
- }
-
-/* If this is a longitude axis... */
- if( gotax ){
-
-/* Check that this is the first longitude axis to be found. */
- if( axlon == -1 ){
-
-/* Find the projection type as specified by the last 4 characters
- in the CTYPE keyword value. AST__WCSBAD is stored in "prj" if the
- last 4 characters do not specify a known WCS projection, but no error
- is reported. Assume simple linear axes if no projection code is
- supplied. Note, AST__WCSBAD is used to indicate a TAB header. */
- ctlen = strlen( ctype );
- if( ctlen > 4 ) {
- prj = astWcsPrjType( ctype + ctlen - 4 );
- } else if( tabmap && *tabmap ) {
- prj = AST__WCSBAD;
- } else {
- prj = AST__CAR;
- carlin = 1;
- }
-
-/* Report an error if the projection is unknown. */
- if( prj == AST__WCSBAD && ctlen > 4 ){
- astError( AST__BDFTS, "%s(%s): FITS keyword '%s' refers to "
- "an unknown projection type '%s'.", status, method, class,
- keyname, ctype + ctlen - 4 );
- break;
- }
-
-/* Store the index of the longitude axis, type of longitude, etc. */
- axlon = i;
- strcpy( lontype, wcscelestial_type );
- strcpy( lonkey, keyname );
- strcpy( lonctype, ctype );
- lonprj = prj;
-
-/* If another longitude axis has already been found, report an error. */
- } else {
- astError( AST__BDFTS, "%s(%s): FITS keywords '%s' (='%s') "
- "and '%s' (='%s') both describe celestial longitude axes.", status,
- method, class, keyname, ctype, lonkey, lonctype );
- break;
- }
- }
-
-/* Do the same for the latitude axis, checking for "DEC-" and "xLAT" and
- "yzLT". */
- gotax = 0;
- if( !strcmp( ctype, "DEC" ) || !strncmp( ctype, "DEC-", 4 ) ){
- strcpy( wcscelestial_type, "EQU" );
- gotax = 1;
- } else if( !strcmp( ctype, "EL" ) || !strncmp( ctype, "EL--", 4 ) ){
- strcpy( wcscelestial_type, "AZL" );
- gotax = 1;
- } else if( !strcmp( ctype + 1, "LAT" ) || !strncmp( ctype + 1, "LAT-", 4 ) ){
- wcscelestial_type[ 0 ] = ctype[ 0 ];
- wcscelestial_type[ 1 ] = 0;
- gotax = 1;
- } else if( !strcmp( ctype + 2, "LT" ) || !strncmp( ctype + 2, "LT-", 3 ) ){
- wcscelestial_type[ 0 ] = ctype[ 0 ];
- wcscelestial_type[ 1 ] = ctype[ 1 ];
- wcscelestial_type[ 2 ] = 0;
- gotax = 1;
- }
- if( gotax ){
- if( axlat == -1 ){
- ctlen = strlen( ctype );
- if( ctlen > 4 ) {
- prj = astWcsPrjType( ctype + ctlen - 4 );
- } else if( tabmap && *tabmap ) {
- prj = AST__WCSBAD;
- } else {
- prj = AST__CAR;
- carlin = 1;
- }
-
- if( prj == AST__WCSBAD && ctlen > 4 ){
- astError( AST__BDFTS, "%s(%s): FITS keyword '%s' refers to "
- "an unknown projection type '%s'.", status, method, class,
- keyname, ctype + ctlen - 4 );
- break;
- }
- axlat = i;
- strcpy( lattype, wcscelestial_type );
- strcpy( latkey, keyname );
- strcpy( latctype, ctype );
- latprj = prj;
- } else {
- astError( AST__BDFTS, "%s(%s): FITS keywords '%s' (='%s') "
- "and '%s' (='%s') both describe celestial latitude axes.", status,
- method, class, keyname, ctype, latkey, latctype );
- break;
- }
- }
- }
- }
-
-/* Check the above went OK */
- if( astOK ){
-
-/* If both longitude and latitude axes were found... */
- if( axlat != -1 && axlon != -1 ){
-
-/* Report an error if they refer to different celestial coordinate systems. */
- if( strcmp( lattype, lontype ) ){
- astError( AST__BDFTS, "%s(%s): FITS keywords '%s' and '%s' "
- "indicate different celestial coordinate systems "
- "('%s' and '%s').", status, method, class, latkey, lonkey,
- latctype, lonctype );
-
-/* Otherwise report an error if longitude and latitude axes use different
- projections. */
- } else if( lonprj != latprj ){
- astError( AST__BDFTS, "%s(%s): FITS keywords '%s' and '%s' "
- "indicate different projections ('%s' and '%s').", status,
- method, class, latkey, lonkey, latctype, lonctype );
- }
-
-/* If only one axis has been provided without the other (e.g. longitude but no
- latitude), report an error. */
- } else if( axlat != -1 && prj != AST__WCSBAD ){
- astError( AST__BDFTS, "%s(%s): A latitude axis ('%s') was found "
- "without a corresponding longitude axis.", status, method, class,
- latctype );
- } else if( axlon != -1 && prj != AST__WCSBAD ){
- astError( AST__BDFTS, "%s(%s): A longitude axis ('%s') was found "
- "without a corresponding latitude axis.", status, method, class,
- lonctype );
- }
- }
-
-/* If a pair of matching celestial axes was not found, return a UnitMap
- and leave the Frame unchanged.
- ===================================================================== */
- if( axlat == -1 || axlon == -1 ) {
- ret = (AstMapping *) astUnitMap( naxes, "", status );
-
-/* The rest of this function deals with creating a Mapping from
- intermediate world coords to celestial coords, and modifying the
- Frame appropriately.
- ===================================================================== */
- } else if( astOK ) {
-
-/* Create a MatrixMap which scales the intermediate world coordinate axes
- corresponding to the longitude and latitude axes from degrees to radians.
- Only do this if a projection was supplied. */
- if( latprj != AST__WCSBAD ) {
- mat = (double *) astMalloc( sizeof(double)*naxes );
- if( mat ){
- for( i = 0; i < naxes; i++ ){
- if( i == axlat || i == axlon ){
- mat[ i ] = AST__DD2R;
- } else {
- mat[ i ] = 1.0;
- }
- }
- map1 = (AstMapping *) astMatrixMap( naxes, naxes, 1, mat, "", status );
- mat = (double *) astFree( (void *) mat );
- }
- } else {
- map1 = (AstMapping *) astUnitMap( naxes, " ", status );
- }
-
-/* If the projection is a CAR projection, but the CarLin attribute is
- set, then we consider the CAR projection to be a simple linear mapping
- of pixel coords to celestial coords. Do this by using a WcsMap with no
- projection. All axes will then be treated as linear and non-celestial.
- If no projection was specified (i.e. if prj == AST__WCSBAD, as is the
- case when using -TAB for instance) then do the same but use a UnitMap
- instead of a WcsMap. */
- map3 = NULL;
- if( ( latprj == AST__CAR && carlin ) || latprj == AST__WCSBAD ) {
- if( latprj == AST__CAR ) {
- map2 = (AstMapping *) astWcsMap( naxes, AST__WCSBAD, axlon + 1,
- axlat + 1, "", status );
- } else {
- map2 = (AstMapping *) astUnitMap( naxes, "", status );
- }
-
-/* Now create a WinMap which adds on the CRVAL values to each axis. */
- ina = astMalloc( sizeof(double)*naxes );
- inb = astMalloc( sizeof(double)*naxes );
- outa = astMalloc( sizeof(double)*naxes );
- outb = astMalloc( sizeof(double)*naxes );
- if( astOK ) {
- for( i = 0; i < naxes; i++ ) {
- ina[ i ] = 0.0;
- inb[ i ] = 1.0;
- outa[ i ] = 0.0;
- outb[ i ] = 1.0;
- }
- lonval = GetItem( &(store->crval), axlon, 0, s, NULL, method, class, status );
- if( lonval != AST__BAD ) {
-
-/* For recognised projections the CRVAL value is required to be degrees,
- so convert to radians. For other algorithms (e.g. -TAB) the CRVAL
- values are in unknown units so retain their original scaling. */
- *reflon = ( latprj == AST__CAR ) ? lonval*AST__DD2R : lonval;
-
- outa[ axlon ] += *reflon;
- outb[ axlon ] += *reflon;
- } else {
- outa[ axlon ] = AST__BAD;
- outb[ axlon ] = AST__BAD;
- }
-
- latval = GetItem( &(store->crval), axlat, 0, s, NULL, method, class, status );
- if( latval != AST__BAD ) {
- *reflat = ( latprj == AST__CAR ) ? latval*AST__DD2R : latval;
- outa[ axlat ] += *reflat;
- outb[ axlat ] += *reflat;
- } else {
- outa[ axlat ] = AST__BAD;
- outb[ axlat ] = AST__BAD;
- }
-
- map3 = (AstMapping *) astWinMap( naxes, ina, inb, outa, outb, "", status );
-
- }
- ina = astFree( ina );
- inb = astFree( inb );
- outa = astFree( outa );
- outb = astFree( outb );
-
-/* Otherwise, create a WcsMap with the specified projection. The WcsMap
- is equivalent to a unit mapping for all axes other than "axlat" and
- "axlon". */
- } else {
-
-/* Get the highest index ("m" value) of any supplied PVi_m projection
- parameters (on any axes). */
- np = GetMaxJM( &(store->pv), s, status );
-
-/* Create the WcsMap */
- map2 = (AstMapping *) astWcsMap( naxes, latprj, axlon + 1,
- axlat + 1, "", status );
-
-/* If the FITS header contains any projection parameters, store them in
- the WcsMap. */
- mxpar_lat = astGetPVMax( map2, axlat );
- mxpar_lon = astGetPVMax( map2, axlon );
- for( m = 0; m <= np; m++ ){
- pv = GetItem( &(store->pv), axlat, m, s, NULL, method, class, status );
- if( pv != AST__BAD ) {
- if( m <= mxpar_lat ) {
- astSetPV( map2, axlat, m, pv );
- } else {
- sprintf( buf, "Projection parameter PV%d_%d found, "
- "but is not used by %s projections.", axlat + 1,
- m, astWcsPrjName( astGetWcsType( map2 ) ) );
- Warn( this, "badpv", buf, method, class, status );
- }
- }
- pv = GetItem( &(store->pv), axlon, m, s, NULL, method, class, status );
- if( pv != AST__BAD ) {
- if( m <= mxpar_lon ) {
- astSetPV( map2, axlon, m, pv );
- } else {
- sprintf( buf, "Projection parameter PV%d_%d found, "
- "but is not used by %s projections.", axlon + 1,
- m, astWcsPrjName( astGetWcsType( map2 ) ) );
- Warn( this, "badpv", buf, method, class, status );
- }
- }
- }
-
-/* Invert the WcsMap to get a DEprojection. */
- astInvert( map2 );
-
-/* Now produce a Mapping which converts the axes holding "Native Spherical
- Coords" into "Celestial Coords", leaving all other axes unchanged. */
- map3 = WcsNative( this, store, s, (AstWcsMap *) map2, -1, -1,
- method, class, status );
-
-/* Retrieve and store the reference longitude and latitude. */
- *reflon = GetItem( &(store->crval), axlon, 0, s, NULL, method, class, status );
- if( *reflon != AST__BAD ) *reflon *= AST__DD2R;
- *reflat = GetItem( &(store->crval), axlat, 0, s, NULL, method, class, status );
- if( *reflat != AST__BAD ) *reflat *= AST__DD2R;
- }
-
-/* If projection parameter PVi_0a for the longitude axis "i" is non-zero,
- then there is a shift of origin between Intermediate World Coords, IWC,
- (the CRPIXi values correspond to the origin of IWC), and Projection Plane
- Coords, PPC (these are the cartesian coordinates used by the WcsMap).
- This shift of origin results in the fiducial point specified by the
- CRVALi values mapping onto the pixel reference point specified by the
- CRPIXj values. In this case we need to add a Mapping which implements
- the shift of origin. Note, the AST-specific "TPN" projection cannot use
- this convention since it uses PVi_0 to hold a polynomial correction term. */
- if( latprj != AST__WCSBAD && astGetWcsType( map2 ) != AST__TPN &&
- astGetPV( map2, axlon, 0 ) != 0.0 ) {
-
-/* Find the projection plane coords corresponding to the fiducial point
- of the projection. This is done by using the inverse WcsMap to convert
- the native spherical coords at the fiducial point into PPC (x,y), which
- are returned in units of radians (not degrees). */
- GetFiducialPPC( (AstWcsMap *) map2, &x0, &y0, status );
- if( x0 != AST__BAD && y0 != AST__BAD ) {
-
-/* Allocate resources. */
- shifts = astMalloc( sizeof( double )*(size_t) naxes );
-
-/* Check pointers can be used safely. */
- if( astOK ) {
-
-/* Create a Mapping (a ShiftMap) from IWC to PPC. */
- for( i = 0; i < naxes; i++ ) shifts[ i ] = 0.0;
- shifts[ axlon ] = x0;
- shifts[ axlat ] = y0;
- shiftmap = (AstMapping *) astShiftMap( naxes, shifts, "", status );
-
-/* Produce a CmpMap which combines "map1" (which converts degrees to
- radians on the celestial axes) with the above ShiftMap. */
- newmap = (AstMapping *) astCmpMap( map1, shiftmap, 1, "", status );
-
-/* Annul the component Mappings and use the new one in place of map1. */
- shiftmap = astAnnul( shiftmap );
- map1 = astAnnul( map1 );
- map1 = newmap;
- }
-
-/* Free resources. */
- shifts = astFree( shifts );
- }
- }
-
-/* Now concatenate the Mappings to produce the returned Mapping. */
- map4 = (AstMapping *) astCmpMap( map1, map2, 1, "", status );
- ret = (AstMapping *) astCmpMap( map4, map3, 1, "", status );
-
-/* Annul the component Mappings. */
- map1 = astAnnul( map1 );
- map2 = astAnnul( map2 );
- map3 = astAnnul( map3 );
- map4 = astAnnul( map4 );
-
-/* We now make changes to the supplied Frame so that the longitude and
- latitude axes are described by a SkyFrame. First create an appropriate
- SkyFrame. */
- sfrm = WcsSkyFrame( this, store, s, prj, wcscelestial_type, axlon,
- axlat, method, class, status );
-
-/* The values currently stored in *reflat and *reflon are the CRVAL
- values. In some circumstances, these may not be the original values in
- the supplied header but may have been translated within the SpecTrans
- function as part of the process of translating an old unsupported
- projection into a new supported projection. Since the returned RefLat
- and RefLon values may be used to set the reference position for a
- SpecFrame, we should return the original values rather than the
- translated values. The original values will have been stored (within
- SpecTrans) in the FitsChan as keywords RFVALi. If such keywords can
- be found, use their values in preference to the currently stored CRVAL
- values.*/
- if( GetValue( this, FormatKey( "RFVAL", axlon + 1, -1, s, status ),
- AST__FLOAT, (void *) &lonval, 0, 0, method, class, status ) &&
- GetValue( this, FormatKey( "RFVAL", axlat + 1, -1, s, status ),
- AST__FLOAT, (void *) &latval, 0, 0, method, class, status ) ) {
- *reflon = lonval*AST__DD2R;
- *reflat = latval*AST__DD2R;
- }
-
-/* Store the reflon and reflat values as the SkyRef position in the
- SkyFrame, and set SkyRefIs to "ignore" so that the SkyFrame continues
- to represent absolute celestial coords. Do not change the SkyFrame if
- it already had a set reference posiiton. */
- if( ! astTestSkyRef( sfrm, 0 ) ) {
- if( *reflon != AST__BAD && *reflat != AST__BAD ) {
- astSetSkyRef( sfrm, 0, *reflon );
- astSetSkyRef( sfrm, 1, *reflat );
- astSet( sfrm, "SkyRefIs=Ignored", status );
- }
- }
-
-/* Return a clone of this SkyFrame as the reference Frame. */
- *reffrm = astClone( sfrm );
-
-/* Create a Frame by picking all the other (non-celestial) axes from the
- supplied Frame. */
- axes = astMalloc( naxes*sizeof( int ) );
- if( axes ) {
- j = 0;
- for( i = 0; i < naxes; i++ ) {
- if( i != axlat && i != axlon ) axes[ j++ ] = i;
- }
-
-/* If there were no other axes, replace the supplied Frame with the skyframe. */
- if( j == 0 ) {
- (void) astAnnul( *frm );
- *frm = (AstFrame *) astClone( sfrm );
-
-/* Otherwise pick the other axes from the supplied Frame */
- } else {
- ofrm = astPickAxes( *frm, j, axes, NULL );
-
-/* Replace the supplied Frame with a CmpFrame made up of this Frame and
- the SkyFrame. */
- (void) astAnnul( *frm );
- *frm = (AstFrame *) astCmpFrame( ofrm, sfrm, "", status );
- ofrm = astAnnul( ofrm );
- }
-
-/* Permute the axis order to put the longitude and latitude axes back in
- their original position. The SkyFrame will have the default axis
- ordering (lon=axis 0, lat = axis 1). */
- j = 0;
- for( i = 0; i < naxes; i++ ) {
- if( i == axlat ) {
- axes[ i ] = naxes - 1;
- } else if( i == axlon ) {
- axes[ i ] = naxes - 2;
- } else {
- axes[ i ] = j++;
- }
- }
- astPermAxes( *frm, axes );
-
-/* Free the axes array. */
- axes= astFree( axes );
- }
-
-/* Set the units in the supplied IWC Frame for the longitude and latitude
- axes. Unless using -TAB, these are degrees (the conversion from degs to
- rads is part of the Mapping from IWC to WCS). If using -TAB the units
- are unknown. */
- if( !tabaxis || !tabaxis[ axlon ] ) astSetUnit( iwcfrm, axlon, "deg" );
- if( !tabaxis || !tabaxis[ axlat ] ) astSetUnit( iwcfrm, axlat, "deg" );
-
-/* Modify any supplied tabmap so that the celestial outputs create
- radians rather than degrees (but only if the celestial axes are
- generated by the -TAB algorithm). */
- if( tabaxis && tabaxis[ axlon ] && tabaxis[ axlat ] ) {
- mat = (double *) astMalloc( sizeof(double)*naxes );
- if( mat ){
- for( i = 0; i < naxes; i++ ){
- if( i == axlat || i == axlon ){
- mat[ i ] = AST__DD2R;
- } else {
- mat[ i ] = 1.0;
- }
- }
- map1 = (AstMapping *) astMatrixMap( naxes, naxes, 1, mat, "", status );
- mat = (double *) astFree( (void *) mat );
- map2 = (AstMapping *) astCmpMap( *tabmap, map1, 1, " ", status );
- map1 = astAnnul( map1 );
- (void) astAnnul( *tabmap );
- *tabmap = map2;
- }
-
-/* Also modify the returned reflon and reflat values to transform them
- using the tabmap. Also transform the reference position in the SkyFrame. */
- if( *reflon != AST__BAD && *reflat != AST__BAD ) {
- ina = astMalloc( sizeof(double)*naxes );
- outa = astMalloc( sizeof(double)*naxes );
- if( astOK ) {
- for( i = 0; i < naxes; i++ ) ina[ i ] = 0.0;
- ina[ axlat ] = *reflat;
- ina[ axlon ] = *reflon;
- astTranN( *tabmap, 1, naxes, 1, ina, 1, naxes, 1, outa );
- *reflon = outa[ axlon ];
- *reflat = outa[ axlat ];
- }
- ina = astFree( ina );
- outa = astFree( outa );
-
-/* Store this transformed reference position in the SkyFrame. */
- astSetSkyRef( sfrm, 0, *reflon );
- astSetSkyRef( sfrm, 1, *reflat );
- astSet( sfrm, "SkyRefIs=Ignored", status );
- }
- }
-
-/* If the header contains AXREF values for both lon and lat axes, use
- them as the sky reference position in preferences to the values
- derived form the CRVAL values. AXREF keywords are created by the
- astWrite method for axes described by -TAB algorithm that have no inverse
- transformation. */
- if( GetValue( this, FormatKey( "AXREF", axlon + 1, -1, s, status ),
- AST__FLOAT, (void *) &lonval, 0, 0, method, class, status ) &&
- GetValue( this, FormatKey( "AXREF", axlat + 1, -1, s, status ),
- AST__FLOAT, (void *) &latval, 0, 0, method, class, status ) ) {
- *reflon = lonval*AST__DD2R;
- *reflat = latval*AST__DD2R;
- astSetSkyRef( sfrm, 0, *reflon );
- astSetSkyRef( sfrm, 1, *reflat );
- astSet( sfrm, "SkyRefIs=Ignored", status );
- }
-
-/* Free resources. */
- sfrm = astAnnul( sfrm );
- }
-
-/* Return the result. */
- return ret;
-}
-
-static void WcsFcRead( AstFitsChan *fc, AstFitsChan *fc2, FitsStore *store,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* WcsFcRead
-
-* Purpose:
-* Extract WCS information from a supplied FitsChan using a FITSWCS
-* encoding, and store it in the supplied FitsStore.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WcsFcRead( AstFitsChan *fc, AstFitsChan *fc2, FitsStore *store,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function extracts FITSWCS keywords from the supplied FitsChan,
-* and stores the corresponding WCS information in the supplied FitsStore.
-
-* Parameters:
-* fc
-* Pointer to the FitsChan containing the cards read from the
-* original FITS header. This should not include any un-used
-* non-standard keywords.
-* fc2
-* Pointer to a second FitsChan. If a card read from "fc" fails to
-* be converted to its correct data type, a warning is only issued
-* if there is no card for this keyword in "fc2". "fc2" may be NULL
-* in which case a warning is always issued.
-* store
-* Pointer to the FitsStore structure.
-* 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.
-*/
-
-/* Local Variables: */
- char buf[200]; /* Buffer for warning message */
- char *cval; /* String keyword value */
- char *keynam; /* Pointer to current keyword name */
- char s; /* Co-ordinate version character */
- double dval; /* Floating point keyword value */
- int fld[2]; /* Integer field values from keyword name */
- int jm; /* Pixel axis or projection parameter index */
- int i; /* Intermediate axis index */
- int mark; /* Non-zero if card should be removed once used */
- int nfld; /* Number of integer fields in test string */
- int ok; /* Was value converted succesfully? */
- int type; /* Keyword data type */
- int undef; /* Is an undefined keyword value acceptable? */
- void *item; /* Pointer to item to get/put */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Ensure the FitsChan is re-wound. */
- astClearCard( fc );
-
-/* Loop round all the cards in the FitsChan obtaining the keyword name for
- each card. Note, the single "=" is correct in the following "while"
- statement. */
- s = 0;
- jm = -1;
- i = -1;
- type = AST__NOTYPE;
- while( (keynam = CardName( fc, status )) ){
- item = NULL;
-
-/* Assume the card is to be consumed by the reading process. This means
- the card will be marked as used and effectively excluded from the header.
- Keywords which supply observation details that do not depend on the
- mapping from pixel to WCS axes, or on the nature of the WCS axes,
- are not removed as they may be needed for other, non-WCS related,
- purposes. */
- mark = 1;
-
-/* For most keywords, if the keyword is present in the header it must
- have a definded value. However, some keywords are read from the header
- but not actually used for anything. This is done to ensure that the
- keyword is stripped from the header. It is acceptable for such
- keywords to have an undefined value. Initialise a flag indicating that
- the next keyword read is not allowed to have an undefined value. */
- undef = 0;
-
-/* Is this a primary CRVAL keyword? */
- if( Match( keynam, "CRVAL%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->crval);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary CRVAL keyword? */
- } else if( Match( keynam, "CRVAL%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->crval);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary CRPIX keyword? */
- } else if( Match( keynam, "CRPIX%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->crpix);
- type = AST__FLOAT;
- i = 0;
- jm = fld[ 0 ] - 1;
- s = ' ';
-
-/* Is this a secondary CRPIX keyword? */
- } else if( Match( keynam, "CRPIX%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->crpix);
- type = AST__FLOAT;
- i = 0;
- jm = fld[ 0 ] - 1;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary CDELT keyword? */
- } else if( Match( keynam, "CDELT%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->cdelt);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary CDELT keyword? */
- } else if( Match( keynam, "CDELT%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->cdelt);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary CTYPE keyword? If so, store the associated comment. */
- } else if( Match( keynam, "CTYPE%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->ctype);
- type = AST__STRING;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = ' ';
- SetItemC( &(store->ctype_com), i, 0, ' ', CardComm( fc, status ), status );
-
-/* Is this a secondary CTYPE keyword? If so, store the associated comment. */
- } else if( Match( keynam, "CTYPE%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->ctype);
- type = AST__STRING;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
- SetItemC( &(store->ctype_com), i, 0, s, CardComm( fc, status ), status );
-
-/* Is this a primary CNAME keyword? */
- } else if( Match( keynam, "CNAME%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->cname);
- type = AST__STRING;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary CNAME keyword? */
- } else if( Match( keynam, "CNAME%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->cname);
- type = AST__STRING;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary CUNIT keyword? */
- } else if( Match( keynam, "CUNIT%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->cunit);
- type = AST__STRING;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary CUNIT keyword? */
- } else if( Match( keynam, "CUNIT%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->cunit);
- type = AST__STRING;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary PC keyword? */
- } else if( Match( keynam, "PC%d_%d", 2, fld, &nfld, method, class, status ) ){
- item = &(store->pc);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = fld[ 1 ] - 1;
- s = ' ';
-
-/* Is this a secondary PC keyword? */
- } else if( Match( keynam, "PC%d_%d%1c", 2, fld, &nfld, method, class, status ) ){
- item = &(store->pc);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = fld[ 1 ] - 1;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary PV keyword? */
- } else if( Match( keynam, "PV%d_%d", 2, fld, &nfld, method, class, status ) ){
- item = &(store->pv);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = fld[ 1 ];
- s = ' ';
-
-/* Is this a secondary PV keyword? */
- } else if( Match( keynam, "PV%d_%d%1c", 2, fld, &nfld, method, class, status ) ){
- item = &(store->pv);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = fld[ 1 ];
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary PS keyword? */
- } else if( Match( keynam, "PS%d_%d", 2, fld, &nfld, method, class, status ) ){
- item = &(store->ps);
- type = AST__STRING;
- i = fld[ 0 ] - 1;
- jm = fld[ 1 ];
- s = ' ';
-
-/* Is this a secondary PS keyword? */
- } else if( Match( keynam, "PS%d_%d%1c", 2, fld, &nfld, method, class, status ) ){
- item = &(store->ps);
- type = AST__STRING;
- i = fld[ 0 ] - 1;
- jm = fld[ 1 ];
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary RADESYS keyword? */
- } else if( Match( keynam, "RADESYS", 0, fld, &nfld, method, class, status ) ){
- item = &(store->radesys);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary RADESYS keyword? */
- } else if( Match( keynam, "RADESYS%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->radesys);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary EQUINOX keyword? */
- } else if( Match( keynam, "EQUINOX", 0, fld, &nfld, method, class, status ) ){
- item = &(store->equinox);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary EQUINOX keyword? */
- } else if( Match( keynam, "EQUINOX%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->equinox);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary LATPOLE keyword? */
- } else if( Match( keynam, "LATPOLE", 0, fld, &nfld, method, class, status ) ){
- item = &(store->latpole);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary LATPOLE keyword? */
- } else if( Match( keynam, "LATPOLE%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->latpole);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary LONPOLE keyword? */
- } else if( Match( keynam, "LONPOLE", 0, fld, &nfld, method, class, status ) ){
- item = &(store->lonpole);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary LONPOLE keyword? */
- } else if( Match( keynam, "LONPOLE%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->lonpole);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary WXSAXES keyword? */
- } else if( Match( keynam, "WCSAXES", 0, fld, &nfld, method, class, status ) ){
- item = &(store->wcsaxes);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary WCSAXES keyword? */
- } else if( Match( keynam, "WCSAXES%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->wcsaxes);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary DUT1 keyword? */
- } else if( Match( keynam, "DUT1", 0, fld, &nfld, method, class, status ) ){
- mark = 0;
- item = &(store->dut1);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a primary MJD-OBS keyword? */
- } else if( Match( keynam, "MJD-OBS", 0, fld, &nfld, method, class, status ) ){
- mark = 0;
- item = &(store->mjdobs);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a primary WCSNAME keyword? */
- } else if( Match( keynam, "WCSNAME", 0, fld, &nfld, method, class, status ) ){
- item = &(store->wcsname);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary WCSNAME keyword? */
- } else if( Match( keynam, "WCSNAME%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->wcsname);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary SPECSYS keyword? */
- } else if( Match( keynam, "SPECSYS", 0, fld, &nfld, method, class, status ) ){
- item = &(store->specsys);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary SPECSYS keyword? */
- } else if( Match( keynam, "SPECSYS%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->specsys);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary SSYSSRC keyword? */
- } else if( Match( keynam, "SSYSSRC", 0, fld, &nfld, method, class, status ) ){
- item = &(store->ssyssrc);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary SSYSSRC keyword? */
- } else if( Match( keynam, "SSYSSRC%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->ssyssrc);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary ZSOURCE keyword? */
- } else if( Match( keynam, "ZSOURCE", 0, fld, &nfld, method, class, status ) ){
- item = &(store->zsource);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary ZSOURCE keyword? */
- } else if( Match( keynam, "ZSOURCE%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->zsource);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary VELOSYS keyword? */
- } else if( Match( keynam, "VELOSYS", 0, fld, &nfld, method, class, status ) ){
- item = &(store->velosys);
- type = AST__FLOAT;
- undef = 1;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary VELOSYS keyword? */
- } else if( Match( keynam, "VELOSYS%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->velosys);
- type = AST__FLOAT;
- undef = 1;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary RESTFRQ keyword? */
- } else if( Match( keynam, "RESTFRQ", 0, fld, &nfld, method, class, status ) ){
- item = &(store->restfrq);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary RESTFRQ keyword? */
- } else if( Match( keynam, "RESTFRQ%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->restfrq);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary RESTWAV keyword? */
- } else if( Match( keynam, "RESTWAV", 0, fld, &nfld, method, class, status ) ){
- item = &(store->restwav);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary RESTWAV keyword? */
- } else if( Match( keynam, "RESTWAV%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->restwav);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary IMAGFREQ keyword? */
- } else if( Match( keynam, "IMAGFREQ", 0, fld, &nfld, method, class, status ) ){
- item = &(store->imagfreq);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a primary SKYREF keyword? */
- } else if( Match( keynam, "SREF%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->skyref);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary SKYREF keyword? */
- } else if( Match( keynam, "SREF%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->skyref);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary SKYREFP keyword? */
- } else if( Match( keynam, "SREFP%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->skyrefp);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary SKYREFP keyword? */
- } else if( Match( keynam, "SREFP%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->skyrefp);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary SKYREFIS keyword? */
- } else if( Match( keynam, "SREFIS", 0, fld, &nfld, method, class, status ) ){
- item = &(store->skyrefis);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary SKYREFIS keyword? */
- } else if( Match( keynam, "SREFIS%1c", 0, fld, &nfld, method, class, status ) ){
- item = &(store->skyrefis);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary AXREF keyword? */
- } else if( Match( keynam, "AXREF%d", 1, fld, &nfld, method, class, status ) ){
- item = &(store->axref);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = ' ';
-
-/* Is this a secondary AXREF keyword? */
- } else if( Match( keynam, "AXREF%d%1c", 1, fld, &nfld, method, class, status ) ){
- item = &(store->axref);
- type = AST__FLOAT;
- i = fld[ 0 ] - 1;
- jm = 0;
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a MJD-AVG keyword? */
- } else if( Match( keynam, "MJD-AVG", 0, fld, &nfld, method, class, status ) ){
- mark = 0;
- item = &(store->mjdavg);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a OBSGEO-X keyword? */
- } else if( Match( keynam, "OBSGEO-X", 0, fld, &nfld, method, class, status ) ){
- mark = 0;
- item = &(store->obsgeox);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a OBSGEO-Y keyword? */
- } else if( Match( keynam, "OBSGEO-Y", 0, fld, &nfld, method, class, status ) ){
- mark = 0;
- item = &(store->obsgeoy);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a OBSGEO-Z keyword? */
- } else if( Match( keynam, "OBSGEO-Z", 0, fld, &nfld, method, class, status ) ){
- mark = 0;
- item = &(store->obsgeoz);
- type = AST__FLOAT;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Is this a TIMESYS keyword? */
- } else if( Match( keynam, "TIMESYS", 0, fld, &nfld, method, class, status ) ){
- item = &(store->timesys);
- type = AST__STRING;
- i = 0;
- jm = 0;
- s = ' ';
-
-/* Following keywords are used to describe "-SIP" distortion as used by
- the Spitzer project... */
-
-/* Is this a primary A keyword? */
- } else if( Match( keynam, "A_%d_%d", 2, fld, &nfld, method, class, status ) ){
- item = &(store->asip);
- type = AST__FLOAT;
- i = fld[ 0 ];
- jm = fld[ 1 ];
- s = ' ';
-
-/* Is this a secondary A keyword? */
- } else if( Match( keynam, "A_%d_%d%1c", 2, fld, &nfld, method, class, status ) ){
- item = &(store->asip);
- type = AST__FLOAT;
- i = fld[ 0 ];
- jm = fld[ 1 ];
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary B keyword? */
- } else if( Match( keynam, "B_%d_%d", 2, fld, &nfld, method, class, status ) ){
- item = &(store->bsip);
- type = AST__FLOAT;
- i = fld[ 0 ];
- jm = fld[ 1 ];
- s = ' ';
-
-/* Is this a secondary B keyword? */
- } else if( Match( keynam, "B_%d_%d%1c", 2, fld, &nfld, method, class, status ) ){
- item = &(store->bsip);
- type = AST__FLOAT;
- i = fld[ 0 ];
- jm = fld[ 1 ];
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary AP keyword? */
- } else if( Match( keynam, "AP_%d_%d", 2, fld, &nfld, method, class, status ) ){
- item = &(store->apsip);
- type = AST__FLOAT;
- i = fld[ 0 ];
- jm = fld[ 1 ];
- s = ' ';
-
-/* Is this a secondary AP keyword? */
- } else if( Match( keynam, "AP_%d_%d%1c", 2, fld, &nfld, method, class, status ) ){
- item = &(store->apsip);
- type = AST__FLOAT;
- i = fld[ 0 ];
- jm = fld[ 1 ];
- s = keynam[ strlen( keynam ) - 1 ];
-
-/* Is this a primary BP keyword? */
- } else if( Match( keynam, "BP_%d_%d", 2, fld, &nfld, method, class, status ) ){
- item = &(store->bpsip);
- type = AST__FLOAT;
- i = fld[ 0 ];
- jm = fld[ 1 ];
- s = ' ';
-
-/* Is this a secondary BP keyword? */
- } else if( Match( keynam, "BP_%d_%d%1c", 2, fld, &nfld, method, class, status ) ){
- item = &(store->bpsip);
- type = AST__FLOAT;
- i = fld[ 0 ];
- jm = fld[ 1 ];
- s = keynam[ strlen( keynam ) - 1 ];
- }
-
-/* If this keyword was recognized, store it in the FitsStore, and mark it
- as having been read. */
- if( item ){
- ok = 1;
- if( type == AST__FLOAT ){
- if( CnvValue( fc, AST__FLOAT, undef, &dval, method, status ) ) {
- SetItem( (double ****) item, i, jm, s, dval, status );
- if( mark ) MarkCard( fc, status );
- } else {
- ok = 0;
- }
- } else {
- if( CnvValue( fc, AST__STRING, undef, &cval, method, status ) ) {
- cval[ astChrLen( cval ) ] = 0; /* Exclude trailing spaces */
- SetItemC( (char *****) item, i, jm, s, cval, status );
- if( mark ) MarkCard( fc, status );
- } else {
- ok = 0;
- }
- }
-
-/* Issue a warning if the value could not be converted to the expected
- type. */
- if( !ok ) {
-
-/* First check that the keyword is not included in "fc2". */
- if( !HasCard( fc2, keynam, method, class, status ) ) {
- sprintf( buf, "The original FITS header contained a value for "
- "keyword %s which could not be converted to a %s.",
- keynam, ( type==AST__FLOAT ? "floating point number":
- "character string" ) );
- Warn( fc, "badval", buf, "astRead", "FitsChan", status );
- }
- }
- }
-
-/* Move on to the next card. */
- MoveCard( fc, 1, method, class, status );
- }
-}
-
-static int WcsFromStore( AstFitsChan *this, FitsStore *store,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* WcsFromStore
-
-* Purpose:
-* Store WCS keywords in a FitsChan using FITS-WCS encoding.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* int WcsFromStore( AstFitsChan *this, FitsStore *store,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function copies the WCS information stored in the supplied
-* FitsStore into the supplied FitsChan, using FITS-WCS encoding.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* store
-* Pointer to the FitsStore.
-* 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 value of 1 is returned if succesfull, and zero is returned
-* otherwise.
-*/
-
-/* Local Variables: */
- char *comm; /* Pointer to comment string */
- char *cval; /* Pointer to string keyword value */
- char parprefix[3]; /* Prefix for projection parameter keywords */
- char combuf[80]; /* Buffer for FITS card comment */
- char s; /* Co-ordinate version character */
- char sign[2]; /* Fraction's sign character */
- char sup; /* Upper limit on s */
- char type[MXCTYPELEN];/* Buffer for CTYPE value */
- double cdl; /* CDELT value */
- double fd; /* Fraction of a day */
- double mjd99; /* MJD at start of 1999 */
- double val; /* General purpose value */
- int *tabaxis; /* Flags WCS axes that use -TAB algorithm */
- int i; /* Axis index */
- int ihmsf[ 4 ]; /* Hour, minute, second, fractional second */
- int iymdf[ 4 ]; /* Year, month, date, fractional day */
- int j; /* Axis index */
- int jj; /* SlaLib status */
- int m; /* Parameter index */
- int maxm; /* Upper limit on m */
- int naxis; /* Value of NAXIS keyword */
- int nc; /* Length of STYPE string */
- int nwcs; /* No. of WCS axes */
- int ok; /* Frame created succesfully? */
- int prj; /* Projection type */
- int ret; /* Returned value */
-
-/* Initialise */
- ret = 0;
-
-/* Other initialisation to avoid compiler warnings. */
- tabaxis = NULL;
-
-/* Check the inherited status. */
- if( !astOK ) return ret;
-
-/* If the FitsChan contains a value for the NAXIS keyword, note it.
- Otherwise store -1. */
- if( !astGetFitsI( this, "NAXIS", &naxis ) ) naxis = -1;
-
-/* Find the last WCS related card. */
- FindWcs( this, 1, 1, 0, method, class, status );
-
-/* Loop round all co-ordinate versions */
- sup = GetMaxS( &(store->crval), status );
- for( s = ' '; s <= sup && astOK; s++ ){
-
-/* For alternate axes, skip this axis description if there is no CRPIX1 or
- CRVAL1 value. This avoids partial axis descriptions being written out. */
- if( s != ' ' ) {
- if( GetItem( &(store->crpix), 0, 0, s, NULL, method, class, status ) ==
- AST__BAD ||
- GetItem( &(store->crval), 0, 0, s, NULL, method, class, status ) ==
- AST__BAD ) {
- ok = 0;
- goto next;
- }
- }
-
-/* Assume the Frame can be created succesfully. */
- ok = 1;
-
-/* Save the number of wcs axes. If a value for WCSAXES has been set, or
- if the number of axes is not the same as specified in the NAXIS keyword,
- store a WCSAXES keyword. */
- val = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- nwcs = (int) ( val + 0.5 );
- } else {
- nwcs = GetMaxJM( &(store->crpix), s, status ) + 1;
- if( nwcs != 0 && nwcs != naxis ) val = (double) nwcs;
- }
- if( val != AST__BAD ) {
- SetValue( this, FormatKey( "WCSAXES", -1, -1, s, status ),
- &nwcs, AST__INT, "Number of WCS axes", status );
- }
-
-/* Get and save WCSNAME. This is NOT required, so do not return if it is
- not available. If the WCS is 1-d, only store WCSNAME if its value is
- different to the CTYPE1 value. */
- cval = GetItemC( &(store->wcsname), 0, 0, s, NULL, method, class, status );
- if( cval && nwcs == 1 ) {
- comm = GetItemC( &(store->ctype), 0, 0, s, NULL, method, class, status );
- if( comm && Similar( comm, cval, status ) ) cval = NULL;
- }
- if( cval ) SetValue( this, FormatKey( "WCSNAME", -1, -1, s, status ), &cval,
- AST__STRING, "Reference name for the coord. frame", status );
-
-/* The prefix for numerical projection parameters is usually "PV". */
- strcpy( parprefix, "PV" );
-
-/* Keywords common to all axis types... */
-
-/* Get and save CRPIX for all pixel axes. These are required, so pass on
- if they are not available. */
- for( i = 0; i < nwcs; i++ ) {
- val = GetItem( &(store->crpix), 0, i, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- goto next;
- }
- sprintf( combuf, "Reference pixel on axis %d", i + 1 );
- SetValue( this, FormatKey( "CRPIX", i + 1, -1, s, status ), &val, AST__FLOAT,
- combuf, status );
- }
-
-/* Get and save CRVAL for all WCS axes. These are required, so
- pass on if they are not available. */
- for( i = 0; i < nwcs; i++ ) {
- val = GetItem( &(store->crval), i, 0, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- goto next;
- }
- sprintf( combuf, "Value at ref. pixel on axis %d", i + 1 );
- SetValue( this, FormatKey( "CRVAL", i + 1, -1, s, status ), &val, AST__FLOAT,
- combuf, status );
- }
-
-/* Allocate memory to indicate if each WCS axis is described by a -TAB
- algorithm or not. Initialiss it to zero. */
- tabaxis = astCalloc( nwcs, sizeof( int ) );
-
-/* Get and save CTYPE for all WCS axes. These are required, so
- pass on if they are not available. */
- for( i = 0; i < nwcs; i++ ) {
- cval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- if( !cval ) {
- ok = 0;
- goto next;
- }
- comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status );
- if( !comm ) {
- sprintf( combuf, "Type of co-ordinate on axis %d", i + 1 );
- comm = combuf;
- }
-
-/* Extract the projection type as specified by the last 4 characters
- in the CTYPE keyword value. This will be AST__WCSBAD for non-celestial
- axes. Note, CTYPE can be more than 8 characters long. */
- nc = strlen( cval );
- prj = ( nc > 4 ) ? astWcsPrjType( cval + nc - 4 ) : AST__WCSBAD;
-
-/* If the projection type is "TPN" (an AST-specific code) convert it to
- standard FITS-WCS code "TAN" and change the prefix for projection
- parameters from "PV" to "QV". AST will do the inverse conversions when
- reading such a header. Non-AST software will simply ignore the QV
- terms and interpret the header as a simple TAN projection. */
- if( prj == AST__TPN ) {
- strcpy( parprefix, "QV" );
- strcpy( type, cval );
- (void) strcpy( type + nc - 4, "-TAN" );
- cval = type;
- }
-
-/* Note if the axis is described by the -TAB algorithm. */
- tabaxis[ i ] = ( prj == AST__WCSBAD && strlen( cval ) >= 8 &&
- !strncmp( cval + 4, "-TAB", 4 ) );
-
-/* Store the (potentially modified) CTYPE value. */
- SetValue( this, FormatKey( "CTYPE", i + 1, -1, s, status ), &cval, AST__STRING,
- comm, status );
- }
-
-/* Get and save CNAME for all WCS axes. These are NOT required, so
- do not pass on if they are not available. Do not include a CNAME
- keyword if its value equals the commen or value of the corresponding
- CTYPE keyword. */
- for( i = 0; i < nwcs; i++ ) {
- cval = GetItemC( &(store->cname), i, 0, s, NULL, method, class, status );
- if( cval ) {
- comm = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- if( !comm || strcmp( comm, cval ) ) {
- comm = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status );
- if( !comm || strcmp( comm, cval ) ) {
- sprintf( combuf, "Description of axis %d", i + 1 );
- SetValue( this, FormatKey( "CNAME", i + 1, -1, s, status ), &cval,
- AST__STRING, combuf, status );
- }
- }
- }
- }
-
-/* Now choose whether to produce CDi_j or CDELT/PCi_j keywords. */
- if( astGetCDMatrix( this ) ) {
-
-/* CD matrix. Multiply the row of the PC matrix by the CDELT value. */
- for( i = 0; i < nwcs; i++ ) {
- cdl = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
- if( cdl == AST__BAD ) cdl = 1.0;
- for( j = 0; j < nwcs; j++ ){
- val = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
- if( val == AST__BAD ) val = ( i == j ) ? 1.0 : 0.0;
- val *= cdl;
- if( val != 0.0 ) {
- SetValue( this, FormatKey( "CD", i + 1, j + 1, s, status ), &val,
- AST__FLOAT, "Transformation matrix element", status );
- }
- }
- }
-
-/* If producing PC/CDELT keywords... */
- } else {
-
-/* CDELT keywords. */
- for( i = 0; i < nwcs; i++ ) {
- val = GetItem( &(store->cdelt), i, 0, s, NULL, method, class, status );
- if( val == AST__BAD ) {
- ok = 0;
- goto next;
- }
- sprintf( combuf, "Pixel size on axis %d", i + 1 );
- SetValue( this, FormatKey( "CDELT", i + 1, -1, s, status ), &val, AST__FLOAT,
- combuf, status );
- }
-
-/* PC matrix. */
- for( i = 0; i < nwcs; i++ ) {
- for( j = 0; j < nwcs; j++ ){
- val = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- if( i == j ) {
- if( astEQUAL( val, 1.0 ) ) val = AST__BAD;
- } else {
- if( astEQUAL( val, 0.0 ) ) val = AST__BAD;
- }
- }
- if( val != AST__BAD ) {
- SetValue( this, FormatKey( "PC", i + 1, j + 1, s, status ), &val,
- AST__FLOAT, "Transformation matrix element", status );
- }
- }
- }
- }
-
-/* Get and save CUNIT for all WCS axes. These are NOT required, so
- do not pass on if they are not available. */
- for( i = 0; i < nwcs; i++ ) {
- cval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status );
- if( cval ) {
- sprintf( combuf, "Units for axis %d", i + 1 );
- SetValue( this, FormatKey( "CUNIT", i + 1, -1, s, status ), &cval, AST__STRING,
- combuf, status );
- }
- }
-
-/* Get and save AXREF for all WCS axes. These are NOT required, so do not
- pass on if they are not available. Note, AXREF is a non-standard keyword
- used by AST to communicate the reference position on any axes described
- by the -TAB algorithm and which has no inverse transformation. For all
- other cases, the reference position corresponds to the values of CRVAL. */
- for( i = 0; i < nwcs; i++ ) {
- val = GetItem( &(store->axref), i, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- sprintf( combuf, "Reference WCS value on axis %d", i + 1 );
- SetValue( this, FormatKey( "AXREF", i + 1, -1, s, status ), &val, AST__FLOAT,
- combuf, status );
- }
- }
-
-/* Get and save SREFIS. This is NOT required, so do not return if it is
- not available. Note, SREFIS is a non-standard keyword used by AST to
- communicate the SkyRefIs attribute in the original SkyFrame. */
- cval = GetItemC( &(store->skyrefis), 0, 0, s, NULL, method, class, status );
- if( cval ) SetValue( this, FormatKey( "SREFIS", -1, -1, s, status ), &cval,
- AST__STRING, "Is SkyRef used as pole or origin?", status );
-
-/* Get and save SREF for all WCS axes. These are NOT required, so do not
- pass on if they are not available. Note, SREF is a non-standard keyword
- used by AST to communicate the SkyRef position on any axes described
- by a offset SkyFrame. */
- for( i = 0; i < nwcs; i++ ) {
- val = GetItem( &(store->skyref), i, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- sprintf( combuf, "Sky reference position on axis %d", i + 1 );
- SetValue( this, FormatKey( "SREF", i + 1, -1, s, status ), &val, AST__FLOAT,
- combuf, status );
- }
- }
-
-/* Get and save SREFP for all WCS axes. These are NOT required, so do not
- pass on if they are not available. Note, SREFP is a non-standard keyword
- used by AST to communicate the SkyRefP position on any axes described
- by a offset SkyFrame. */
- for( i = 0; i < nwcs; i++ ) {
- val = GetItem( &(store->skyrefp), i, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- sprintf( combuf, "Sky primary meridian position on axis %d", i + 1 );
- SetValue( this, FormatKey( "SREFP", i + 1, -1, s, status ), &val, AST__FLOAT,
- combuf, status );
- }
- }
-
-/* Date of observation (only allowed for primary axis descriptions). */
- if( s == ' ' ) {
- val = GetItem( &(store->mjdobs), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- SetValue( this, FormatKey( "MJD-OBS", -1, -1, s, status ),
- &val, AST__FLOAT, "Modified Julian Date of observation", status );
-
-/* The format used for the DATE-OBS keyword depends on the value of the
- keyword. For DATE-OBS < 1999.0, use the old "dd/mm/yy" format.
- Otherwise, use the new "ccyy-mm-ddThh:mm:ss[.ssss]" format. */
- palCaldj( 99, 1, 1, &mjd99, &jj );
- if( val < mjd99 ) {
- palDjcal( 0, val, iymdf, &jj );
- sprintf( combuf, "%2.2d/%2.2d/%2.2d", iymdf[ 2 ], iymdf[ 1 ],
- iymdf[ 0 ] - ( ( iymdf[ 0 ] > 1999 ) ? 2000 : 1900 ) );
- } else {
- palDjcl( val, iymdf, iymdf+1, iymdf+2, &fd, &jj );
- palDd2tf( 3, fd, sign, ihmsf );
- sprintf( combuf, "%4.4d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2d.%3.3d",
- iymdf[0], iymdf[1], iymdf[2], ihmsf[0], ihmsf[1],
- ihmsf[2], ihmsf[3] );
- }
-
-/* Now store the formatted string in the FitsChan. */
- cval = combuf;
- SetValue( this, "DATE-OBS", (void *) &cval, AST__STRING,
- "Date of observation", status );
- }
- val = GetItem( &(store->mjdavg), 0, 0, ' ', NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, "MJD-AVG", &val, AST__FLOAT,
- "Average Modified Julian Date of observation", status );
-
-/* Store the timescale in TIMESYS. */
- cval = GetItemC( &(store->timesys), 0, 0, s, NULL, method, class, status );
- if( cval ) SetValue( this, "TIMESYS", &cval, AST__STRING,
- "Timescale for MJD-OBS/MJD-AVG values", status );
- }
-
-/* Numerical projection parameters */
- maxm = GetMaxJM( &(store->pv), s, status );
- for( i = 0; i < nwcs; i++ ){
- for( m = 0; m <= maxm; m++ ){
- val = GetItem( &(store->pv), i, m, s, NULL, method, class, status );
- if( val != AST__BAD ) {
-
-/* If the axis uses the "TAB" algorithm, there may be a PVi_4a parameter
- in the FitsStore. This is an AST extension to the published -TAB
- algorithm, and is used to hold the interpolation method. To avoid
- clashing with any standard use of PV1_4a, rename it to QVi_4a. The
- default is zero (linear interpolation) so do not write the QV value
- if it zero. */
- if( m == 4 && tabaxis[ i ] ) {
- if( val != 0.0 ) {
- SetValue( this, FormatKey( "QV", i + 1, m, s, status ),
- &val, AST__FLOAT, "Use nearest neighbour "
- "interpolation", status );
- }
-
-/* Just store the parameters for other type of axes. */
- } else {
- SetValue( this, FormatKey( parprefix, i + 1, m, s, status ), &val,
- AST__FLOAT, "Projection parameter", status );
- }
- }
- }
- }
-
-/* String projection parameters */
- maxm = GetMaxJMC( &(store->ps), s, status );
- for( i = 0; i < nwcs; i++ ){
- for( m = 0; m <= maxm; m++ ){
- cval = GetItemC( &(store->ps), i, m, s, NULL, method, class, status );
- if( cval ) {
- SetValue( this, FormatKey( "PS", i + 1, m, s, status ), &cval,
- AST__STRING, "Projection parameter", status );
- }
- }
- }
-
-/* Keywords specific to celestial axes... */
-
-/* Get and save RADESYS. This is NOT required, so do not return if it is
- not available. */
- cval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status );
- if( cval ) SetValue( this, FormatKey( "RADESYS", -1, -1, s, status ), &cval,
- AST__STRING, "Reference frame for RA/DEC values", status );
-
-/* Reference equinox */
- val = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "EQUINOX", -1, -1, s, status ),
- &val, AST__FLOAT,
- "[yr] Epoch of reference equinox", status );
-
-/* Latitude of native north pole */
- val = GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "LATPOLE", -1, -1, s, status ),
- &val, AST__FLOAT,
- "[deg] Latitude of native north pole", status );
-
-/* Longitude of native north pole */
- val = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "LONPOLE", -1, -1, s, status ),
- &val, AST__FLOAT,
- "[deg] Longitude of native north pole", status );
-
-/* Keywords specific to spectral axes... */
-
-/* SPECSYS - the standard of rest for the spectral axis */
- cval = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status );
- if( cval ) SetValue( this, FormatKey( "SPECSYS", -1, -1, s, status ), &cval,
- AST__STRING, "Standard of rest for spectral axis", status );
-
-/* SSYSSRC - the standard of rest in which ZSOURCE is stored. */
- cval = GetItemC( &(store->ssyssrc), 0, 0, s, NULL, method, class, status );
- if( cval ) SetValue( this, FormatKey( "SSYSSRC", -1, -1, s, status ), &cval,
- AST__STRING, "Standard of rest for source redshift", status );
-
-/* ZSOURCE - topocentric optical velocity of source */
- val = GetItem( &(store->zsource), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "ZSOURCE", -1, -1, s, status ),
- &val, AST__FLOAT, "[] Redshift of source", status );
-
-/* VELOSYS - topocentric apparent radial velocity of the standard of rest. */
- val = GetItem( &(store->velosys), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "VELOSYS", -1, -1, s, status ),
- &val, AST__FLOAT, "[m/s] Topo. apparent velocity of rest frame", status );
-
-/* RESTFRQ - rest frequency */
- val = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "RESTFRQ", -1, -1, s, status ),
- &val, AST__FLOAT, "[Hz] Rest frequency", status );
-
-/* RESTWAV - rest wavelength */
- val = GetItem( &(store->restwav), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, FormatKey( "RESTWAV", -1, -1, s, status ),
- &val, AST__FLOAT, "[m] Rest wavelength", status );
-
-/* The image frequency corresponding to the rest frequency (only used for
- double sideband data). This is not part of the FITS-WCS standard but
- is added for the benefit of JACH. */
- val = GetItem( &(store->imagfreq), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) {
- SetValue( this, "IMAGFREQ", &val, AST__FLOAT, "[Hz] Image frequency", status );
- }
-
-/* OBSGEO-X/Y/Z - observer's geocentric coords. Note, these always refer
- to the primary axes. */
- if( s == ' ' ) {
- val = GetItem( &(store->obsgeox), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, "OBSGEO-X", &val, AST__FLOAT, "[m] Observatory geocentric X", status );
- val = GetItem( &(store->obsgeoy), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, "OBSGEO-Y", &val, AST__FLOAT, "[m] Observatory geocentric Y", status );
- val = GetItem( &(store->obsgeoz), 0, 0, s, NULL, method, class, status );
- if( val != AST__BAD ) SetValue( this, "OBSGEO-Z", &val, AST__FLOAT, "[m] Observatory geocentric Z", status );
- }
-
-/* See if a Frame was sucessfully written to the FitsChan. */
-next:
- ok = ok && astOK;
-
-/* If so, indicate we have something to return. */
- if( ok ) ret = 1;
-
-/* If we are producing secondary axes, clear any error status so we can
- continue to produce the next Frame. Retain the error if the primary axes
- could not be produced. After the primary axes, do the A axes. */
- if( s != ' ' ) {
- astClearStatus;
- } else {
- s = 'A' - 1;
- }
-
-/* Remove the secondary "new" flags from the FitsChan. This flag is
- associated with cards which have been added to the FitsChan during
- this pass through the main loop in this function. If the Frame was
- written out succesfully, just clear the flags. If anything went wrong
- with this Frame, remove the flagged cards from the FitsChan. */
- FixNew( this, NEW2, !ok, method, class, status );
-
-/* Set the current card so that it points to the last WCS-related keyword
- in the FitsChan (whether previously read or not). */
- FindWcs( this, 1, 1, 0, method, class, status );
-
-/* Free resources. */
- tabaxis = astFree( tabaxis );
- }
-
-/* Return zero or ret depending on whether an error has occurred. */
- return astOK ? ret : 0;
-}
-
-static AstMapping *WcsIntWorld( AstFitsChan *this, FitsStore *store, char s,
- int naxes, const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* WcsIntWorld
-
-* Purpose:
-* Create a Mapping from pixel coords to intermediate world coords.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* AstMapping *WcsIntWorld( AstFitsChan *this, FitsStore *store, char s,
-* int naxes, const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function interprets the contents of the supplied FitsStore
-* structure, and creates a Mapping which describes the transformation
-* from pixel coordinates to intermediate world coordinates, using the
-* FITS World Coordinate System conventions. This is a general linear
-* transformation described by the CRPIXj, PCi_j and CDELTi keywords.
-
-* Parameters:
-* this
-* The FitsChan. ASTWARN cards may be added to this FitsChan if any
-* anomalies are found in the keyword values in the FitsStore.
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* naxes
-* The number of intermediate world coordinate axes (WCSAXES).
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the Mapping.
-*/
-
-/* Local Variables: */
- AstMapping *mapd1; /* Pointer to first distortion Mapping */
- AstMapping *mapd2; /* Pointer to second distortion Mapping */
- AstMapping *mapd3; /* Pointer to third distortion Mapping */
- AstMapping *mapd4; /* Pointer to fourth distortion Mapping */
- AstMapping *map0; /* Pointer to a Mapping */
- AstMapping *map1; /* Pointer to a Mapping */
- AstMapping *ret; /* Pointer to the returned Mapping */
-
-/* Initialise the pointer to the returned Mapping. */
- ret = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return ret;
-
-/* First of all, check the CTYPE keywords to see if they contain any known
- distortion codes (following the syntax described in FITS-WCS paper IV).
- If so, Mappings are returned which represents the distortions to be
- applied at each point in the chain of Mappings produced by this function.
- Any distortion codes are removed from the CTYPE values in the FitsStore. */
- DistortMaps( this, store, s, naxes, &mapd1, &mapd2, &mapd3, &mapd4, method,
- class, status );
-
-/* If distortion is to be applied now, initialise the returned Mapping to
- be the distortion. */
- if( mapd1 ) ret = mapd1;
-
-/* Try to create a WinMap which translates the pixel coordinates so
- that they are refered to an origin at the reference pixel. This
- subtracts the value of CRPIXi from axis i. */
- map1 = (AstMapping *) WcsShift( store, s, naxes, method, class, status );
-
-/* Combine this with any previous Mapping. */
- if( ret ) {
- map0 = (AstMapping *) astCmpMap( ret, map1, 1, "", status );
- ret = astAnnul( ret );
- map1 = astAnnul( map1 );
- ret = map0;
- } else {
- ret = map1;
- }
-
-/* If distortion is to be applied now, combine the two Mappings. */
- if( mapd2 ) {
- map0 = (AstMapping *) astCmpMap( ret, mapd2, 1, "", status );
- ret = astAnnul( ret );
- mapd2 = astAnnul( mapd2 );
- ret = map0;
- }
-
-/* Now try to create a MatrixMap to implement the PC matrix. Combine it
- with the above Mapping. Add a Warning if this mapping cannot be inverted. */
- map1 = (AstMapping *) WcsPCMatrix( store, s, naxes, method, class, status );
- if( !astGetTranInverse( map1 ) ) {
- Warn( this, "badmat", "The pixel rotation matrix in the original FITS "
- "header (specified by CD or PC keywords) could not be inverted. "
- "This may be because the matrix contains rows or columns which "
- "are entirely zero.", method, class, status );
- }
- map0 = (AstMapping *) astCmpMap( ret, map1, 1, "", status );
- ret = astAnnul( ret );
- map1 = astAnnul( map1 );
- ret = map0;
-
-/* If distortion is to be applied now, combine the two Mappings. */
- if( mapd3 ) {
- map0 = (AstMapping *) astCmpMap( ret, mapd3, 1, "", status );
- ret = astAnnul( ret );
- mapd3 = astAnnul( mapd3 );
- ret = map0;
- }
-
-/* Now try to create a diagonal MatrixMap to implement the CDELT scaling.
- Combine it with the above Mapping. */
- map1 = (AstMapping *) WcsCDeltMatrix( store, s, naxes, method, class, status );
- map0 = (AstMapping *) astCmpMap( ret, map1, 1, "", status );
- ret = astAnnul( ret );
- map1 = astAnnul( map1 );
- ret = map0;
-
-/* If distortion is to be applied now, combine the two Mappings. */
- if( mapd4 ) {
- map0 = (AstMapping *) astCmpMap( ret, mapd4, 1, "", status );
- ret = astAnnul( ret );
- mapd4 = astAnnul( mapd4 );
- ret = map0;
- }
-
-/* Return the result. */
- return ret;
-}
-
-static AstMapping *WcsMapFrm( AstFitsChan *this, FitsStore *store, char s,
- AstFrame **frm, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* WcsMapFrm
-
-* Purpose:
-* Create a Mapping and Frame for the WCS transformations described in a
-* FITS header.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* AstMapping *WcsMapFrm( AstFitsChan *this, FitsStore *store, char s,
-* AstFrame **frm, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function interprets the contents of the supplied FitsStore
-* structure, and creates a Mapping which describes the transformation
-* from pixel coordinates to world coordinates, using the FITS World
-* Coordinate System conventions. It also creates a Frame describing
-* the world coordinate axes.
-
-* Parameters:
-* this
-* The FitsChan.
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* frm
-* The address of a location at which to store a pointer to the
-* Frame describing the world coordinate axes. If the Iwc attribute
-* is non-zero, then this is actually a FrameSet in which the current
-* Frame is the required WCS system. The FrameSet also contains one
-* other Frame which defines the FITS IWC system.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the Mapping.
-*/
-
-/* Local Variables: */
- AstFrame *iwcfrm; /* Frame defining IWC system */
- AstFrameSet *fs; /* Pointer to returned FrameSet */
- AstMapping *map10; /* Pointer to a Mapping */
- AstMapping *map1; /* Pointer to a Mapping */
- AstMapping *map2; /* Pointer to a Mapping */
- AstMapping *map3; /* Pointer to a Mapping */
- AstMapping *map4; /* Pointer to a Mapping */
- AstMapping *map5; /* Pointer to a Mapping */
- AstMapping *map6; /* Pointer to a Mapping */
- AstMapping *map7; /* Pointer to a Mapping */
- AstMapping *map8; /* Pointer to a Mapping */
- AstMapping *map9; /* Pointer to a Mapping */
- AstMapping *ret; /* Pointer to the returned Mapping */
- AstMapping *tabmap; /* Mapping from psi to WCS (paper III - 6.1.2) */
- AstSkyFrame *reffrm; /* SkyFrame defining reflon and reflat */
- char id[2]; /* ID string for returned Frame */
- char iwc[5]; /* Domain name for IWC Frame */
- const char *cc; /* Pointer to Domain */
- double dut1; /* UT1-UTC correction in days */
- double dval; /* Temporary double value */
- double reflat; /* Reference celestial latitude */
- double reflon; /* Reference celestial longitude */
- int *tabaxis; /* Flags indicating -TAB axes */
- int wcsaxes; /* Number of physical axes */
-
-/* Initialise the pointer to the returned Mapping. */
- ret = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return ret;
-
-/* Identify any axes that use the -TAB algoritm code described in FITS-WCS
- paper III, and convert their CTYPE values to describe linear axes
- (i.e. just remove "-TAB" from the CTYPE value). This also returns a
- Mapping (which includes one or more LutMaps) that should be applied to
- the resulting linear axis values in order to generate the final WCS
- axis values. A NULL pointer is returned if no axes use -TAB. */
- tabmap = TabMapping( this, store, s, &tabaxis, method, class, status );
-
-/* Obtain the number of physical axes in the header. If the WCSAXES header
- was specified, use it. Otherwise assume it is the same as the number
- of pixel axes. */
- dval = GetItem( &(store->wcsaxes), 0, 0, s, NULL, method, class, status );
- if( dval != AST__BAD ) {
- wcsaxes = (int) dval + 0.5;
- } else {
- wcsaxes = store->naxis;
- }
-
-/* Create a simple Frame to represent IWC coords. */
- iwcfrm = astFrame( wcsaxes, "Title=FITS Intermediate World Coordinates", status );
- strcpy( iwc, "IWC" );
- iwc[ 3 ]= s;
- iwc[ 4 ]= 0;
- astSetDomain( iwcfrm, iwc );
-
-/* Create a simple Frame which will be used as the initial representation
- for the physical axes. This Frame will be changed later (or possibly
- replaced by a Frame of another class) when we know what type of
- physical axes we are dealing with. Set its Domain to "AST_FITSCHAN"
- This value is used to identify axes which have not been changed,
- and will be replaced before returning the final FrameSet. */
- *frm = astFrame( wcsaxes, "Domain=AST_FITSCHAN", status );
-
-/* Store the coordinate version character as the Ident attribute for the
- returned Frame. */
- id[ 0 ] = s;
- id[ 1 ] = 0;
- astSetIdent( *frm, id );
-
-/* Create a Mapping which goes from pixel coordinates to what FITS-WCS
- paper I calls "intermediate world coordinates". This stage is the same
- for all axes. It uses the CRPIXj, PCi_j and CDELTi headers (and
- distortion codes from the CTYPE keywords). */
- map1 = WcsIntWorld( this, store, s, wcsaxes, method, class, status );
-
-/* The conversion from intermediate world coordinates to the final world
- coordinates depends on the type of axis being converted (as specified
- by its CTYPE keyword). Check for each type of axis for which known
- conventions exist... */
-
-/* Celestial coordinate axes. The following call returns a Mapping which
- transforms any celestial coordinate axes from intermediate world
- coordinates to the final celestial coordinates. Other axes are left
- unchanged by the Mapping. It also modifies the Frame so that a
- SkyFrame is used to describe the celestial axes. */
- map2 = WcsCelestial( this, store, s, frm, iwcfrm, &reflon, &reflat,
- &reffrm, &tabmap, tabaxis, method, class, status );
-
-/* Spectral coordinate axes. The following call returns a Mapping which
- transforms any spectral coordinate axes from intermediate world
- coordinates to the final spectral coordinates. Other axes are left
- unchanged by the Mapping. It also modifies the Frame so that a
- SpecFrame is used to describe the spectral axes. */
- map3 = WcsSpectral( this, store, s, frm, iwcfrm, reflon, reflat, reffrm,
- method, class, status );
-
-/* Any axes which were not recognized by the above calls are assumed to
- be linear. Create a Mapping which adds on the reference value for such
- axes, and modify the Frame to desribe the axes. */
- map4 = WcsOthers( this, store, s, frm, iwcfrm, method, class, status );
-
-/* If the Frame still has the Domain "AST_FITSCHAN", clear it. */
- cc = astGetDomain( *frm );
- if( cc && !strcmp( cc, "AST_FITSCHAN" ) ) astClearDomain( *frm );
-
-/* Concatenate the Mappings and simplify the result. */
- map5 = (AstMapping *) astCmpMap( map1, map2, 1, "", status );
- map6 = (AstMapping *) astCmpMap( map5, map3, 1, "", status );
- map7 = (AstMapping *) astCmpMap( map6, map4, 1, "", status );
- if( tabmap ) {
- map8 = (AstMapping *) astCmpMap( map7, tabmap, 1, "", status );
- } else {
- map8 = astClone( map7 );
- }
-
- ret = astSimplify( map8 );
-
-/* Ensure that the coordinate version character is stored as the Ident
- attribute for the returned Frame (the above calls may have changed it). */
- astSetIdent( *frm, id );
-
-/* Set the DUT1 value. Note, the JACH store DUT1 in units of days in their
- FITS headers, so convert from days to seconds. May need to do somthing
- about this if the forthcoming FITS-WCS paper 5 (time axes) defines DUT1
- to be in seconds. */
- dut1 = GetItem( &(store->dut1), 0, 0, s, NULL, method, class, status );
- if( dut1 != AST__BAD ) astSetDut1( *frm, dut1*SPD );
-
-/* The returned Frame is actually a FrameSet in which the current Frame
- is the required WCS Frame. The FrameSet contains one other Frame,
- which is the Frame representing IWC. Create a FrameSet containing these
- two Frames. */
- if( astGetIwc( this ) ) {
- fs = astFrameSet( iwcfrm, "", status );
- astInvert( map1 );
- map9 = (AstMapping *) astCmpMap( map1, ret, 1, "", status );
- astInvert( map1 );
- map10 = astSimplify( map9 );
- astAddFrame( fs, AST__BASE, map10, *frm );
-
-/* Return this FrameSet instead of the Frame. */
- *frm = astAnnul( *frm );
- *frm = (AstFrame *) fs;
-
-/* Free resources */
- map9 = astAnnul( map9 );
- map10 = astAnnul( map10 );
- }
-
-/* Annull temporary resources. */
- if( reffrm ) reffrm = astAnnul( reffrm );
- if( tabmap ) tabmap = astAnnul( tabmap );
- tabaxis = astFree( tabaxis );
- iwcfrm = astAnnul( iwcfrm );
- map1 = astAnnul( map1 );
- map2 = astAnnul( map2 );
- map3 = astAnnul( map3 );
- map4 = astAnnul( map4 );
- map5 = astAnnul( map5 );
- map6 = astAnnul( map6 );
- map7 = astAnnul( map7 );
- map8 = astAnnul( map8 );
-
-/* Annul thre returned objects if an error has occurred. */
- if( !astOK ) {
- ret = astAnnul( ret );
- *frm = astAnnul( *frm );
- }
-
-/* Return the result. */
- return ret;
-}
-
-static AstMatrixMap *WcsPCMatrix( FitsStore *store, char s, int naxes,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* WcsPCMatrix
-
-* Purpose:
-* Create a MatrixMap representing the PC matrix.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstMatrixMap *WcsPCMatrix( FitsStore *store, char s, int naxes,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A MatrixMap representing the FITS "PC" matrix is returned.
-
-* Parameters:
-* store
-* A structure containing values for FITS keywords relating to
-* the World Coordinate System.
-* s
-* A character s identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* naxes
-* The number of intermediate world coordinate axes (WCSAXES).
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the created MatrixMap or a NULL pointer if an
-* error occurred.
-*/
-
-/* Local Variables: */
- AstMatrixMap *new; /* The created MatrixMap */
- double *el; /* Pointer to next matrix element */
- double *mat; /* Pointer to matrix array */
- int i; /* Pixel axis index */
- int j; /* Intermediate axis index. */
-
-/* Initialise/ */
- new = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return new;
-
-/* Allocate memory for the matrix. */
- mat = (double *) astMalloc( sizeof(double)*naxes*naxes );
- if( astOK ){
-
-/* Fill the matrix with values from the FitsStore. */
- el = mat;
- for( i = 0; i < naxes; i++ ){
- for( j = 0; j < naxes; j++ ){
-
-/* Get the PCj_i value for this axis. Missing terms can be defaulted so
- do not report an error if the required value is not present in the
- FitsStore. */
- *el = GetItem( &(store->pc), i, j, s, NULL, method, class, status );
-
-/* Diagonal terms default to to 1.0, off-diagonal to zero. */
- if( *el == AST__BAD ) *el = ( i == j ) ? 1.0: 0.0;
-
-/* Move on to the next matrix element. */
- el++;
- }
- }
-
-/* Create the matrix. */
- new = astMatrixMap( naxes, naxes, 0, mat, "", status );
-
-/* Report an error if the inverse transformation is undefined. */
- if( !astGetTranInverse( new ) && astOK ) {
- astError( AST__BDFTS, "%s(%s): Unusable rotation matrix (PC or CD) found "
- "in the FITS-WCS header - the matrix cannot be inverted.", status, method, class );
- }
-
-/* Release the memory used to hold the matrix. */
- mat = (double *) astFree( (void *) mat );
- }
-
-/* If an error has occurred, attempt to annul the returned MatrixMap. */
- if( !astOK ) new = astAnnul( new );
-
-/* Return the MatrixMap. */
- return new;
-}
-
-static AstMapping *WcsNative( AstFitsChan *this, FitsStore *store, char s,
- AstWcsMap *wcsmap, int fits_ilon, int fits_ilat,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* WcsNative
-
-* Purpose:
-* Create a CmpMap which transforms Native Spherical Coords to
-* Celestial Coords.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* AstMapping *WcsNative( AstFitsChan *this, FitsStore *store, char s,
-* AstWcsMap *wcsmap, int fits_ilon, int fits_ilat,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A CmpMap is created which rotates the supplied Native Spherical Coords
-* into Celestial Coords in the standard system specified by the CTYPE
-* keywords. Any non-celestial axes are left unchanged.
-*
-* At the highest level, the returned CmpMap is made up of the following
-
-* Mappings in series (if celestial long/lat axes are present):
-* 1 - A PermMap which rearranges the axes so that the longitude axis is
-* axis 0, the latitude axis is axis 1, and all other axes are
-* stored at higher indices, starting at axis 2.
-* 2 - A CmpMap which converts the values on axes 0 and 1 from Native
-* Spherical to Celestial coordinates, leaving all other axes
-* unchanged.
-* 3 - A PermMap which rearranges the axes to put the longitude and
-* latitude axes back in their original places. This is just the
-* inverse of the PermMap used at stage 1 above.
-*
-* The CmpMap used at stage 2 above, is made up of two Mappings in
-
-* parallel:
-* 4 - A CmpMap which maps axes 0 and 1 from Native Spherical to
-* Celestial coordinates.
-* 5 - A UnitMap which passes on the values to axes 2, 3, etc,
-* without change.
-*
-* The CmpMap used at stage 4 above, is made up of the following Mappings
-
-* in series:
-* 6 - A SphMap which converts the supplied spherical coordinates into
-* Cartesian Coordinates.
-* 7 - A MatrixMap which rotates the Cartesian coordinates from the
-* Native to the Celestial system.
-* 8 - A SphMap which converts the resulting Cartesian coordinates back
-* to spherical coordinates.
-
-* Parameters:
-* this
-* The FitsChan in which to store any warning cards. If NULL, no
-* warnings are stored.
-* store
-* A structure containing values for FITS keywords relating to
-* the World Coordinate System.
-* s
-* Co-ordinate version character to use (space means primary axes).
-* wcsmap
-* A mapping describing the deprojection which is being used. This is
-* needed in order to be able to locate the fiducial point within the
-* Native Speherical Coordinate system, since it varies from projection
-* to projection.
-* fits_ilon
-* The zero-based FITS WCS axis index corresponding to celestial
-* longitude (i.e. one less than the value of "i" in the keyword
-* names "CTYPEi", "CRVALi", etc). If -1 is supplied, the index of
-* the longitude axis in the supplied WcsMap is used.
-* fits_ilat
-* The zero-based FITS WCS axis index corresponding to celestial
-* latitude (i.e. one less than the value of "i" in the keyword
-* names "CTYPEi", "CRVALi", etc). If -1 is supplied, the index of
-* the latitude axis in the supplied WcsMap is used.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the created CmpMap or a NULL pointer if an error occurred.
-
-* Notes:
-* - The local variable names correspond to the notation in the papers
-* by Greisen & Calabretta describing the FITS WCS system.
-*/
-
-/* Local Variables: */
- AstCmpMap *cmpmap; /* A CmpMap */
- AstMapping *new; /* The returned CmpMap */
- AstMatrixMap *matmap2; /* Another MatrixMap */
- AstMatrixMap *matmap; /* A MatrixMap */
- AstPermMap *permmap; /* A PermMap */
- AstSphMap *sphmap; /* A SphMap */
- AstUnitMap *unitmap; /* A UnitMap */
- char buf[150]; /* Message buffer */
- double alpha0; /* Long. of fiduaicl point in standard system */
- double alphap; /* Long. of native nth pole in standard system */
- double axis[3]; /* Vector giving the axis of rotation */
- double delta0; /* Lat. of fiducial point in standard system */
- double deltap; /* Lat. of native nth pole in standard system */
- double latpole; /* Lat. of native nth pole in standard system if deltap undefined */
- double phip; /* Long. of standard nth pole in native system */
- double phi0; /* Native longitude at fiducial point */
- double theta0; /* Native latitude at fiducial point */
- int *inperm; /* Pointer to array of output axis indices */
- int *outperm; /* Pointer to array of input axis indices */
- int axlat; /* Index of latitude physical axis */
- int axlon; /* Index of longitude physical axis */
- int i; /* Loop count */
- int nax_rem; /* No. of non-astrometric axes */
- int naxis; /* No. of axes. */
- int new_axlat; /* Index of lat. physical axis after perming */
- int tpn; /* Is this a TPN projection? */
-
-/* Check the global status. */
- if ( !astOK ) return NULL;
-
-/* Initialise the returned CmpMap pointer. */
- new = NULL;
-
-/* Store the number of axes in a local variable. */
- naxis = astGetNin( wcsmap );
-
-/* Get the indices of the celestial axes. */
- axlon = astGetWcsAxis( wcsmap, 0 );
- axlat = astGetWcsAxis( wcsmap, 1 );
-
-/* If the corresponding FITS axis indices were not supplied, use the
- WcsMap axes found above. */
- if( fits_ilon == -1 ) fits_ilon = axlon;
- if( fits_ilat == -1 ) fits_ilat = axlat;
-
-/* If there is no longitude or latitude axis, or if we have a
- non-celestial projection, just return a UnitMap. */
- if( axlon == axlat || astGetWcsType( wcsmap ) == AST__WCSBAD ){
- new = (AstMapping *) astUnitMap( naxis, "", status );
-
-/* If there is a lon/lat axis pair, create the inperm and outperm arrays
- which will be needed later to create the PermMap which reorganises
- the axes so that axis zero is the longitude axis and axis 1 is the
- latitude axis. */
- } else {
-
-/* Get storage for the two arrays. */
- inperm = (int *) astMalloc( sizeof( int )*(size_t)naxis );
- outperm = (int *) astMalloc( sizeof( int )*(size_t)naxis );
- if( astOK ){
-
-/* Initialise an array holding the indices of the input axes which are copied
- to each output axis. Initially assume that there is no re-arranging of
- the axes. */
- for( i = 0; i < naxis; i++ ) outperm[ i ] = i;
-
-/* Swap the longitude axis and axis 0. */
- i = outperm[ axlon ];
- outperm[ axlon ] = outperm[ 0 ];
- outperm[ 0 ] = i;
-
-/* If axis 0 was originally the latitude axis, the latitude axis will now
- be where the longitude axis was originally (because of the above axis
- swap). */
- if( axlat == 0 ) {
- new_axlat = axlon;
- } else {
- new_axlat = axlat;
- }
-
-/* Swap the latitude axis and axis 1. */
- i = outperm[ new_axlat ];
- outperm[ new_axlat ] = outperm[ 1 ];
- outperm[ 1 ] = i;
-
-/* Create the array holding the output axis index corresponding to
- each input axis. */
- for( i = 0; i < naxis; i++ ) inperm[ outperm[ i ] ] = i;
- }
-
-/* Store the latitude and longitude (in the standard system) of the fiducial
- point, in radians. */
- delta0 = GetItem( &(store->crval), fits_ilat, 0, s, NULL, method, class, status );
- if( delta0 == AST__BAD ) delta0 = 0.0;
- delta0 *= AST__DD2R;
- alpha0 = GetItem( &(store->crval), fits_ilon, 0, s, NULL, method, class, status );
- if( alpha0 == AST__BAD ) alpha0 = 0.0;
- alpha0 *= AST__DD2R;
-
-/* Limit the latitude to the range +/- PI/2, issuing a warning if the
- supplied CRVAL value is outside this range. The "alphap" variable is used
- as workspace here. */
- alphap = palDrange( delta0 );
- delta0 = alphap;
- if ( delta0 > AST__DPIBY2 ){
- delta0 = AST__DPIBY2;
- } else if ( delta0 < -AST__DPIBY2 ){
- delta0 = -AST__DPIBY2;
- }
- if( alphap != delta0 ) {
- sprintf( buf, "The original FITS header specified a fiducial "
- "point with latitude %.*g. A value of %.*g is being used "
- "instead. ", DBL_DIG, alphap*AST__DR2D, DBL_DIG,
- delta0*AST__DR2D );
- Warn( this, "badlat", buf, method, class, status );
- }
-
-/* Set a flag indicating if we have a TPN projection. The handling or
- projection parameters is different for TPN projections. */
- tpn = ( astGetWcsType( wcsmap ) == AST__TPN );
-
-/* Store the radian values of the FITS keywords LONPOLE and LATPOLE. Defaults
- will be used if either of these items was not supplied. These keyword
- values may be stored in projection parameters PVi_3a and PVi_4a for
- longitude axis "i" - in which case the "PV" values take precedence over
- the "LONPOLE" and "LATPOLE" values. Do not do this for TPN projections
- since they use these projection parameters to specify correcton terms. */
- if( astTestPV( wcsmap, axlon, 3 ) && !tpn ) {
- phip = astGetPV( wcsmap, axlon, 3 );
- } else {
- phip = GetItem( &(store->lonpole), 0, 0, s, NULL, method, class, status );
- if( phip != AST__BAD && !tpn ) astSetPV( wcsmap, axlon, 3, phip );
- }
- if( phip != AST__BAD ) phip *= AST__DD2R;
- if( astTestPV( wcsmap, axlon, 4 ) && !tpn ) {
- latpole = astGetPV( wcsmap, axlon, 4 );
- } else {
- latpole = GetItem( &(store->latpole), 0, 0, s, NULL, method, class, status );
- if( latpole != AST__BAD && !tpn ) astSetPV( wcsmap, axlon, 4, latpole );
- }
- if( latpole != AST__BAD ) latpole *= AST__DD2R;
-
-/* Find the standard Celestial Coordinates of the north pole of the Native
- Spherical Coordinate system. Report an error if the position was not
- defined. */
- if( !WcsNatPole( this, wcsmap, alpha0, delta0, latpole, &phip, &alphap,
- &deltap, status ) && astOK ){
- astError( AST__BDFTS, "%s(%s): Conversion from FITS WCS native "
- "coordinates to celestial coordinates is ill-conditioned.", status,
- method, class );
- }
-
-/* Create the SphMap which converts spherical coordinates to Cartesian
- coordinates (stage 6 in the prologue). This asumes that axis 0 is the
- longitude axis, and axis 1 is the latitude axis. This will be ensured
- by a PermMap created later. Indicate that the SphMap will only be used
- to transform points on a unit sphere. This enables a forward SphMap
- to be combined with an inverse SphMap into a UnitMap, and thus aids
- simplification. */
- sphmap = astSphMap( "UnitRadius=1", status );
- astInvert( sphmap );
-
-/* Set the PolarLong attribute of the SphMap so that a longitude of phi0 (the
- native longitude of the fiducial point) is returned by the inverse
- transformation (cartesian->spherical) at either pole. */
- GetFiducialNSC( wcsmap, &phi0, &theta0, status );
- astSetPolarLong( sphmap, phi0 );
-
-/* Create a unit MatrixMap to be the basis of the MatrixMap which rotates
- Native Spherical Coords to Celestial Coords (stage 7 in the prologue). */
- matmap = astMatrixMap( 3, 3, 2, NULL, "", status );
-
-/* Modify the above MatrixMap so that it rotates the Cartesian position vectors
- by -phip (i.e. LONPOLE) about the Z axis. This puts the north pole of the
- standard system at zero longitude in the rotated system. Then annul the
- original MatrixMap and use the new one instead. */
- axis[ 0 ] = 0;
- axis[ 1 ] = 0;
- axis[ 2 ] = 1;
- matmap2 = astMtrRot( matmap, -phip, axis );
- matmap = astAnnul( matmap );
- matmap = matmap2;
-
-/* Now modify the above MatrixMap so that it rotates the Cartesian position
- vectors by -(PI/2-deltap) about the Y axis. This puts the north pole of
- the standard system as 90 degrees latitude in the rotated system. Then annul
- the original MatrixMap and use the new one instead. */
- axis[ 0 ] = 0;
- axis[ 1 ] = 1;
- axis[ 2 ] = 0;
- matmap2 = astMtrRot( matmap, deltap - AST__DPIBY2, axis );
- matmap = astAnnul( matmap );
- matmap = matmap2;
-
-/* Finally modify the above MatrixMap so that it rotates the Cartesian position
- vectors (PI+alphap) about the Z axis. This puts the primary meridian of the
- standard system at zero longitude in the rotated system. This results in the
- rotated system being coincident with the standard system. */
- axis[ 0 ] = 0;
- axis[ 1 ] = 0;
- axis[ 2 ] = 1;
- matmap2 = astMtrRot( matmap, AST__DPI + alphap, axis );
- matmap = astAnnul( matmap );
- matmap = matmap2;
-
-/* Combine the SphMap (stage 6) and MatrixMap (stage 7) in series. */
- cmpmap = astCmpMap( sphmap, matmap, 1, "", status );
- sphmap = astAnnul( sphmap );
- matmap = astAnnul( matmap );
-
-/* Create a new SphMap which converts Cartesian coordinates to spherical
- coordinates (stage 8 in the prologue). Indicate that the SphMap will
- only be used to transform points on a unit sphere. */
- sphmap = astSphMap( "UnitRadius=1", status );
-
-/* Set the PolarLong attribute of the SphMap so that a longitude of alpha0
- (the celestial longitude of the fiducial point) is returned by the
- forward transformation (cartesian->spherical) at either pole. */
- astSetPolarLong( sphmap, alpha0 );
-
-/* Add it to the compound mapping. The CmpMap then corresponds to stage 4
- in the prologue. Annul the constituent mappings. */
- new = (AstMapping *) astCmpMap( cmpmap, sphmap, 1, "", status );
- cmpmap = astAnnul( cmpmap );
- sphmap = astAnnul( sphmap );
-
-/* If there are any remaining axes (i.e. axes which do not describe a
- Celestial coordinate system), create a UnitMap which passes on their
- values unchanged (stage 5 in the prologue), and add it the CmpMap,
- putting it in parallel with the earlier mappings. The resulting CmpMap
- then corresponds to stage 2 in the prologue. Note, the axis numbering
- used by this UnitMap needs to take account of the fact that it is only
- applied to the non-celestial axes. The axes are re-ordered by the
- PermMap described at stage 1 in the prologue. */
- nax_rem = naxis - 2;
- if( nax_rem > 0 ){
- unitmap = astUnitMap( nax_rem, "", status );
- cmpmap = astCmpMap( new, unitmap, 0, "", status );
- new = astAnnul( new );
- unitmap = astAnnul( unitmap );
- new = (AstMapping *) cmpmap;
- }
-
-/* Now we need to ensure that axes 0 and 1 correspond to longitude and
- latitude. If this is already the case, then the CmpMap can be returned
- as it is. Otherwise, a PermMap needs to be created to rearrange the
- axes. */
- if( axlon != 0 || axlat != 1 ){
-
-/* Create the PermMap using the inperm and outperm arrays created earlier.
- This is the mapping described as stage 1 in the prologue. */
- permmap = astPermMap( naxis, inperm, naxis, outperm, NULL, "", status );
-
-/* Compound this PermMap and the CmpMap corresponding to stage 2 (created
- earlier) in series. */
- cmpmap = astCmpMap( permmap, new, 1, "", status );
- new = astAnnul( new );
- new = (AstMapping *) cmpmap;
-
-/* Now invert the PermMap, so that it re-arranges the axes back into
- their original order. This is the mapping described as stage 3 in
- the prologue. */
- astInvert( permmap );
-
-/* And finally.... add this inverted PermMap onto the end of the CmpMap. */
- cmpmap = astCmpMap( new, permmap, 1, "", status );
- permmap = astAnnul( permmap );
- new = astAnnul( new );
- new = (AstMapping *) cmpmap;
- }
-
-/* Free the temporary arrays. */
- inperm = (int *) astFree( (void *) inperm );
- outperm = (int *) astFree( (void *) outperm );
- }
-
-/* If an error has occurred, attempt to annul the new CmpMap. */
- if( !astOK ) new = astAnnul( new );
-
-/* Return the CmpMap. */
- return new;
-}
-
-static int WcsNatPole( AstFitsChan *this, AstWcsMap *wcsmap, double alpha0,
- double delta0, double latpole, double *phip,
- double *alphap, double *deltap, int *status ){
-
-/*
-* Name:
-* WcsNatPole
-
-* Purpose:
-* Find the celestial coordinates of the north pole of the Native Spherical
-* Coordinate system.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* int WcsNatPole( AstFitsChan *this, AstWcsMap *wcsmap, double alpha0,
-* double delta0, double latpole, double *phip,
-* double *alphap, double *deltap, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* The supplied WcsMap converts projected positions given in
-* "Projection Plane Coords" to positions in the "Native Spherical
-* Coordinate" system. This function finds the pole of this spherical
-* coordinate system in terms of the standard celestial coordinate
-* system to which the CRVALi, LONPOLE and LATPOLE keywords refer (this
-* system should be identified by characters 5-8 of the CTYPEi
-* keywords). It also supplies a default value for LONPOLE if no value
-* has been supplied explicitly in the FITS header.
-*
-* This function implements equations 8, 9 and 10 from the FITS-WCS paper
-* II by Calabretta & Greisen (plus the associated treatment of special
-* cases). The paper provides more detailed documentation for the
-* mathematics implemented by this function.
-
-* Parameters:
-* this
-* The FitsChan in which to store any warning cards. If NULL, no
-* warnings are stored.
-* wcsmap
-* A mapping describing the deprojection being used (i.e. the
-* mapping from Projection Plane Coords to Native Spherical Coords).
-* alpha0
-* The longitude of the fiducial point in the standard celestial
-* coordinate frame (in radians). Note, this fiducial point does
-* not necessarily correspond to the point given by keywords CRPIXj.
-* delta0
-* The celestial latitude (radians) of the fiducial point.
-* latpole
-* The value of FITS keyword LATPOLE, converted to radians, or the
-* symbolic constant AST__BAD if the keyword was not supplied.
-* phip
-* Pointer to a location at which is stored the longitude of the north
-* pole of the standard Celestial coordinate system, as measured in
-* the Native Spherical Coordinate system, in radians. This should be
-* supplied holding the radian equivalent of the value of the FITS
-* keyword LONPOLE, or the symbolic constant AST__BAD if the keyword was
-* not supplied (in which case a default value will be returned at the
-* given location).
-* alphap
-* Pointer to a location at which to store the calculated longitude
-* of the Native North Pole, in radians.
-* deltap
-* Pointer to a location at which to store the calculated latitude
-* of the Native North Pole, in radians.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A status: non-zero for success, zero if the position of the native
-* north pole is undefined.
-
-* Notes:
-* - Certain combinations of keyword values result in the latitude of
-* the Native North Pole being undefined. In these cases, a value of
-* 0 is returned for the function value, but no error is reported.
-* - All angular values used by this function are in radians.
-* - A value of 0 is returned if an error has already occurred.
-*/
-
-/* Local Variables: */
- char buf[150]; /* Buffer for warning message */
- double cos_theta0; /* Cosine of theta0 */
- double cos_phip; /* Cosine of (phip - phi0) */
- double cos_delta0; /* Cosine of delta0 */
- double cos_deltap; /* Cosine of deltap */
- double deltap_1; /* First possible value for deltap */
- double deltap_2; /* Second possible value for deltap */
- double sin_theta0; /* Sine of theta0 */
- double sin_phip; /* Sine of (phip - phi0) */
- double sin_delta0; /* Sine of delta0 */
- double sin_deltap; /* Sine of deltap */
- double t0, t1, t2, t3, t4; /* Intermediate values */
- double phi0, theta0; /* Native coords of fiducial point */
-
-/* Check the global status. */
- if ( !astOK ) return 0;
-
-/* Get the longitude and latitude of the fiducial point in the native
- spherical coordinate frame (in radians). */
- GetFiducialNSC( wcsmap, &phi0, &theta0, status );
-
-/* If no value was supplied for the FITS keyword LONPOLE, set up a default
- value such that the celestial latitude increases in the same direction
- as the native latitude at the fiducial; point. */
- if( *phip == AST__BAD ){
- if( delta0 >= theta0 ){
- *phip = 0.0;
- } else {
- *phip = AST__DPI;
- }
-
-/* Issue a warning that a default lonpole value has been adopted. */
- sprintf( buf, "The original FITS header did not specify the "
- "longitude of the native north pole. A default value "
- "of %.8g degrees was assumed.", (*phip)*AST__DR2D );
- Warn( this, "nolonpole", buf, "astRead", "FitsChan", status );
- }
-
-/* If the fiducial point is coincident with the Native North Pole, then the
- Native North Pole must have the same coordinates as the fiducial
- point. Tests for equality include some tolerance to allow for rounding
- errors. */
- sin_theta0 = sin( theta0 );
- if( astEQUAL( sin_theta0, 1.0 ) ){
- *alphap = alpha0;
- *deltap = delta0;
-
-/* If the fiducial point is concident with the Native South Pole, then the
- Native North Pole must have the coordinates of the point diametrically
- opposite the fiducial point. */
- } else if( astEQUAL( sin_theta0, -1.0 ) ){
- *alphap = alpha0 + AST__DPI;
- *deltap = -delta0;
-
-/* For all other cases, go through the procedure described in the WCS paper
- by Greisen & Calabretta, to find the position of the Native North Pole.
- First store some useful values. */
- } else {
- cos_theta0 = cos( theta0 );
- cos_delta0 = cos( delta0 );
- cos_phip = cos( *phip - phi0 );
- sin_delta0 = sin( delta0 );
- sin_phip = sin( *phip - phi0 );
-
-/* Next, find the two possible values for the latitude of the Native
- North Pole (deltap). If any stage of this transformation is
- indeterminate, return zero (except for the single special case noted
- in item 6 para. 2 of the WCS paper, for which LATPOLE specifies the
- values to be used). */
- t0 = cos_theta0*cos_phip;
- if( fabs( t0 ) < TOL2 && fabs( sin_theta0 ) < TOL2 ){
- if( latpole != AST__BAD ) {
- *deltap = latpole;
- } else {
- return 0;
- }
- } else {
- t1 = atan2( sin_theta0, t0 );
- t2 = cos_theta0*cos_phip;
- t2 *= t2;
- t2 += sin_theta0*sin_theta0;
- if( t2 <= DBL_MIN ){
- return 0;
- } else {
- t3 = sin_delta0/sqrt( t2 );
- if( fabs( t3 ) > 1.0 + TOL1 ){
- return 0;
- } else {
- if( t3 < -1.0 ){
- t4 = AST__DPI;
- } else if( t3 > 1.0 ){
- t4 = 0.0;
- } else {
- t4 = acos( t3 );
- }
- deltap_1 = palDrange( t1 + t4 );
- deltap_2 = palDrange( t1 - t4 );
-
-/* Select which of these two values of deltap to use. Values outside the
- range +/- PI/2 cannot be used. If both values are within this range
- use the value which is closest to the supplied value of latpole (or
- use the northern most value if the LATPOLE keyword was not supplied. */
- if( fabs( deltap_1 ) > AST__DPIBY2 + TOL2 ){
- *deltap = deltap_2;
- } else if( fabs( deltap_2 ) > AST__DPIBY2 + TOL2 ){
- *deltap = deltap_1;
- } else {
- if( latpole != AST__BAD ){
- if( fabs( deltap_1 - latpole ) <
- fabs( deltap_2 - latpole ) ){
- *deltap = deltap_1;
- } else {
- *deltap = deltap_2;
- }
- } else {
- if( deltap_1 > deltap_2 ){
- *deltap = deltap_1;
- } else {
- *deltap = deltap_2;
- }
-
-/* Issue a warning that a default latpole value has been adopted. */
- sprintf( buf, "The original FITS header did not specify "
- "the latitude of the native north pole. A "
- "default value of %.8g degrees was assumed.",
- (*deltap)*AST__DR2D );
- Warn( this, "nolatpole", buf, "astRead", "FitsChan", status );
- }
- }
- if( fabs( *deltap ) > AST__DPIBY2 + TOL2 ) {
- return 0;
- } else if( *deltap < -AST__DPIBY2 ){
- *deltap = -AST__DPIBY2;
- } else if( *deltap > AST__DPIBY2 ){
- *deltap = AST__DPIBY2;
- }
- }
- }
- }
-
-/* If a valid value for the latitude (deltap) has been found, find the
- longitude of the Native North Pole. */
- if( *deltap != AST__BAD ) {
- if( fabs( cos_delta0) > TOL2 ){
- cos_deltap = cos( *deltap );
- sin_deltap = sin( *deltap );
- if( fabs( cos_deltap ) > TOL2 ){
- t1 = sin_phip*cos_theta0/cos_delta0;
- t2 = ( sin_theta0 - sin_deltap*sin_delta0 )
- /( cos_delta0*cos_deltap );
- if( ( fabs( t1 ) > TOL2 ) || ( fabs( t2 ) > TOL2 ) ){
- *alphap = alpha0 - atan2( t1, t2 );
- } else {
- *alphap = alpha0;
- }
- } else if( sin_deltap > 0.0 ){
- *alphap = alpha0 + (*phip - phi0) - AST__DPI;
- } else {
- *alphap = alpha0 - (*phip - phi0);
- }
- } else {
- *alphap = alpha0;
- }
- } else {
- *alphap = AST__BAD;
- }
- }
-
-/* Return a success status if valid latitude and longitude values were
- found. */
- return (*deltap) != AST__BAD && (*alphap) != AST__BAD ;
-}
-
-static AstMapping *WcsOthers( AstFitsChan *this, FitsStore *store, char s,
- AstFrame **frm, AstFrame *iwcfrm, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* WcsOthers
-
-* Purpose:
-* Create a Mapping from intermediate world coords to any axes
-* which are not covered by specialised conventions.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* AstMapping *WcsOthers( AstFitsChan *this, FitsStore *store, char s,
-* AstFrame **frm, AstFrame *iwcfrm, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function interprets the contents of the supplied FitsStore
-* structure, looking for world coordinate axes for which no
-* description has yet been added to the supplied Frame . It is
-* assumed that any such axes are simple linear axes. It returns a
-* Mapping which simply adds on the CRVAL values to such axes.
-* It also modifies the supplied Frame to describe the axes.
-
-* Parameters:
-* this
-* The FitsChan.
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* frm
-* The address of a location at which to store a pointer to the
-* Frame describing the world coordinate axes.
-* iwcfrm
-* A pointer to the Frame describing the intermediate world coordinate
-* axes. The properties of this Frame may be changed on exit.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the Mapping.
-*/
-
-/* Local Variables: */
- AstFrame *pfrm; /* Pointer to primary Frame */
- AstFrame *pfrm2; /* Pointer to primary Frame */
- AstMapping *map1; /* Pointer to a Mapping */
- AstMapping *map2; /* Pointer to a Mapping */
- AstMapping *ret; /* The returned Mapping */
- char **comms; /* Pointer to array of CTYPE commments */
- char buf[ 100 ]; /* Buffer for textual attribute value */
- char buf2[ 100 ]; /* Buffer for textual attribute value */
- char buf3[ 20 ]; /* Buffer for default CTYPE value */
- char *newdom; /* Pointer to new Domain value */
- const char *ckeyval; /* Pointer to character keyword value */
- int i; /* Axis index */
- int j; /* Axis index */
- int len; /* Used length of string */
- int naxes; /* no. of axes in Frame */
- int nother; /* The number of "other" axes */
- int paxis; /* Primary axis index */
- int usecom; /* Use CTYPE comments as axis Labels? */
-
-/* Initialise the pointer to the returned Mapping. */
- ret = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return ret;
-
-/* Get the number of physical axes. */
- naxes = astGetNaxes( *frm );
-
-/* Assume we will use CTYPE comments as the axis labels. */
- usecom = 1;
-
-/* Initialise the count of "other" axes. */
- nother = 0;
-
-/* Get the comments associated with the CTYPE keywords for all "other"
- axes. */
- comms = astMalloc( naxes*sizeof( char * ) );
- if( comms ) {
-
-/* Loop round all axes in the Frame, and initialise the pointer to its
- comment. */
- for( i = 0; i < naxes; i++ ){
- comms[ i ] = NULL;
-
-/* Get the Domain for the primary frame containing the axis. This will be
- "AST_FITSCHAN" if the axis has not yet been recognised (this Domain is
- set up by WcsMapFrm). Only consider the axis further if the Domain has
- not been changed. */
- astPrimaryFrame( *frm, i, &pfrm, &paxis );
- if( !strcmp( astGetDomain( pfrm ), "AST_FITSCHAN" ) ) {
-
-/* Increment the count of "other" axes. */
- nother++;
-
-/* Get the comment associated with the CTYPE header. */
- ckeyval = GetItemC( &(store->ctype_com), i, 0, s, NULL, method, class, status );
-
-/* If this axis has no CTYPE comment, we will use CTYPE values as axis
- labels (if given, the CNAME keyword take precedence). */
- if( !ckeyval || astChrLen( ckeyval ) == 0 ) {
- usecom = 0;
-
-/* If the CTYPE comment for this axis is the same as any other comment, we
- will use CTYPE values as axis labels. */
- } else {
- for( j = 0; j < nother - 1; j++ ) {
- if( comms[ j ] && !strcmp( ckeyval, comms[ j ] ) ) {
- usecom = 0;
- break;
- }
- }
- }
-
-/* If we are still using comments as axis labels, store a copy of it in the
- workspace. */
- if( usecom ) comms[ i ] = astStore( NULL, ckeyval,
- strlen( ckeyval ) + 1 );
- }
- pfrm = astAnnul( pfrm );
- }
-
-/* Free the workspace holding comments. */
- for( i = 0; i < naxes; i++ ) comms[ i ] = astFree( comms[ i ] );
- comms = astFree( comms );
- }
-
-/* If there are no "other" axes, just return a UnitMap. */
- if( nother == 0 ) {
- ret = (AstMapping *) astUnitMap( naxes, "", status );
-
-/* Otherwise... */
- } else {
-
-/* If we have only a single other axis, use CTYPE value instead of
- comment. */
- if( nother == 1 ) usecom = 0;
-
-/* Not yet started a new Domain value to replace "AST_FITSCHAN". */
- newdom = NULL;
- pfrm2 = NULL;
-
-/* Check each axis of the Frame looking for axes which have not yet been
- recognised. */
- for( i = 0; i < naxes; i++ ) {
-
-/* Get the Domain for the primary frame containing the axis. This will be
- "AST_FITSCHAN" if the axis has not yet been recognised (this Domain is
- set up by WcsMapFrm). Only consider the axis further if the Domain has
- not been changed. */
- astPrimaryFrame( *frm, i, &pfrm, &paxis );
- if( !strcmp( astGetDomain( pfrm ), "AST_FITSCHAN" ) ) {
-
-/* Save a pointer to the primary Frame which we will use to set the
- Domain of the primary Frame. */
- if( !pfrm2 ) pfrm2 = astClone( pfrm );
-
-/* Get the CTYPE value. Use a default of "AXISn". */
- ckeyval = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- if( !ckeyval ) {
- sprintf( buf3, "AXIS%d", i + 1 );
- ckeyval = buf3;
- }
-
-/* If the CTYPE value ends with "-LOG", assume it is a logarithmically spaced
- axis. Get the Mapping from IWC to WCS. Reduce the used length of the
- CTYPE string to exlude any trailing "-LOG" string. */
- len = strlen( ckeyval );
- if( len > 3 && !strcmp( ckeyval + len - 4, "-LOG" ) ){
- map1 = LogWcs( store, i, s, method, class, status );
- sprintf( buf2, "%.*s", len - 4, ckeyval );
-
-/* Otherwise, assume the axis is linearly spaced. */
- } else {
- map1 = LinearWcs( store, i, s, method, class, status );
- sprintf( buf2, "%.*s", len, ckeyval );
- }
-
-/* Append the CTYPE value to the final Domain value for the primary Frame. */
- if( ckeyval && astChrLen( ckeyval ) > 0 ) {
- if( newdom ) {
- sprintf( buf, "%s-%s", newdom, buf2 );
- } else {
- sprintf( buf, "%s", buf2 );
- newdom = buf;
- }
- }
-
-/* Now modify the axis in the Frame to have appropriate values for the
- Unit, Label and Symbol attributes. Also set the Unit attribute for
- the corresponding axis in the IWC Frame. */
- if( ckeyval ) astSetSymbol( *frm, i, buf2 );
- ckeyval = GetItemC( &(store->cname), i, 0, s, NULL, method, class, status );
- if( !ckeyval && usecom ) ckeyval = GetItemC( &(store->ctype_com),
- i, 0, s, NULL, method, class, status );
- if( !ckeyval ) ckeyval = buf2;
- if( ckeyval ) astSetLabel( *frm, i, ckeyval );
- ckeyval = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status );
- if( ckeyval ) {
- astSetUnit( *frm, i, ckeyval );
- astSetUnit( iwcfrm, i, ckeyval );
- }
-
-/* If this axis has been described by an earlier function (because it
- uses specialised conventions such as those described in FITS-WCS papers
- II or III), then create a UnitMap for this axis. */
- } else {
- map1 = (AstMapping *) astUnitMap( 1, "", status );
- }
-
-/* Annul the pointer to the primary Frame containing the current axis. */
- pfrm = astAnnul( pfrm );
-
-/* Add the Mapping for this axis in parallel with the current "running sum"
- Mapping (if any). */
- if( ret ) {
- map2 = (AstMapping *) astCmpMap( ret, map1, 0, "", status );
- ret = astAnnul( ret );
- map1 = astAnnul( map1 );
- ret = map2;
- } else {
- ret = map1;
- }
- }
-
-/* Set the Domain name for the primary Frame. It is currently set to
- AST_FITSCHAN. We replace it with a value formed by concatenating the
- CTYPE values of its axes. */
- if( pfrm2 ) {
- if( newdom && astChrLen( newdom ) > 0 ) {
- astSetDomain( pfrm2, newdom );
- } else {
- astClearDomain( pfrm2 );
- }
- pfrm2 = astAnnul( pfrm2 );
- }
-
-/* If the header contained a WCSNAME keyword, use it as the Domain name for
- the Frame. Also use it to create a title. */
- ckeyval = GetItemC( &(store->wcsname), 0, 0, s, NULL, method, class, status );
- if( ckeyval ){
- astSetDomain( *frm, ckeyval );
- sprintf( buf, "%s coordinates", ckeyval );
- astSetTitle( *frm, buf );
- }
- }
-
-/* Return the result. */
- return ret;
-}
-
-static AstWinMap *WcsShift( FitsStore *store, char s, int naxes,
- const char *method, const char *class, int *status ){
-/*
-* Name:
-* WcsShift
-
-* Purpose:
-* Create a WinMap which shifts pixels coordinates so that their origin
-* is at the reference pixel.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstWinMap *WcsShift( FitsStore *store, char s, int naxes,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* A WinMap is created which implements a shift of origin by subtracting
-* the reference pixel coordinates (CRPIXi) from the input pixel
-* coordinates.
-
-* Parameters:
-* store
-* A structure containing values for FITS keywords relating to
-* the World Coordinate System.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* naxes
-* The number of intermediate world coordinate axes (WCSAXES).
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the created WinMap or a NULL pointer if an
-* error occurred.
-
-* Notes:
-* - If an error occurs, a NULL pointer is returned.
-*/
-
-/* Local Variables: */
- AstWinMap *new; /* The created WinMap */
- int j; /* Pixel axis index */
- double crpix; /* CRPIX keyword value */
- double *c1_in; /* Input corner 1 */
- double *c2_in; /* Input corner 2 */
- double *c1_out; /* Output corner 1 */
- double *c2_out; /* Output corner 2 */
-
-/* Check the global status. */
- if ( !astOK ) return NULL;
-
-/* Initialise the returned WinMap pointer. */
- new = NULL;
-
-/* Allocate memory to hold the two corners, in both input and output
- coordinates. */
- c1_in = (double *) astMalloc( sizeof( double )*(size_t) naxes );
- c1_out = (double *) astMalloc( sizeof( double )*(size_t) naxes );
- c2_in = (double *) astMalloc( sizeof( double )*(size_t) naxes );
- c2_out = (double *) astMalloc( sizeof( double )*(size_t) naxes );
-
-/* Check these pointers can be used. */
- if( astOK ){
-
-/* Set up two arbitrary corners in the input coordinate system, and the
- corresponding values with the CRPIX values subtracted off. */
- for( j = 0; j < naxes; j++ ){
-
-/* Get the CRPIX value for this axis. */
- crpix = GetItem( &(store->crpix), 0, j, s, NULL, method, class, status );
- if( crpix == AST__BAD ) crpix = 0.0;
-
-/* Store the corner co-ordinates. */
- c1_in[ j ] = 0.0;
- c2_in[ j ] = 1.0;
- c1_out[ j ] = -crpix;
- c2_out[ j ] = 1.0 - crpix;
- }
-
-/* Create the WinMap. */
- new = astWinMap( naxes, c1_in, c2_in, c1_out, c2_out, "", status );
-
-/* If an error has occurred, attempt to annul the new WinMap. */
- if( !astOK ) new = astAnnul( new );
- }
-
-/* Free the memory holding the corners. */
- c1_in = (double *) astFree( (void *) c1_in );
- c1_out = (double *) astFree( (void *) c1_out );
- c2_in = (double *) astFree( (void *) c2_in );
- c2_out = (double *) astFree( (void *) c2_out );
-
-/* Return the WinMap. */
- return new;
-}
-
-static AstSkyFrame *WcsSkyFrame( AstFitsChan *this, FitsStore *store, char s,
- int prj, char *sys, int axlon, int axlat,
- const char *method, const char *class, int *status ){
-
-/*
-* Name:
-* WcsSkyFrame
-
-* Purpose:
-* Create a SkyFrame to describe a WCS celestial coordinate system.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstSkyFrame *WcsSkyFrame( AstFitsChan this, FitsStore *store, char s, int prj,
-* char *sys, int axlon, int axlat, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A SkyFrame is returned describing the celestial coordinate system
-* described by a FITS header. The axes are *not* permuted in the
-* returned Frame (that is, axis 0 is longitude and axis 1 is latitude
-* in the returned SkyFrame, no matter what values are supplied for
-* "axlat" and "axlon").
-
-* Parameters:
-* this
-* The FitsChan from which the keywords were read. Warning messages
-* may be added to this FitsChan.
-* store
-* A structure containing values for FITS keywords relating to
-* the World Coordinate System.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* prj
-* An integer code for the WCS projection being used.
-* sys
-* A pointer to a string identifying the celestial co-ordinate system
-* implied by the CTYPE values in the FitsStore. This will be "EQU" (for
-* equatorial), or a one or two character code extracted from the
-* CTYPE values.
-* axlon
-* Zero based index of the longitude axis in the FITS header.
-* axlat
-* Zero based index of the latitude axis in the FITS header.
-* method
-* The calling method. Used only in error messages.
-* class
-* The object class. Used only in error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the SkyFrame.
-
-* Notes:
-* - A NULL pointer is returned if an error has already occurred, or
-* if this function should fail for any reason.
-*/
-
-/* Local Variables: */
- AstSkyFrame *ret; /* Returned Frame */
- char *ckeyval; /* Pointer to string item value */
- char *lattype; /* Pointer to latitude CTYPE value */
- char *lontype; /* Pointer to longitude CTYPE value */
- char bj; /* Besselian/Julian selector */
- char buf[300]; /* Text buffer */
- char sym[10]; /* Axis symbol */
- double dval; /* Floating point attribute value */
- double eqmjd; /* MJD equivalent of equinox */
- double equinox; /* EQUINOX value */
- double geolat; /* Observer's geodetic latitude */
- double geolon; /* Observer's geodetic longitude */
- double h; /* Observer's geodetic height */
- double mjdobs; /* MJD-OBS value */
- double obsgeo[ 3 ]; /* Observer's Cartesian position */
- int radesys; /* RADESYS value */
- int report; /* Report unknown lon/lat system? */
-
-/* Initialise. */
- ret = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return ret;
-
-/* Get the RADESYS keyword from the header, and identify the value.
- Store a integer value identifying the system. Report an error if an
- unrecognised system is supplied. Store NORADEC if the keyword was
- not supplied. */
- ckeyval = GetItemC( &(store->radesys), 0, 0, s, NULL, method, class, status );
- radesys = NORADEC;
- if( ckeyval ){
- if( !strncmp( ckeyval, "FK4 ", 4 ) ||
- !strcmp( ckeyval, "FK4" ) ){
- radesys = FK4;
- } else if( !strncmp( ckeyval, "FK4-NO-E", 8 ) ){
- radesys = FK4NOE;
- } else if( !strncmp( ckeyval, "FK5 ", 4 ) ||
- !strcmp( ckeyval, "FK5" ) ){
- radesys = FK5;
- } else if( !strncmp( ckeyval, "ICRS ", 5 ) ||
- !strcmp( ckeyval, "ICRS" ) ){
- radesys = ICRS;
- } else if( !strncmp( ckeyval, "GAPPT ", 6 ) ||
- !strcmp( ckeyval, "GAPPT" ) ){
- radesys = GAPPT;
- } else if( astOK ){
- astError( AST__BDFTS, "%s(%s): FITS keyword '%s' has the "
- "unrecognised value '%s'.", status, method, class,
- FormatKey( "RADESYS", -1, -1, s, status ), ckeyval );
- }
- } else {
- radesys = NORADEC;
- }
-
-/* Get the value of the EQUINOX keyword. */
- equinox = GetItem( &(store->equinox), 0, 0, s, NULL, method, class, status );
-
-/* For FK4 and FK4-NO-E any supplied equinox value is Besselian. For all
- other systems, the equinox value is Julian. */
- bj = 0;
- if( equinox != AST__BAD ){
- if( radesys == FK4 || radesys == FK4NOE ){
- bj = 'B';
- } else if( radesys != NORADEC ) {
- bj = 'J';
-
-/* If no RADESYS was suppied, but an equinox was, use the IAU 1984 rule
- to determine the default RADESYS and equinox type. */
- } else {
- if( equinox < 1984.0 ){
- radesys = FK4;
- bj = 'B';
- } else {
- radesys = FK5;
- bj = 'J';
- }
-
-/* If an equatorial system is being used, give a warning that a default RADESYS
- value is being used. */
- if( !strcmp( sys, "EQU" ) ){
- sprintf( buf, "The original FITS header did not specify the "
- "RA/DEC reference frame. A default value of %s was "
- "assumed.", ( radesys == FK4 ) ? "FK4" : "FK5" );
- Warn( this, "noradesys", buf, method, class, status );
- }
- }
-
-/* If no equinox was supplied, use a default equinox value depending
- on the frame of reference. For FK4-based systems, use B1950. */
- } else {
- if( radesys == FK4 || radesys == FK4NOE ){
- equinox = 1950.0;
- bj = 'B';
-
-/* For FK5-based systems, use J2000. */
- } else if( radesys == FK5 ){
- equinox = 2000.0;
- bj = 'J';
-
-/* If no RADESYS or EQUINOX was supplied, assume either FK4 B1950 or ICRS -
- as decided by attribute DefB1950 (GAPPT and ICRS do not use EQUINOX). */
- } else if( radesys == NORADEC ) {
- if( astGetDefB1950( this ) ) {
- equinox = 1950.0;
- bj = 'B';
- radesys = FK4;
- } else {
- radesys = ICRS;
- }
- if( !strcmp( sys, "EQU" ) ){
- sprintf( buf, "The original FITS header did not specify the "
- "RA/DEC reference frame. A default value of %s was "
- "assumed.", ( radesys == FK4 ) ? "FK4" : "ICRS" );
- Warn( this, "noradesys", buf, method, class, status );
- }
- }
-
-/* If we have an equatorial or ecliptic system, issue a warning that a default
- equinox has been adopted. */
- if( ( !strcmp( sys, "EQU" ) && radesys != ICRS && radesys != GAPPT ) ||
- !strcmp( sys, "ECL" ) ){
- sprintf( buf, "The original FITS header did not specify the "
- "reference equinox. A default value of %c%.8g was "
- "assumed.", bj, equinox );
- Warn( this, "noequinox", buf, method, class, status );
- }
- }
-
-/* Convert the equinox to a Modified Julian Date. */
- if( equinox != AST__BAD ) {
- if( bj == 'B' ) {
- eqmjd = palEpb2d( equinox );
- } else {
- eqmjd = palEpj2d( equinox );
- }
- } else {
- eqmjd = AST__BAD;
- }
-
-/* Get a value for the Epoch attribute. If no value is available, use
- EQUINOX and issue a warning. */
- mjdobs = ChooseEpoch( this, store, s, method, class, status );
- if( mjdobs == AST__BAD ) {
- mjdobs = eqmjd;
- if( mjdobs != AST__BAD ) {
- sprintf( buf, "The original FITS header did not specify the "
- "date of observation. A default value of %c%.8g was "
- "assumed.", bj, equinox );
- Warn( this, "nomjd-obs", buf, method, class, status );
- }
- }
-
-/* Create a SkyFrame for the specified system. */
- if( !strcmp( sys, "E" ) ){
- ret = astSkyFrame( "System=Ecliptic", status );
- } else if( !strcmp( sys, "H" ) ){
- ret = astSkyFrame( "System=Helioecliptic", status );
- } else if( !(strcmp( sys, "G" ) ) ){
- ret = astSkyFrame( "System=Galactic", status );
- } else if( !(strcmp( sys, "S" ) ) ){
- ret = astSkyFrame( "System=Supergalactic", status );
- } else if( !(strcmp( sys, "AZL" ) ) ){
- ret = astSkyFrame( "System=AzEl", status );
- } else if( !(strcmp( sys, "EQU" ) ) ){
-
-/* For equatorial systems, the specific system is given by the RADESYS
- value. */
- if( radesys == FK4 ){
- ret = astSkyFrame( "System=FK4", status );
- } else if( radesys == FK4NOE ){
- ret = astSkyFrame( "System=FK4-NO-E", status );
- } else if( radesys == FK5 ){
- ret = astSkyFrame( "System=FK5", status );
- } else if( radesys == ICRS ){
- ret = astSkyFrame( "System=ICRS", status );
- } else if( radesys == GAPPT ){
- ret = astSkyFrame( "System=GAPPT", status );
- } else if( astOK ){
- astError( AST__INTER, "%s(%s): Internal AST programming "
- "error - FITS equatorial coordinate system type %d "
- "not yet supported in WcsSkyFrame.", status, method, class, radesys );
- }
-
-/* If an unknown celestial co-ordinate system was specified by the CTYPE
- keywords, add warning messages to the FitsChan and treat the axes as
- a general spherical coordinate system. */
- } else if( astOK ){
- report = 1;
- ret = astSkyFrame( "System=UNKNOWN", status );
- strcpy( sym, sys );
- if( strlen( sys ) == 1 ) {
- strcpy( sym + 1, "LON" );
- astSetSymbol( ret, 0, sym );
- strcpy( sym + 1, "LAT" );
- astSetSymbol( ret, 1, sym );
- } else {
- strcpy( sym + 2, "LN" );
- astSetSymbol( ret, 0, sym );
- strcpy( sym + 2, "LT" );
- astSetSymbol( ret, 1, sym );
-
-/* The code "OF" is used by AST to describe offset sky coordinates. Set
- the Domain to SKY_OFFSETS in these cases, so that we can identify
- these Frames later. */
- if( !strcmp( sys, "OF" ) ) {
- astSetDomain( ret, "SKY_OFFSETS" );
- report = 0;
- }
- }
-
- if( report ) {
- lontype = GetItemC( &(store->ctype), axlon, 0, s, NULL, method, class, status );
- lattype = GetItemC( &(store->ctype), axlat, 0, s, NULL, method, class, status );
- if( lontype && lattype ){
- sprintf( buf, "This FITS header contains references to an unknown "
- "spherical co-ordinate system specified in the values "
- "%s and %s. It may not be possible to convert to "
- "other standard co-ordinate systems.", lontype, lattype );
- Warn( this, "badcel", buf, method, class, status );
- }
- }
- }
-
-/* If a skyFrame was created... */
- if( ret ){
-
-/* Store the projection description. */
- if( prj != AST__WCSBAD ) astSetProjection( ret, astWcsPrjDesc( prj ) );
-
-/* Store the epoch of the observation in the SkyFrame. */
- if( mjdobs != AST__BAD ) astSetEpoch( ret, mjdobs );
-
-/* For equatorial and ecliptic systems, store the epoch of the reference
- equinox in the SkyFrame. */
- if( ( !strcmp( sys, "EQU" ) || !strcmp( sys, "ECL" ) ) &&
- equinox != AST__BAD ) astSetEquinox( ret, eqmjd );
-
-/* If either of the CNAME keywords is set, use it as the axis label. */
- ckeyval = GetItemC( &(store->cname), axlon, 0, s, NULL, method, class, status );
- if( ckeyval ) astSetLabel( ret, 0, ckeyval );
- ckeyval = GetItemC( &(store->cname), axlat, 0, s, NULL, method, class, status );
- if( ckeyval ) astSetLabel( ret, 1, ckeyval );
-
-/* Observer's position (from primary axis descriptions). Get the OBSGEO-X/Y/Z
- keywords, convert to geodetic longitude and latitude and store as the
- SpecFrame's ObsLat, ObsLon and ObsAlt attributes. */
- obsgeo[ 0 ] = GetItem( &(store->obsgeox), 0, 0, ' ', NULL, method, class, status );
- obsgeo[ 1 ] = GetItem( &(store->obsgeoy), 0, 0, ' ', NULL, method, class, status );
- obsgeo[ 2 ] = GetItem( &(store->obsgeoz), 0, 0, ' ', NULL, method, class, status );
- if( obsgeo[ 0 ] != AST__BAD &&
- obsgeo[ 1 ] != AST__BAD &&
- obsgeo[ 2 ] != AST__BAD ) {
- eraGc2gd( 1, obsgeo, &geolon, &geolat, &h );
- astSetObsLat( ret, geolat );
- astSetObsLon( ret, geolon );
- astSetObsAlt( ret, h );
- }
-
-/* Store values for the reference point in the SkyFrame. */
- dval = GetItem( &(store->skyref), axlon, 0, s, NULL, method, class, status );
- if( dval != AST__BAD ) astSetSkyRef( ret, 0, dval );
- dval = GetItem( &(store->skyref), axlat, 0, s, NULL, method, class, status );
- if( dval != AST__BAD ) astSetSkyRef( ret, 1, dval );
-
- dval = GetItem( &(store->skyrefp), axlon, 0, s, NULL, method, class, status );
- if( dval != AST__BAD ) astSetSkyRefP( ret, 0, dval );
- dval = GetItem( &(store->skyrefp), axlat, 0, s, NULL, method, class, status );
- if( dval != AST__BAD ) astSetSkyRefP( ret, 1, dval );
-
-/* We cannot store the SkyRefIs value yet since this needs to be done
- after the SkyFrame has been added into the FrameSet, so that the Frame
- will be remapped to represent the intended offsets. SO instance, mark
- the Frame by setting the domain to "SKY_POLE" or "SKY_ORIGIN". This
- odd Domain value will be cleared later in TidyOffsets. */
- ckeyval = GetItemC( &(store->skyrefis), 0, 0, s, NULL, method, class, status );
- if( ckeyval ) {
- if( !Ustrcmp( "POLE", ckeyval, status ) ) {
- astSetDomain( ret, "SKY_POLE" );
- } else if( !Ustrcmp( "ORIGIN", ckeyval, status ) ) {
- astSetDomain( ret, "SKY_ORIGIN" );
- }
- }
- }
-
-/* If an error has occurred, annul the Frame. */
- if( !astOK ) ret = astAnnul( ret );
-
-/* Return the Frame. */
- return ret;
-}
-
-static AstMapping *WcsSpectral( AstFitsChan *this, FitsStore *store, char s,
- AstFrame **frm, AstFrame *iwcfrm, double reflon, double reflat,
- AstSkyFrame *reffrm, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* WcsSpectral
-
-* Purpose:
-* Create a Mapping from intermediate world coords to spectral coords
-* as described in a FITS header.
-
-* Type:
-* Private function.
-
-* Synopsis:
-
-* AstMapping *WcsSpectral( AstFitsChan *this, FitsStore *store, char s,
-* AstFrame **frm, AstFrame *iwcfrm, double reflon,
-* double reflat, AstSkyFrame *reffrm,
-* const char *method, const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function interprets the contents of the supplied FitsStore
-* structure, looking for world coordinate axes which describe positions
-* in a spectrum. If such an axis is found, a Mapping is returned which
-* transforms the corresponding intermediate world coordinates to
-* spectral world coordinates (this mapping leaves any other axes
-* unchanged). It also, modifies the supplied Frame to describe the
-* axis (again, other axes are left unchanged). If no spectral axis
-* is found, a UnitMap is returned, and the supplied Frame is left
-* unchanged.
-
-* Parameters:
-* this
-* The FitsChan.
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* frm
-* The address of a location at which to store a pointer to the
-* Frame describing the world coordinate axes.
-* iwcfrm
-* A pointer to the Frame describing the intermediate world coordinate
-* axes. The properties of this Frame may be changed on exit.
-* reflon
-* The reference celestial longitude, in the frame given by reffrm.
-* reflat
-* The reference celestial latitude, in the frame given by reffrm.
-* reffrm
-* The SkyFrame defining reflon and reflat.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the Mapping.
-*/
-
-/* Local Variables: */
- AstFrame *ofrm; /* Pointer to a Frame */
- AstMapping *map1; /* Pointer to Mapping */
- AstMapping *map2; /* Pointer to Mapping */
- AstMapping *ret; /* Pointer to the returned Mapping */
- AstSpecFrame *specfrm; /* Pointer to a SpecFrame */
- char algcode[ 5 ]; /* Displayed spectral type string */
- char stype[ 5 ]; /* Displayed spectral type string */
- const char *cname; /* Pointer to CNAME value */
- const char *ctype; /* Pointer to CTYPE value */
- const char *cunit; /* Pointer to CUNIT value */
- const char *defunit; /* Default unit string */
- const char *specsys; /* Pointer to SPECSYS value */
- const char *ssyssrc; /* Pointer to SSYSSRC value */
- double geolat; /* Observer's geodetic latitude */
- double geolon; /* Observer's geodetic longitude */
- double h; /* Observer's geodetic height */
- double mjd; /* Modified Julian Date */
- double obscentre; /* Spectral value at observation centre */
- double obsgeo[ 3 ]; /* Observer's Cartesian position */
- double restfrq; /* RESTFRQ keyword value */
- double vsource; /* Source velocity */
- int *axes; /* Pointer to axis permutation array */
- int i; /* Axis index */
- int j; /* Loop count */
- int k; /* Loop count */
- int kk; /* Loop count */
- int naxes; /* No. of axes in Frame */
-
-/* Initialise the pointer to the returned Mapping. */
- ret = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return ret;
-
-/* Get the number of physical axes. */
- naxes = astGetNaxes( *frm );
-
-/* An array to hold a list of axis selections. */
- axes = astMalloc( naxes*sizeof( int ) );
-
-/* Loop round checking each axis. */
- defunit = NULL;
- map1 = NULL;
- for( i = 0; i < naxes && astOK; i++ ) {
-
-/* Get the CTYPE value. Pass on to the next axis if no CTYPE is available. */
- ctype = GetItemC( &(store->ctype), i, 0, s, NULL, method, class, status );
- if( ctype ) {
-
-/* See if this CTYPE describes a spectral axis, and if so, extract the
- system code, the algorithm code and get the default units. */
- defunit = IsSpectral( ctype, stype, algcode, status );
-
-/* Skip to the next axis if the system type was not a spectral system
- type. */
- if( defunit ) {
-
-/* Create a SpecFrame or DSBSpecFrame with this system (the FITS type codes
- are also legal SpecFrame System values). We use astSetC rather than
- astSetSystem because astSetC translates string values into the
- corresponding integer system identifiers. */
- if( GetItem( &(store->imagfreq), 0, 0, s, NULL, method,
- class, status ) == AST__BAD ) {
- specfrm = astSpecFrame( "", status );
- } else {
- specfrm = (AstSpecFrame *) astDSBSpecFrame( "", status );
- }
- astSetC( specfrm, "System", stype );
-
-/* Set the reference position (attributes RefRA and RefDec), if known. */
- if( reffrm ) astSetRefPos( specfrm, reffrm, reflon, reflat );
-
-/* Set the SpecFrame units. Use the value of the CUNIT FITS keyword for this
- axis if available, otherwise use the default units for the system, noted
- above. */
- cunit = GetItemC( &(store->cunit), i, 0, s, NULL, method, class, status );
- if( !cunit ) cunit = defunit;
- astSetUnit( specfrm, 0, cunit );
-
-/* Set the axis unit in the IWC Frame. */
- astSetUnit( iwcfrm, i, cunit );
-
-/* Get a value for the Epoch attribute (the date of observation). */
- mjd = ChooseEpoch( this, store, s, method, class, status );
- if( mjd != AST__BAD ) astSetEpoch( specfrm, mjd );
-
-/* Set the rest frequency. Use the RESTFRQ keyword (assumed to be in Hz),
- or (if RESTFRQ is not available), RESTWAV (assumes to be in m). */
- restfrq = GetItem( &(store->restfrq), 0, 0, s, NULL, method, class, status );
- if( restfrq == AST__BAD ) {
- restfrq = GetItem( &(store->restwav), 0, 0, s, NULL, method, class, status );
- if( restfrq != AST__BAD ) restfrq = AST__C/restfrq;
- }
- astSetRestFreq( specfrm, restfrq );
-
-/* Observer's position (from primary axis descriptions). Get the OBSGEO-X/Y/Z
- keywords, convert to geodetic longitude and latitude and store as the
- SpecFrame's ObsLat, ObsLon and ObsAlt attributes. */
- obsgeo[ 0 ] = GetItem( &(store->obsgeox), 0, 0, ' ', NULL, method, class, status );
- obsgeo[ 1 ] = GetItem( &(store->obsgeoy), 0, 0, ' ', NULL, method, class, status );
- obsgeo[ 2 ] = GetItem( &(store->obsgeoz), 0, 0, ' ', NULL, method, class, status );
- if( obsgeo[ 0 ] != AST__BAD &&
- obsgeo[ 1 ] != AST__BAD &&
- obsgeo[ 2 ] != AST__BAD ) {
- eraGc2gd( 1, obsgeo, &geolon, &geolat, &h );
- astSetObsLat( specfrm, geolat );
- astSetObsLon( specfrm, geolon );
- astSetObsAlt( specfrm, h );
- }
-
-/* Source velocity rest frame */
- ssyssrc = GetItemC( &(store->ssyssrc), 0, 0, s, NULL, method, class, status );
- if( ssyssrc ) astSetC( specfrm, "SourceVRF", ssyssrc );
-
-/* Source velocity. Use the ZSOURCE keyword and convert from redshift to
- velocity. */
- vsource = GetItem( &(store->zsource), 0, 0, s, NULL, method, class, status );
- if( vsource != AST__BAD ) {
- vsource += 1.0;
- vsource *= vsource;
- vsource = AST__C*( vsource - 1.0 )/( vsource + 1.0 );
- astSetSourceVel( specfrm, vsource );
- }
-
-/* Reference frame. If the SPECSYS keyword is set, use it (the FITS codes
- are also legal SpecFrame StdOfRest values). We use astSetC rather than
- astSetSystem because astSetC translates string values into the
- corresponding integer system identifiers. */
- specsys = GetItemC( &(store->specsys), 0, 0, s, NULL, method, class, status );
- if( specsys ) astSetC( specfrm, "StdOfRest", specsys );
-
-/* Axis label. If the CNAME keyword is set, use it as the axis label. */
- cname = GetItemC( &(store->cname), i, 0, s, NULL, method, class, status );
- if( cname ) astSetLabel( specfrm, 0, cname );
-
-/* If the header contains an AXREF value for the spectral axis, use it as the
- observation centre in preferences to the CRVAL value. AXREF keywords are
- created by the astWrite method for axes described by -TAB algorithm that
- have no inverse transformation. */
- obscentre = GetItem( &(store->axref), i, 0, s, NULL, method,
- class, status );
- if( obscentre == AST__BAD ) {
- obscentre = GetItem( &(store->crval), i, 0, s, NULL, method,
- class, status );
- }
-
-/* Now do the extra stuff needed if we are creating a dual sideband
- SpecFrame. */
- if( astIsADSBSpecFrame( specfrm ) ) {
- DSBSetUp( this, store, (AstDSBSpecFrame *) specfrm, s,
- obscentre, method, class, status );
- }
-
-/* Now branch for each type of algorithm code. Each case returns a 1D
- Mapping which converts IWC value into the specified Spectral system. */
-
-/* Linear */
- if( strlen( algcode ) == 0 ) {
- map1 = LinearWcs( store, i, s, method, class, status );
-
-/* Log-Linear */
- } else if( !strcmp( "-LOG", algcode ) ) {
- map1 = LogWcs( store, i, s, method, class, status );
-
-/* Non-Linear */
- } else if( algcode[ 0 ] == '-' && algcode[ 2 ] == '2' ) {
- map1 = NonLinSpecWcs( this, algcode, store, i, s, specfrm, method, class, status );
-
-/* Grism */
- } else if( !strcmp( "-GRI", algcode ) ||
- !strcmp( "-GRA", algcode ) ) {
- map1 = GrismSpecWcs( algcode, store, i, s, specfrm, method, class, status );
- } else {
- map1 = NULL;
- }
- if( map1 == NULL && astOK ) {
- specfrm = astAnnul( specfrm );
- astError( AST__BDFTS, "%s(%s): Cannot implement spectral "
- "algorithm code '%s' specified in FITS keyword '%s'.", status,
- method, class, ctype + 4, FormatKey( "CTYPE", i + 1, -1, s, status ) );
- astError( AST__BDFTS, "%s(%s): Unknown algorithm code or "
- "unusable parameter values.", status, method, class );
- break;
- }
-
-/* Create a Frame by picking all the other (non-spectral) axes from the
- supplied Frame. */
- j = 0;
- for( k = 0; k < naxes; k++ ) {
- if( k != i ) axes[ j++ ] = k;
- }
-
-/* If there were no other axes, replace the supplied Frame with the
- specframe. */
- if( j == 0 ) {
- (void) astAnnul( *frm );
- *frm = (AstFrame *) specfrm;
-
-/* Otherwise pick the other axes from the supplied Frame */
- } else {
- ofrm = astPickAxes( *frm, j, axes, NULL );
-
-/* Replace the supplied Frame with a CmpFrame made up of this Frame and
- the SpecFrame. */
- (void) astAnnul( *frm );
- *frm = (AstFrame *) astCmpFrame( ofrm, specfrm, "", status );
- ofrm = astAnnul( ofrm );
- specfrm = astAnnul( specfrm );
- }
-
-/* Permute the axis order to put the spectral axis back in its original
- position. */
- j = 0;
- for( kk = 0; kk < naxes; kk++ ) {
- if( kk == i ) {
- axes[ kk ] = naxes - 1;
- } else {
- axes[ kk ] = j++;
- }
- }
- astPermAxes( *frm, axes );
- }
- }
-
-/* If this axis is not a spectral axis, create a UnitMap (the Frame is left
- unchanged). */
- if( !map1 && astOK ) map1 = (AstMapping *) astUnitMap( 1, "", status );
-
-/* Add the Mapping for this axis in parallel with the Mappings for
- previous axes. */
- if( ret ) {
- map2 = (AstMapping *) astCmpMap( ret, map1, 0, "", status );
- ret = astAnnul( ret );
- map1 = astAnnul( map1 );
- ret = map2;
- } else {
- ret = map1;
- map1 = NULL;
- }
- }
-
-/* Free the axes array. */
- axes= astFree( axes );
-
-/* Return the result. */
- return ret;
-}
-
-static void WcsToStore( AstFitsChan *this, AstFitsChan *trans,
- FitsStore *store, const char *method,
- const char *class, int *status ){
-
-/*
-* Name:
-* WcsToStore
-
-* Purpose:
-* Extract WCS information from the supplied FitsChan using a FITSWCS
-* encoding, and store it in the supplied FitsStore.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* void WcsToStore( AstFitsChan *this, AstFitsChan *trans,
-* FitsStore *store, const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* A FitsStore is a structure containing a generalised represention of
-* a FITS WCS FrameSet. Functions exist to convert a FitsStore to and
-* from a set of FITS header cards (using a specified encoding), or
-* an AST FrameSet. In other words, a FitsStore is an encoding-
-* independant intermediary staging post between a FITS header and
-* an AST FrameSet.
-*
-* This function extracts FITSWCS keywords from the supplied FitsChan(s),
-* and stores the corresponding WCS information in the supplied FitsStore.
-* Keywords will be searched for first in "trans", and then, if they
-* are not found in "trans", they will be searched for in "this".
-
-* Parameters:
-* this
-* Pointer to the FitsChan containing the cards read from the
-* original FITS header. This may include non-standard keywords.
-* trans
-* Pointer to a FitsChan containing cards representing standard
-* translations of any non-standard keywords in "this". A NULL
-* pointer indicates that "this" contains no non-standard keywords.
-* store
-* Pointer to the FitsStore structure.
-* 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.
-*/
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Read all usable cards out of the main FitsChan, into the FitsStore. */
- WcsFcRead( this, trans, store, method, class, status );
-
-/* If a FitsChan containing standard translations was supplied, read all
- cards out of it, into the FitsStore, potentially over-writing the
- non-standard values stored in the previous call to WcsFcRead. */
- if( trans ) WcsFcRead( trans, NULL, store, method, class, status );
-}
-
-static int WorldAxes( AstFitsChan *this, AstMapping *cmap, double *dim, int *perm,
- int *status ){
-
-/*
-* Name:
-* WorldAxes
-
-* Purpose:
-* Associate final world axes with pixel axes.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-
-* int WorldAxes( AstFitsChan *this, AstMapping *cmap, double *dim, int *perm,
-* int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function finds the association between the axes of the final
-* world coordinate system, and those of the pixel coordinate
-* system. This may not simply be a 1-to-1 association because the
-* Mapping may include a PermMap. Each output axis is associated with
-* the input axis which is most nearly aligned with it.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* cmap
-* Pointer to the Mapping from pixel coordinates to final world
-* coordinates.
-* dim
-* Pointer to an array with one element for each input of "map",
-* supplied holding the no. of pixels in the data cube along the axis, or
-* AST__BAD If unknown.
-* perm
-* Pointer to an array with one element for each output of "map".
-* On exit, each element of this array holds the zero-based index of the
-* "corresponding" (i.e. most nearly parallel) pixel axis.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* Non-zero for success - zero for failure.
-*/
-
-/* Local Variables: */
- AstMapping *smap;
- AstMapping *map;
- AstPointSet *pset1;
- AstPointSet *pset2;
- double **ptr2;
- double **ptr1;
- double *dw;
- double *g0;
- double *nwt;
- double *ntn;
- double *tn;
- double *wt;
- double *w0;
- double dg;
- double s;
- double sj;
- double tnmin;
- double wtmax;
- int *outs;
- int i2;
- int i;
- int imin;
- int j2;
- int j;
- int jmin;
- int nin;
- int nout;
- int nouts;
- int nused;
- int ret;
- int retain;
- int used;
-
-/* Initialise returned value */
- ret = 0;
-
-/* Other initialisation to avoid compiler warnings. */
- retain = 0;
-
-/* Check the status */
- if( !astOK ) return ret;
-
-/* Simplfy the Mapping. */
- map = astSimplify( cmap );
-
-/* Get the number of inputs and outputs for the Mapping. */
- nin = astGetNin( map );
- nout = astGetNout( map );
-
-/* Initialise "perm". */
- for( i = 0; i < nout; i++ ) perm[ i ] = i;
-
-/* First deal with Mappings that are defined in both directions. */
- if( astGetTranForward( map ) && astGetTranInverse( map ) ) {
-
-/* Use FindBasisVectors to find an input position which coresponds to a
- good output position. Store it in a dynamic array pointed to by "g0". */
- pset1 = astPointSet( nin+1, nin, "", status );
- pset2 = astPointSet( nin+1, nout, "", status );
- if( FindBasisVectors( map, nin, nout, dim, pset1, pset2, status ) ) {
- g0 = astMalloc( sizeof(double)*nin );
- ptr1 = astGetPoints( pset1 );
- if( astOK ) {
- for( j = 0; j < nin; j++ ) g0[ j ] = ptr1[ j ][ 0 ];
- }
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
-
-/* If no basis vectors found, return. */
- } else {
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
- return ret;
- }
-
-/* Create Pointset to hold two input (pixel) points. */
- pset1 = astPointSet( 2, nin, "", status );
- ptr1 = astGetPoints( pset1 );
-
-/* Create a Pointset to hold the same number of output (world) points. */
- pset2 = astPointSet( 2, nout, "", status );
- ptr2 = astGetPoints( pset2 );
-
-/* Allocate memory to use as work space */
- w0 = astMalloc( sizeof(double)*nout );
- dw = astMalloc( sizeof(double)*nout );
- tn = astMalloc( sizeof(double)*nout*nin );
- wt = astMalloc( sizeof(double)*nout*nin );
-
-/* Check that the pointers can be used. */
- if( astOK ) {
-
-/* Transform the grid position found above, plus a position 1 pixel away
- along all pixel axes, into world coords. Also set up "dw" to hold
- "a small increment" along each world axis. */
- for( j = 0; j < nin; j++ ) {
- ptr1[ j ] [ 0 ] = g0[ j ];
- ptr1[ j ] [ 1 ] = g0[ j ] + 1.0;
- }
- (void) astTransform( map, pset1, 1, pset2 );
- for( i = 0; i < nout; i++ ) {
- w0[ i ] = ptr2[ i ] [ 0 ];
- if( w0[ i ] != AST__BAD && ptr2[ i ] [ 1 ] != AST__BAD ) {
- dw[ i ] = fabs( 0.1*( ptr2[ i ] [ 1 ] - w0[ i ] ) );
- if( dw[ i ] <= fabs( 0.001*w0[ i ] ) ) {
- if( w0[ i ] != 0.0 ) {
- dw[ i ] = fabs( 0.001*w0[ i ] );
- } else {
- dw[ i ] = 1.0;
- }
- }
- } else {
- dw[ i ] = AST__BAD;
- }
- }
-
-/* Any PermMap in the mapping may result in the the "inverse transformation"
- not being a true inverse of the forward transformation (for instance,
- constant values fed in for degenerate axis would have this effect). To
- ensure that "g0" and "w0" are corresponding positions, transform the
- "w0" position back into grid coords and use the resulting grid position
- as "g0". */
- (void) astTransform( map, pset2, 0, pset1 );
- for( j = 0; j < nin; j++ ) {
- g0[ j ] = ptr1[ j ] [ 0 ];
- }
-
-/* In the next loop we find the tan of the angle between each WCS axis and
- each of the pixel axes. Loop round each WCS axis. */
- for( i = 0; i < nout; i++ ) {
-
-/* Initialise the tan values for this WCS axis to AST__BAD. */
- ntn = tn + i*nin;
- nwt = wt + i*nin;
- for( j = 0; j < nin; j++ ) ntn[ j ] = AST__BAD;
-
-/* As a side issue, initialise the pixel axis assigned to each WCS axis
- to -1, to indicate that no grid axis has yet been associated with this
- WCS axis. */
- perm[ i ] = -1;
-
-/* Skip over this axis if the increment is bad. */
- if( dw[ i ] != AST__BAD ) {
-
-/* Store a WCS position which is offset from the "w0" position by a small
- amount along the current WCS axis. The first position in "ptr2" is
- currently "w0". */
- ptr2[ i ][ 0 ] += dw[ i ];
-
-/* Transform this position into grid coords. */
- (void) astTransform( map, pset2, 0, pset1 );
-
-/* Re-instate the original "w0" values within "ptr2", ready for the next
- WCS axis. */
- ptr2[ i ][ 0 ] = w0[ i ];
-
-/* Consider each pixel axis in turn as a candidate for being assigned to
- the current WCS axis. */
- for( j = 0; j < nin; j++ ) {
-
-/* Find the tan of the angle between the current ("i"th) WCS axis and the
- current ("j"th) pixel axis. This gets stored in tn[j+nin*i]. A
- corresponding weight for each angle is stored in nwt[j+nin*i]. This
- is the length of the projection of the vector onto the "j"th pixel
- axis. */
- s = 0.0;
- sj = 0.0;
- for( j2 = 0; j2 < nin; j2++ ) {
- if( ptr1[ j2 ][ 0 ] != AST__BAD ) {
- dg = ptr1[ j2 ][ 0 ] - g0[ j2 ];
- if( j2 != j ) {
- s += dg*dg;
- } else {
- sj = fabs( dg );
- }
- } else {
- s = AST__BAD;
- break;
- }
- }
- if( s != AST__BAD && sj != 0.0 ) {
- ntn[ j ] = sqrt( s )/sj;
- nwt[ j ] = sj;
- }
- }
- }
- }
-
-/* Loop until every grid axes has been assigned to a WCS axis. */
- while( 1 ) {
-
-/* Pass through the array of tan values, finding the smallest. Note the
- pixel and WCS axis for which the smallest tan value occurs. If the tan
- values are equal, favour the one with highest weight. */
- ntn = tn;
- nwt = wt;
- tnmin = AST__BAD;
- wtmax = AST__BAD;
- imin = 0;
- jmin = 0;
- for( i = 0; i < nout; i++ ) {
- for( j = 0; j < nin; j++ ) {
- if( *ntn != AST__BAD ) {
- if( tnmin == AST__BAD || *ntn < tnmin ) {
- tnmin = *ntn;
- wtmax = *nwt;
- imin = i;
- jmin = j;
- } else if( astEQUAL( *ntn, tnmin ) && *nwt > wtmax ) {
- wtmax = *nwt;
- imin = i;
- jmin = j;
- }
- }
- ntn++;
- nwt++;
- }
- }
-
-/* Check we found a usable minimum tan value */
- if( tnmin != AST__BAD ) {
-
-/* Assign the pixel axis to the WCS axis. */
- perm[ imin ] = jmin;
-
-/* Set bad all the tan values for this pixel and WCS axis pair. This ensures
- that the pixel axis will not be assigned to another WCS axis, and that
- the WCS will not have another pixel axis assigned to it. */
- ntn = tn;
- for( i = 0; i < nout; i++ ) {
- for( j = 0; j < nin; j++ ) {
- if( i == imin || j == jmin ) *ntn = AST__BAD;
- ntn++;
- }
- }
-
-/* Leave the loop if no more good tan values were found. */
- } else {
- break;
- }
- }
-
-/* The above process may have left some WCS axes with out any assigned
- pixel axis. We assign the remaining pixel arbitrarily to such axes,
- starting with the first remaining pixel axis. Find the lowest unused
- pixel axis. */
- for( j = 0; j < nin; j++ ) {
- used = 0;
- for( i = 0; i < nout; i++ ) {
- if( perm[ i ] == j ) {
- used = 1;
- break;
- }
- }
- if( !used ) break;
- }
-
-/* Now check each WCS axis looking for outputs which were not assigned a
- pixel axis in the above process. */
- for( i = 0; i < nout; i++ ) {
- if( perm[ i ] == -1 ) {
-
-/* Use the next unused axis value. */
- perm[ i ] = j++;
-
-/* Find the next unused axis value. */
- for( ; j < nin; j++ ) {
- used = 0;
- for( i2 = 0; i2 < nout; i2++ ) {
- if( perm[ i2 ] == j ) {
- used = 1;
- break;
- }
- }
- if( !used ) break;
- }
- }
- }
-
-/* Indicate success. */
- if( astOK ) ret = 1;
- }
-
-/* Free resources. */
- pset1 = astAnnul( pset1 );
- pset2 = astAnnul( pset2 );
- g0 = astFree( g0 );
- w0 = astFree( w0 );
- tn = astFree( tn );
- wt = astFree( wt );
- dw = astFree( dw );
-
-/* Now, if we can use the TAB algorithm, deal with Mappings that are defined only in the forward direction. */
- } else if( astGetTranForward( map ) && astGetTabOK( this ) > 0 ) {
-
-/* Assume success. */
- ret = 1;
-
-/* Initialise to indicate no outputs have yet been assigned. */
- for( i = 0; i < nout; i++ ) perm[ i ] = -1;
-
-/* Find the output associated with each input. */
- for( j = 0; j < nin; j++ ) {
-
-/* Attempt to split off the current input. */
- outs = astMapSplit( map, 1, &j, &smap );
-
-/* If successfull, store the index of the corresponding input for each
- output. */
- if( outs && smap ) {
- nouts = astGetNout( smap );
- for( i = 0; i < nouts; i++ ) {
- if( perm[ outs[ i ] ] == -1 ) {
- perm[ outs[ i ] ] = j;
- } else {
- ret = 0;
- }
- }
- }
-
-/* Free resources. */
- outs = astFree( outs );
- if( smap ) smap = astAnnul( smap );
- }
-
-/* Check all outputs were assigned . */
- for( i = 0; i < nout && ret; i++ ) {
- if( perm[ i ] == -1 ) ret = 0;
- }
-
-/* If succesful, attempt to remove any duplicates from the "perm" array
- (i.e. inputs that supply more than one output). First get a list of
- the inputs that are currently unused (i.e. do not appear in "perm"). */
- if( ret ) {
-
-/* Check each input. */
- for( j = 0; j < nin; j++ ) {
-
-/* See how many outputs are fed by this input. */
- nused = 0;
- for( i = 0; i < nout; i++ ) {
- if( perm[ i ] == j ) nused++;
- }
-
-/* If it used more than once, we need to remove all but one of the
- occurrences. */
- if( nused > 1 ) {
-
-/* Choose the occurrence to retain. If the output with the same index as
- the input is one of them, use it. Otherwise, use the first occurrence. */
- if( perm[ j ] == j ) {
- retain = j;
- } else {
- for( i = 0; i < nout; i++ ) {
- if( perm[ i ] == j ) {
- retain = i;
- break;
- }
- }
- }
-
-/* Loop round all occurrences of this input again. */
- for( i = 0; i < nout && ret; i++ ) {
- if( perm[ i ] == j ) {
-
-/* Replace all occurrences, except for the one being retained. */
- if( i != retain ) {
-
-/* Replace it with the next unused input. */
- for( j2 = 0; j2 < nin; j2++ ) {
- used = 0;
- for( i2 = 0; i2 < nout; i2++ ) {
- if( perm[ i2 ] == j2 ) {
- used = 1;
- break;
- }
- }
- if( ! used ) {
- perm[ i ] = j2;
- break;
- }
- }
-
-/* If there were no unused inputs, we cannot do it. */
- if( used ) ret = 0;
- }
- }
- }
- }
- }
- }
- }
-
-/* Free resources. */
- map = astAnnul( map );
-
-/* Return the result. */
- return ret;
-}
-
-static int Write( AstChannel *this_channel, AstObject *object, int *status ) {
-/*
-* Name:
-* Write
-
-* Purpose:
-* Write an Object to a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* int Write( AstChannel *this, AstObject *object, int *status )
-
-* Class Membership:
-* FitsChan member function (over-rides the astWrite method
-* inherited from the Channel class).
-
-* Description:
-* This function writes an Object to a FitsChan.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* object
-* Pointer to the Object which is to be written.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* The number of Objects written to the FitsChan by this invocation of
-* astWrite.
-
-* Notes:
-* - A value of zero will be returned if this function is invoked
-* with the AST error status set, or if it should fail for any
-* reason.
-* - The Base Frame in the FrameSet is used as the pixel Frame, and
-* the Current Frame is used to create the primary axis descriptions.
-* Attempts are made to create secondary axis descriptions for any
-* other Frames in the FrameSet (up to a total of 26).
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- FitsStore *store; /* Intermediate storage for WCS information */
- char banner[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ]; /* Buffer for begin/end banner */
- const char *class; /* Pointer to string holding object class */
- const char *method; /* Pointer to string holding calling method */
- double *dim; /* Pointer to array of axis dimensions */
- int card0; /* Index of original current card */
- int comm; /* Value of Comm attribute */
- int encoding; /* FITS encoding scheme to use */
- int i; /* Axis index */
- int naxis; /* No. of pixel axes */
- int ret; /* Number of objects read */
-
-/* Initialise. */
- ret = 0;
-
-/* Check the global error status. */
- if ( !astOK ) return ret;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_channel);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* Store the calling method, and object class. */
- method = "astWrite";
- class = astGetClass( this );
-
-/* The original current card is re-instated at the end if no object
- is written. Save its index. */
- card0 = astGetCard( this );
-
-/* Indicate that all cards added to the FitsCHan by this call should be
- marked as "new". */
- mark_new = 1;
-
-/* Get the encoding scheme used by the FitsChan. */
- encoding = astGetEncoding( this );
-
-/* First deal with cases where we are writing to a FitsChan in which AST
- objects are encoded using native AST-specific keywords... */
- if( encoding == NATIVE_ENCODING ){
-
-/* Increment the nesting level which keeps track of recursive
- invocations of this function. */
- write_nest++;
-
-/* Initialise the current indentation level for top-level objects. */
- if ( !write_nest ) current_indent = 0;
-
-/* Obtain the value of the Comm attribute. */
- comm = astGetComment( this );
-
-/* If this is the top-level invocation (i.e. we are about to write out
- a new top-level Object), then prefix it with a blank FITS line and
- an appropriate banner of FITS comments, unless comments have been
- suppressed. */
- if ( !write_nest && comm ) {
- astSetFitsCom( this, " ", "", 0 );
- MakeBanner(
-"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++",
- "", "", banner, status );
- astSetFitsCom( this, "COMMENT", banner, 0 );
- if( astIsAFrameSet( object ) ) {
- MakeBanner( "WCS information in AST format", "", "", banner, status );
- astSetFitsCom( this, "COMMENT", banner, 0 );
- MakeBanner( "See http://www.starlink.ac.uk/ast/", "", "", banner, status );
- astSetFitsCom( this, "COMMENT", banner, 0 );
- }
- MakeBanner( HEADER_TEXT, astGetClass( object ), " object", banner, status );
- astSetFitsCom( this, "COMMENT", banner, 0 );
- MakeBanner(
-"................................................................",
- "", "", banner, status );
- astSetFitsCom( this, "COMMENT", banner, 0 );
- }
-
-/* Invoke the parent astWrite method to write out the Object data. */
- (*parent_write)( this_channel, object, status );
-
-/* Append a banner of FITS comments to the object data, as above, if
- necessary. */
- if ( !write_nest && comm ) {
- MakeBanner(
-"................................................................",
- "", "", banner, status );
- astSetFitsCom( this, "COMMENT", banner, 0 );
- MakeBanner( FOOTER_TEXT, astGetClass( object ), " object", banner, status );
- astSetFitsCom( this, "COMMENT", banner, 0 );
- MakeBanner(
-"----------------------------------------------------------------",
- "", "", banner, status );
- astSetFitsCom( this, "COMMENT", banner, 0 );
- }
-
-/* Return the nesting level to its previous value. */
- write_nest--;
-
-/* Indicate that an object has been written. */
- ret = 1;
-
-/* Now deal with cases where we are writing to a FitsChan in which AST
- objects are encoded using any of the supported foreign encodings... */
- } else {
-
-/* Only proceed if the supplied object is a FrameSet. */
- if( astIsAFrameSet( object ) ){
-
-/* Note the number of pixel (i.e. Base Frame) axes, and allocate memory to
- hold the image dimensions. */
- naxis = astGetNin( (AstFrameSet *) object );
- dim = (double *) astMalloc( sizeof(double)*naxis );
- if( dim ){
-
-/* Note the image dimensions, if known. If not, store AST__BAD values. */
- for( i = 0; i < naxis; i++ ){
- if( !astGetFitsF( this, FormatKey( "NAXIS", i + 1, -1, ' ', status ),
- dim + i ) ) dim[ i ] = AST__BAD;
- }
-
-/* Extract the required information from the FrameSet into a standard
- intermediary structure called a FitsStore. The indices of any
- celestial axes are returned. */
- store = FsetToStore( this, (AstFrameSet *) object, naxis, dim,
- encoding, method, class, status );
-
-/* If the FrameSet cannot be described in terms of any of the supported
- FITS encodings, a null pointer will have been returned. */
- if( store ){
-
-/* Now put header cards describing the contents of the FitsStore into the
- supplied FitsChan, using the requested encoding. Zero or one is
- returned depending on whether the information could be encoded. */
- ret = FitsFromStore( this, store, encoding, dim,
- (AstFrameSet *) object, method, class, status );
-
-/* Release the resources used by the FitsStore. */
- store = FreeStore( store, status );
-
-/* If the Object was written to the FitsChan, set the current card to
- end-of-file. */
- if( ret ) astSetCard( this, INT_MAX );
- }
-
-/* Free workspace holding image dimensions */
- dim = (double *) astFree( (void *) dim );
- }
- }
- }
-
-/* If an error has occurred, return zero and remove any new cards added
- to the FitsCHan by this call. */
- if( !astOK ) ret = 0;
-
-/* Clear the new flag associated with cards which have been added to the
- FitsChan as a result of this function. If the object was not added
- succesfully to the FitsChan, remove any cards which were added before
- the error was discovered. */
- FixNew( this, NEW1, !ret, method, class, status );
- FixNew( this, NEW2, !ret, method, class, status );
-
-/* Indicate that all cards added to the FitsChan from now on should not be
- marked as "new". */
- mark_new = 0;
-
-/* If no object was written, re-instate the original current card. */
- if( !ret ) astSetCard( this, card0 );
-
-/* Return the answer. */
- return ret;
-}
-
-static void WriteBegin( AstChannel *this_channel, const char *class,
- const char *comment, int *status ) {
-/*
-* Name:
-* WriteBegin
-
-* Purpose:
-* Write a "Begin" data item to a data sink.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WriteBegin( AstChannel *this, const char *class,
-* const char *comment )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected astWriteBegin
-* method inherited from the Channel class).
-
-* Description:
-* This function writes a "Begin" data item to the data sink
-* associated with a FitsChan, so as to begin the output of a new
-* Object definition.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* class
-* Pointer to a constant null-terminated string containing the
-* name of the class to which the Object belongs.
-* comment
-* Pointer to a constant null-terminated string containing a
-* textual comment to be associated with the "Begin"
-* item. Normally, this will describe the purpose of the Object.
-
-* Notes:
-* - The comment supplied may not actually be used, depending on
-* the nature of the FitsChan supplied.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFitsChan *this; /* Pointer to the FitsChan structure. */
- char buff[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ];
- /* Character buffer */
- char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_channel);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Increment the indentation level for comments. */
- current_indent += INDENT_INC;
-
-/* If we are not beginning a top-level Object definition, and helpful
- information has not been suppressed, generate an indented comment
- to mark the "Begin" item and write it to the FitsChan as a comment
- card with a blank keyword. */
- if ( write_nest && ( astGetFull( this ) >= 0 ) ) {
- MakeIndentedComment( current_indent, '+', "Beginning of ", class, buff, status );
- astSetFitsCom( this, " ", buff, 0 );
- }
-
-/* Create a unique FITS keyword for this "Begin" item, basing it on
- "BEGAST". */
- CreateKeyword( this, "BEGAST", keyword, status );
-
-/* Generate a pre-quoted version of the class name. */
- PreQuote( class, buff, status );
-
-/* Write the "Begin" item to the FitsChan as a keyword and string
- value. */
- astSetFitsS( this, keyword, buff,
- astGetComment( this ) ? comment : NULL, 0 );
-
-/* Clear the count of items written. */
- items_written = 0;
-}
-
-static void WriteDouble( AstChannel *this_channel, const char *name,
- int set, int helpful,
- double value, const char *comment, int *status ) {
-/*
-* Name:
-* WriteDouble
-
-* Purpose:
-* Write a double value to a data sink.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WriteDouble( AstChannel *this, const char *name,
-* int set, int helpful,
-* double value, const char *comment )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected
-* astWriteDouble method inherited from the Channel class).
-
-* Description:
-* This function writes a named double value, representing the
-* value of a class instance variable, to the data sink associated
-* with a FitsChan. It is intended for use by class "Dump"
-* functions when writing out class information which will
-* subsequently be re-read.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a constant null-terminated string containing the
-* name to be used to identify the value in the external
-* representation. This will form the key for identifying it
-* again when it is re-read. The name supplied should be unique
-* within its class.
-*
-* Mixed case may be used and will be preserved in the external
-* representation (where possible) for cosmetic effect. However,
-* case is not significant when re-reading values.
-*
-* It is recommended that a maximum of 6 alphanumeric characters
-* (starting with an alphabetic character) be used. This permits
-* maximum flexibility in adapting to standard external data
-* representations (e.g. FITS).
-* set
-* If this is zero, it indicates that the value being written is
-* a default value (or can be re-generated from other values) so
-* need not necessarily be written out. Such values will
-* typically be included in the external representation with
-* (e.g.) a comment character so that they are available to
-* human readers but will be ignored when re-read. They may also
-* be completely omitted in some circumstances.
-*
-* If "set" is non-zero, the value will always be explicitly
-* included in the external representation so that it can be
-* re-read.
-* helpful
-* This flag provides a hint about whether a value whose "set"
-* flag is zero (above) should actually appear at all in the
-* external representaton.
-*
-* If the external representation allows values to be "commented
-* out" then, by default, values will be included in this form
-* only if their "helpful" flag is non-zero. Otherwise, they
-* will be omitted entirely. When possible, omitting the more
-* obscure values associated with a class is recommended in
-* order to improve readability.
-*
-* This default behaviour may be further modified if the
-* FitsChan's Full attribute is set - either to permit all
-* values to be shown, or to suppress non-essential information
-* entirely.
-* value
-* The value to be written.
-* comment
-* Pointer to a constant null-terminated string containing a
-* textual comment to be associated with the value.
-*
-* Note that this comment may not actually be used, depending on
-* the nature of the FitsChan supplied and the setting of its
-* Comm attribute.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFitsChan *this; /* Pointer to the FitsChan structure. */
- char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_channel);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Use the "set" and "helpful" flags, along with the FitsChan's
- attributes to decide whether this value should actually be
- written. */
- if ( Use( this, set, helpful, status ) ) {
-
-/* Create a unique FITS keyword from the name supplied. */
- CreateKeyword( this, name, keyword, status );
-
-/* Write the value to the FitsChan as a keyword and value */
- astSetFitsF( this, keyword, value,
- astGetComment( this ) ? comment : NULL, 0 );
-
-/* If the value is not "set", replace the card just written by a COMMENT
- card containing the text of the card as the comment. */
- if( !set ) MakeIntoComment( this, "astWrite", astGetClass( this ), status );
-
-/* Increment the count of items written. */
- items_written++;
- }
-}
-
-static void WriteEnd( AstChannel *this_channel, const char *class, int *status ) {
-/*
-* Name:
-* WriteEnd
-
-* Purpose:
-* Write an "End" data item to a data sink.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WriteEnd( AstChannel *this, const char *class )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected astWriteEnd
-* method inherited from the Channel class).
-
-* Description:
-* This function writes an "End" data item to the data sink
-* associated with a FitsChan. This item delimits the end of an
-* Object definition.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* class
-* Pointer to a constant null-terminated string containing the
-* class name of the Object whose definition is being terminated
-* by the "End" item.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFitsChan *this; /* Pointer to the FitsChan structure. */
- char buff[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ];
- /* Character buffer */
- char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_channel);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Create a unique FITS keyword for this "End" item, basing it on
- "ENDAST". */
- CreateKeyword( this, "ENDAST", keyword, status );
-
-/* Generate a pre-quoted version of the class name. */
- PreQuote( class, buff, status );
-
-/* Write the "End" item to the FitsChan as a keyword and string
- value. */
- astSetFitsS( this, keyword, buff,
- astGetComment( this ) ? "End of object definition" : NULL,
- 0 );
-
-/* If we are not ending a top-level Object definition, and helpful
- information has not been suppressed, generate an indented comment
- to mark the "End" item and write it to the FitsChan as a comment
- card with a blank keyword. */
- if ( write_nest && ( astGetFull( this ) >= 0 ) ) {
- MakeIndentedComment( current_indent, '-', "End of ", class, buff, status );
- astSetFitsCom( this, " ", buff, 0 );
- }
-
-/* Decrement the indentation level for comments. */
- current_indent -= INDENT_INC;
-}
-
-static void WriteFits( AstFitsChan *this, int *status ){
-
-/*
-*++
-* Name:
-c astWriteFits
-f AST_WRITEFITS
-
-* Purpose:
-* Write out all cards in a FitsChan to the sink function.
-
-* Type:
-* Public virtual function.
-
-* Synopsis:
-c #include "fitschan.h"
-c void astWriteFits( AstFitsChan *this )
-f CALL AST_WRITEFITS( THIS, STATUS )
-
-* Class Membership:
-* FitsChan method.
-
-* Description:
-c This function
-f This routine
-* writes out all cards currently in the FitsChan. If the SinkFile
-* attribute is set, they will be written out to the specified sink file.
-* Otherwise, they will be written out using the sink function specified
-* when the FitsChan was created. All cards are then deleted from the
-* FitsChan.
-
-* Parameters:
-c this
-f THIS = INTEGER (Given)
-* Pointer to the FitsChan.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Notes:
-* - If the SinkFile is unset, and no sink function is available, this
-* method simply empties the FitsChan, and is then equivalent to
-c astEmptyFits.
-f AST_EMPTYFITS.
-* - This method attempt to execute even if an error has occurred
-* previously.
-*--
-*/
-
-/* Ensure a FitsChan was supplied. */
- if( this ) {
-
-/* Ensure the source function has been called */
- ReadFromSource( this, status );
-
-/* We can usefully use the local destructor function to do the work,
- since it only frees resources used within teh FitsChan, rather than
- freeing the FitsChan itself. */
- Delete( (AstObject *) this, status );
- }
-}
-
-static void WriteInt( AstChannel *this_channel, const char *name,
- int set, int helpful,
- int value, const char *comment, int *status ) {
-/*
-* Name:
-* WriteInt
-
-* Purpose:
-* Write an int value to a data sink.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WriteInt( AstChannel *this, const char *name,
-* int set, int helpful,
-* int value, const char *comment )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected
-* astWriteInt method inherited from the Channel class).
-
-* Description:
-* This function writes a named int value, representing the
-* value of a class instance variable, to the data sink associated
-* with a FitsChan. It is intended for use by class "Dump"
-* functions when writing out class information which will
-* subsequently be re-read.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a constant null-terminated string containing the
-* name to be used to identify the value in the external
-* representation. This will form the key for identifying it
-* again when it is re-read. The name supplied should be unique
-* within its class.
-*
-* Mixed case may be used and will be preserved in the external
-* representation (where possible) for cosmetic effect. However,
-* case is not significant when re-reading values.
-*
-* It is recommended that a maximum of 6 alphanumeric characters
-* (starting with an alphabetic character) be used. This permits
-* maximum flexibility in adapting to standard external data
-* representations (e.g. FITS).
-* set
-* If this is zero, it indicates that the value being written is
-* a default value (or can be re-generated from other values) so
-* need not necessarily be written out. Such values will
-* typically be included in the external representation with
-* (e.g.) a comment character so that they are available to
-* human readers but will be ignored when re-read. They may also
-* be completely omitted in some circumstances.
-*
-* If "set" is non-zero, the value will always be explicitly
-* included in the external representation so that it can be
-* re-read.
-* helpful
-* This flag provides a hint about whether a value whose "set"
-* flag is zero (above) should actually appear at all in the
-* external representaton.
-*
-* If the external representation allows values to be "commented
-* out" then, by default, values will be included in this form
-* only if their "helpful" flag is non-zero. Otherwise, they
-* will be omitted entirely. When possible, omitting the more
-* obscure values associated with a class is recommended in
-* order to improve readability.
-*
-* This default behaviour may be further modified if the
-* FitsChan's Full attribute is set - either to permit all
-* values to be shown, or to suppress non-essential information
-* entirely.
-* value
-* The value to be written.
-* comment
-* Pointer to a constant null-terminated string containing a
-* textual comment to be associated with the value.
-*
-* Note that this comment may not actually be used, depending on
-* the nature of the FitsChan supplied and the setting of its
-* Comm attribute.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFitsChan *this; /* Pointer to the FitsChan structure. */
- char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_channel);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Use the "set" and "helpful" flags, along with the FitsChan's
- attributes to decide whether this value should actually be
- written. */
- if ( Use( this, set, helpful, status ) ) {
-
-/* Create a unique FITS keyword from the name supplied. */
- CreateKeyword( this, name, keyword, status );
-
-/* Write the value to the FitsChan as a keyword and value */
- astSetFitsI( this, keyword, value,
- astGetComment( this ) ? comment : NULL, 0 );
-
-/* If the value is not "set", replace the card just written by a COMMENT
- card containing the text of the card as the comment. */
- if( !set ) MakeIntoComment( this, "astWrite", astGetClass( this ), status );
-
-/* Increment the count of items written. */
- items_written++;
- }
-}
-
-static void WriteIsA( AstChannel *this_channel, const char *class,
- const char *comment, int *status ) {
-/*
-* Name:
-* WriteIsA
-
-* Purpose:
-* Write an "IsA" data item to a data sink.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WriteIsA( AstChannel *this, const char *class,
-* const char *comment )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected astWriteIsA
-* method inherited from the Channel class).
-
-* Description:
-* This function writes an "IsA" data item to the data sink
-* associated with a FitsChan. This item delimits the end of the
-* data associated with the instance variables of a class, as part
-* of an overall Object definition.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* class
-* Pointer to a constant null-terminated string containing the
-* name of the class whose data are terminated by the "IsA"
-* item.
-* comment
-* Pointer to a constant null-terminated string containing a
-* textual comment to be associated with the "IsA"
-* item. Normally, this will describe the purpose of the class
-* whose data are being terminated.
-
-* Notes:
-* - The comment supplied may not actually be used, depending on
-* the nature of the FitsChan supplied.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFitsChan *this; /* Pointer to the FitsChan structure. */
- char buff[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN + 1 ];
- /* Character buffer */
- char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_channel);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Output an "IsA" item only if there has been at least one item
- written since the last "Begin" or "IsA" item, or if the Full
- attribute for the Channel is greater than zero (requesting maximum
- information). */
- if ( items_written || astGetFull( this ) > 0 ) {
-
-/* Create a unique FITS keyword for this "IsA" item, basing it on
- "ISA". */
- CreateKeyword( this, "ISA", keyword, status );
-
-/* Generate a pre-quoted version of the class name. */
- PreQuote( class, buff, status );
-
-/* Write the "IsA" item to the FitsChan as a keyword and string
- value. */
- astSetFitsS( this, keyword, buff,
- astGetComment( this ) ? comment : NULL, 0 );
-
-/* If helpful information has not been suppressed, generate an
- indented comment to mark the "IsA" item and write it to the
- FitsChan as a comment card with a blank keyword. */
- if ( astGetFull( this ) >= 0 ) {
- MakeIndentedComment( current_indent, '.', "Class boundary", "",
- buff, status );
- astSetFitsCom( this, " ", buff, 0 );
- }
- }
-
-/* Clear the count of items written. */
- items_written = 0;
-}
-
-static void WriteObject( AstChannel *this_channel, const char *name,
- int set, int helpful,
- AstObject *value, const char *comment, int *status ) {
-/*
-* Name:
-* WriteObject
-
-* Purpose:
-* Write an Object value to a data sink.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WriteObject( AstChannel *this, const char *name,
-* int set, int helpful,
-* AstObject *value, const char *comment )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected
-* astWriteObject method inherited from the Channel class).
-
-* Description:
-* This function writes a named Object value, representing the
-* value of a class instance variable, to the data sink associated
-* with a FitsChan. It is intended for use by class "Dump"
-* functions when writing out class information which will
-* subsequently be re-read.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a constant null-terminated string containing the
-* name to be used to identify the value in the external
-* representation. This will form the key for identifying it
-* again when it is re-read. The name supplied should be unique
-* within its class.
-*
-* Mixed case may be used and will be preserved in the external
-* representation (where possible) for cosmetic effect. However,
-* case is not significant when re-reading values.
-*
-* It is recommended that a maximum of 6 alphanumeric characters
-* (starting with an alphabetic character) be used. This permits
-* maximum flexibility in adapting to standard external data
-* representations (e.g. FITS).
-* set
-* If this is zero, it indicates that the value being written is
-* a default value (or can be re-generated from other values) so
-* need not necessarily be written out. Such values will
-* typically be included in the external representation with
-* (e.g.) a comment character so that they are available to
-* human readers but will be ignored when re-read. They may also
-* be completely omitted in some circumstances.
-*
-* If "set" is non-zero, the value will always be explicitly
-* included in the external representation so that it can be
-* re-read.
-* helpful
-* This flag provides a hint about whether a value whose "set"
-* flag is zero (above) should actually appear at all in the
-* external representaton.
-*
-* If the external representation allows values to be "commented
-* out" then, by default, values will be included in this form
-* only if their "helpful" flag is non-zero. Otherwise, they
-* will be omitted entirely. When possible, omitting the more
-* obscure values associated with a class is recommended in
-* order to improve readability.
-*
-* This default behaviour may be further modified if the
-* FitsChan's Full attribute is set - either to permit all
-* values to be shown, or to suppress non-essential information
-* entirely.
-* value
-* A pointer to the Object to be written.
-* comment
-* Pointer to a constant null-terminated string containing a
-* textual comment to be associated with the value.
-*
-* Note that this comment may not actually be used, depending on
-* the nature of the FitsChan supplied and the setting of its
-* Comm attribute.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFitsChan *this; /* Pointer to the FitsChan structure. */
- char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_channel);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Use the "set" and "helpful" flags, along with the FitsChan's
- attributes to decide whether this value should actually be
- written. */
- if ( Use( this, set, helpful, status ) ) {
-
-/* Create a unique FITS keyword from the name supplied. */
- CreateKeyword( this, name, keyword, status );
-
-/* Write the value to the FitsChan as a keyword and a blank string value,
- not pre-quoted (this "null" value indicates that an Object description
- follows). */
- astSetFitsS( this, keyword, "",
- astGetComment( this ) ? comment : NULL, 0 );
-
-/* If the value is "set", write out the Object description. */
- if ( set ) {
- astWrite( this, value );
-
-/* If the value is not set, replace the card just written to the FitsChan
- by COMENT card containing the keyword and blank string value (do not
- write out the Object description). */
- } else {
- MakeIntoComment( this, "astWrite", astGetClass( this ), status );
- }
-
-/* Increment the count of items written. */
- items_written++;
- }
-}
-
-static void WriteToSink( AstFitsChan *this, int *status ){
-/*
-* Name:
-* WriteToSink
-
-* Purpose:
-* Write the contents of the FitsChan out to the sink file or function.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WriteToSink( AstFitsChan *this, int *status )
-
-* Class Membership:
-* FitsChan member function.
-
-* Description:
-* If the SinkFile attribute is set, each card in the FitsChan is
-* written out to the sink file. Otherwise, the cards are passed in
-* turn to the sink function specified when the FitsChan was created.
-* If no sink function was provided, the cards are not written out.
-* Cards marked as having been read into an AST object are not written
-* out.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - The current card is left unchanged.
-*/
-
-/* Local Constants: */
-#define ERRBUF_LEN 80
-
-/* Local Variables: */
- FILE *fd; /* File descriptor for sink file */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- char *errstat; /* Pointer for system error message */
- char card[ AST__FITSCHAN_FITSCARDLEN + 1]; /* Buffer for header card */
- char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */
- const char *sink_file; /* Path to output sink file */
- int icard; /* Current card index on entry */
- int old_ignore_used; /* Original value of external variable ignore_used */
-
-/* Check the global status. */
- if( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this);
-
-/* If the SinkFile attribute is set, open the file. */
- fd = NULL;
- if( astTestSinkFile( this ) ) {
- sink_file = astGetSinkFile( this );
- fd = fopen( sink_file, "w" );
- if( !fd ) {
- if ( errno ) {
-#if HAVE_STRERROR_R
- strerror_r( errno, errbuf, ERRBUF_LEN );
- errstat = errbuf;
-#else
- errstat = strerror( errno );
-#endif
- astError( AST__WRERR, "astDelete(%s): Failed to open output "
- "SinkFile '%s' - %s.", status, astGetClass( this ),
- sink_file, errstat );
- } else {
- astError( AST__WRERR, "astDelete(%s): Failed to open output "
- "SinkFile '%s'.", status, astGetClass( this ),
- sink_file );
- }
- }
- }
-
-/* Only proceed if a file was opened, or sink function and wrapper were supplied. */
- if( fd || ( this->sink && this->sink_wrap ) ){
-
-/* Store the current card index. */
- icard = astGetCard( this );
-
-/* Indicate that cards which have been read into an AST object should skipped
- over by the functions which navigate the linked list of cards. */
- old_ignore_used = ignore_used;
- ignore_used = 1;
-
-/* Ensure that the first card in the FitsChan will be the next one to be
- read. */
- astSetCard( this, 1 );
-
-/* Loop round obtaining and writing out each card, until all cards have been
- processed. */
- while( !astFitsEof( this ) && astOK ){
-
-/* Get the current card, and write it out through the sink function.
- The call to astFindFits increments the current card. */
- if( astFindFits( this, "%f", card, 1 ) ) {
-
-/* If s sink file was opened, write the card out to it. */
- if( fd ) {
- fprintf( fd, "%s\n", card );
-
-/* Otherwise, use the isnk function. The sink function is an externally
- supplied function which may not be thread-safe, so lock a mutex first.
- Also store the channel data pointer in a global variable so that it can
- be accessed in the sink function using macro astChannelData. */
- } else {
- astStoreChannelData( this );
- LOCK_MUTEX3;
- ( *this->sink_wrap )( *this->sink, card, status );
- UNLOCK_MUTEX3;
- }
- }
- }
-
-/* Re-instate the original flag indicating if cards marked as having been
- read should be skipped over. */
- ignore_used = old_ignore_used;
-
-/* Set the current card index back to what it was on entry. */
- astSetCard( this, icard );
- }
-
-/* Close the sink file. */
- if( fd ) fclose( fd );
-}
-
-static void WriteString( AstChannel *this_channel, const char *name,
- int set, int helpful,
- const char *value, const char *comment, int *status ) {
-/*
-* Name:
-* WriteString
-
-* Purpose:
-* Write a string value to a data sink.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* void WriteString( AstChannel *this, const char *name,
-* int set, int helpful,
-* const char *value, const char *comment )
-
-* Class Membership:
-* FitsChan member function (over-rides the protected
-* astWriteString method inherited from the Channel class).
-
-* Description:
-* This function writes a named string value, representing the
-* value of a class instance variable, to the data sink associated
-* with a FitsChan. It is intended for use by class "Dump"
-* functions when writing out class information which will
-* subsequently be re-read.
-
-* Parameters:
-* this
-* Pointer to the FitsChan.
-* name
-* Pointer to a constant null-terminated string containing the
-* name to be used to identify the value in the external
-* representation. This will form the key for identifying it
-* again when it is re-read. The name supplied should be unique
-* within its class.
-*
-* Mixed case may be used and will be preserved in the external
-* representation (where possible) for cosmetic effect. However,
-* case is not significant when re-reading values.
-*
-* It is recommended that a maximum of 6 alphanumeric characters
-* (starting with an alphabetic character) be used. This permits
-* maximum flexibility in adapting to standard external data
-* representations (e.g. FITS).
-* set
-* If this is zero, it indicates that the value being written is
-* a default value (or can be re-generated from other values) so
-* need not necessarily be written out. Such values will
-* typically be included in the external representation with
-* (e.g.) a comment character so that they are available to
-* human readers but will be ignored when re-read. They may also
-* be completely omitted in some circumstances.
-*
-* If "set" is non-zero, the value will always be explicitly
-* included in the external representation so that it can be
-* re-read.
-* helpful
-* This flag provides a hint about whether a value whose "set"
-* flag is zero (above) should actually appear at all in the
-* external representaton.
-*
-* If the external representation allows values to be "commented
-* out" then, by default, values will be included in this form
-* only if their "helpful" flag is non-zero. Otherwise, they
-* will be omitted entirely. When possible, omitting the more
-* obscure values associated with a class is recommended in
-* order to improve readability.
-*
-* This default behaviour may be further modified if the
-* FitsChan's Full attribute is set - either to permit all
-* values to be shown, or to suppress non-essential information
-* entirely.
-* value
-* Pointer to a constant null-terminated string containing the
-* value to be written.
-* comment
-* Pointer to a constant null-terminated string containing a
-* textual comment to be associated with the value.
-*
-* Note that this comment may not actually be used, depending on
-* the nature of the FitsChan supplied and the setting of its
-* Comm attribute.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- AstFitsChan *this; /* Pointer to the FitsChan structure. */
- char *c; /* Pointer to next buffer character */
- char buff1[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ]; /* Buffer for a single substring */
- char buff2[ AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 3 ]; /* Buffer for pre-quoted string */
- char cc; /* Next character */
- char keyword[ FITSNAMLEN + 1 ]; /* Buffer for FITS keyword */
- const char *start; /* Pointer to start of substring */
- int first; /* Is this the first sub-string? */
- int nc; /* No. of available columns remaining */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_channel);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_channel;
-
-/* Use the "set" and "helpful" flags, along with the FitsChan's
- attributes to decide whether this value should actually be
- written. */
- if ( Use( this, set, helpful, status ) ) {
-
-/* Create a unique FITS keyword from the name supplied. */
- CreateKeyword( this, name, keyword, status );
-
-/* Store a pointer to the start of the next sub-string (i.e. the
- beggining of the string), and then loop round until the end of the
- string is reached. */
- start = value;
- first = 1;
- while( *start && astOK ){
-
-/* Store the number of characters available in the 80 column header card
- for the next substring, leaving room for the "= " string at the start,
- and the delimiting quotes. Also reserve 2 characters to allow for the
- possibility of double quotes being needed to protect trailing white space
- (see function PreQuote). */
- nc = AST__FITSCHAN_FITSCARDLEN - FITSNAMLEN - 6;
-
-/* If this is the first sub-string reserve room for any comment. */
- if( first ){
- if( comment && comment[0] ) nc -= ChrLen( comment, status ) + 3;
-
-/* If the first card will be turned into a comment card, we need to leave room
- for the keyword name and equals sign, etc, within the 80 columns. */
- if( !set ) nc -= FITSNAMLEN + 5;
- }
-
-/* We need to check the sub-string for single quotes since these will
- take up 2 characters each instead of 1 when encoded since single quotes
- within a string are doubled. Search through from the starting
- character, copying the sub-string into a buffer, and reducing the number
- of available characters remaining in the card for each character. */
- c = buff1;
- while( *start && nc > 0 ){
- cc = *(start++);
- *(c++) = cc;
- if( cc == '\'' ) {
- nc -= 2;
- } else {
- nc -= 1;
- }
- }
-
-/* If the last character in the substring was a single quote, there may
- not have been room for the extra quote which is added when the
- sub-string is encoded. In this case we need to back up a character in
- order to remove the single quote frin this substring and move it into
- the next sub-string. */
- if( nc < 0 ){
- start--;
- c--;
- }
-
-/* If the supplied value has not been exhausted, append an ampersand to
- the string. In this case we need to move the last character in the
- substring into the next substring to make room for the ampersand. */
- if( *start ) {
- start--;
- c--;
- *(c++) = '&';
- }
-
-/* Terminate the buffer. */
- *c = 0;
-
-/* The FITS standard considers trailing white space is be insignificant,
- and so we need to guard against external applications throwing away
- significant trailing white space. This is done by encosing the string,
- including trailing white space, in double quotes. */
- PreQuote( buff1, buff2, status );
-
-/* On the first pass through this loop, write the value to the FitsChan as
- a keyword and value */
- if( first ){
- astSetFitsS( this, keyword, buff2,
- astGetComment( this ) ? comment : NULL, 0 );
-
-/* If the value is not "set", replace the card just written by a COMMENT
- card containing the text of the card as the comment. */
- if( !set ) MakeIntoComment( this, "astWrite", astGetClass( this ), status );
-
-/* On subsequent passes through the loop, store the string using a CONTINUE
- keyword, with type AST__CONTINUE (this type is like AST__STRING but is
- formatted without an equals sign). */
- } else {
- astSetFitsCN( this, "CONTINUE", buff2, NULL, 0 );
- }
- first = 0;
- }
-
-/* Increment the count of items written. */
- items_written++;
- }
-}
-
-static AstMapping *ZPXMapping( AstFitsChan *this, FitsStore *store, char s,
- int naxes, int zpxaxes[2], const char *method,
- const char *class, int *status ){
-/*
-* Name:
-* ZPXMapping
-
-* Purpose:
-* Create a Mapping descriping "-ZPX" (IRAF) distortion.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* AstMapping *ZPXMapping( AstFitsChan *this, FitsStore *store, char s,
-* int naxes, int zpxaxes[2], const char *method,
-* const char *class, int *status )
-
-* Class Membership:
-* FitsChan
-
-* Description:
-* This function uses the values in the supplied FitsStore to create a
-* Mapping which implements the "-ZPX" distortion code, produced by
-* the IRAF project. See:
-*
-* http://iraf.noao.edu/projects/ccdmosaic/zpx.html
-*
-* Note, the Mapping created by this function implements the "lngcor"
-* and "latcor" corrections described in the WAT... keywords. The
-* basic ZPN projection code is handled in the normal way, as any
-* other projection is handled.
-
-* Parameters:
-* store
-* A structure containing information about the requested axis
-* descriptions derived from a FITS header.
-* s
-* A character identifying the co-ordinate version to use. A space
-* means use primary axis descriptions. Otherwise, it must be an
-* upper-case alphabetical characters ('A' to 'Z').
-* naxes
-* The number of intermediate world coordinate axes (WCSAXES).
-* zpxaxes
-* The zero-based indices of the two IWC axes that use the ZPX projection.
-* method
-* A pointer to a string holding the name of the calling method.
-* This is used only in the construction of error messages.
-* class
-* A pointer to a string holding the class of the object being
-* read. This is used only in the construction of error messages.
-* status
-* Pointer to the inherited status variable.
-
-* Returned Value:
-* A pointer to the Mapping.
-*/
-
-/* Local Variables: */
- AstMapping *ret;
- char *watstr;
- double *cvals[ 2 ];
- int *mvals[ 2 ];
- int ncoeff[ 2 ];
- int i;
- int icoeff;
- int ok;
-
-/* Initialise the pointer to the returned Mapping. */
- ret = NULL;
-
-/* Check the global status. */
- if ( !astOK ) return ret;
-
-/* Check both axes */
- for( i = 0; i < 2; i++ ){
- mvals[ i ] = NULL;
- cvals[ i ] = NULL;
- ncoeff[ i ] = 0;
-
-/* Concatenate all the IRAF "WAT" keywords together for this axis. These
- keywords are marked as having been used, so that they are not written
- out when the FitsChan is deleted. */
- watstr = ConcatWAT( this, zpxaxes[ i ], method, class, status );
-
-/* Extract the polynomial coefficients from the concatenated WAT string.
- These are returned in the form of a list of PVi_m values for a TPN
- projection. */
- ncoeff[ i ] = WATCoeffs( watstr, i, cvals + i, mvals + i, &ok, status );
-
-/* If the current axis of the ZPX projection uses features not supported
- by AST, do not do any more axes. */
- if( !ok ) break;
-
-/* Free the WAT string. */
- watstr = astFree( watstr );
- }
-
-/* If we can handle the ZPX projection, store the polynomial coefficients in
- a new inverted TPN WcsMap. This WcsMap is used as a correction to the ZPN
- WcsMap to be created later, therefore set its FITSProj value to zero so
- that it is not used as the FITS projection when written out via
- astWrite. Also set TPNTan to zero to indicate that the TAN part of the
- TPN projection should not be used (i.e. just use the polynomial part). */
- if( ok && astOK ) {
-
- if( ncoeff[ 0 ] || ncoeff[ 1 ] ) {
- ret = (AstMapping *) astWcsMap( naxes, AST__TPN, zpxaxes[ 0 ] + 1,
- zpxaxes[ 1 ] + 1, "Invert=1",
- status );
- astSetFITSProj( ret, 0 );
- astSetTPNTan( ret, 0 );
- for( i = 0; i < 2; i++ ){
- for( icoeff = 0; icoeff < ncoeff[ i ]; icoeff++ ) {
- astSetPV( ret, zpxaxes[ i ], (mvals[ i ])[ icoeff ],
- (cvals[ i ])[ icoeff ] );
- }
- }
-
- } else {
- ret = (AstMapping *) astUnitMap( naxes, " ", status );
- }
-
-/* If the TNX cannot be represented in FITS-WCS (within our restrictions), add
- warning keywords to the FitsChan. */
- } else {
- Warn( this, "zpx", "This FITS header includes, or was "
- "derived from, a ZPX projection which requires "
- "unsupported IRAF-specific corrections. The WCS "
- "information may therefore be incorrect.", method, class,
- status );
- }
-
-/* Return the result. */
- return ret;
-}
-
-/* Functions which access class attributes. */
-/* ---------------------------------------- */
-
-/* Implement member functions to access the attributes associated with
- this class using the macros defined for this purpose in the
- "object.h" file. For a description of each attribute, see the class
- interface (in the associated .h file). */
-
-/* Card. */
-/* ===== */
-
-/*
-*att++
-* Name:
-* Card
-
-* Purpose:
-* Index of current FITS card in a FitsChan.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer.
-
-* Description:
-* This attribute gives the index of the "current" FITS header card
-* within a FitsChan, the first card having an index of 1. The
-c choice of current card affects the behaviour of functions that
-f choice of current card affects the behaviour of routines that
-c access the contents of the FitsChan, such as astDelFits,
-c astFindFits and astPutFits.
-f access the contents of the FitsChan, such as AST_DELFITS,
-f AST_FINDFITS and AST_PUTFITS.
-*
-* A value assigned to Card will position the FitsChan at any
-* desired point, so that a particular card within it can be
-* accessed. Alternatively, the value of Card may be enquired in
-* order to determine the current position of a FitsChan.
-*
-* The default value of Card is 1. This means that clearing
-c this attribute (using astClear) effectively "rewinds" the
-f this attribute (using AST_CLEAR) effectively "rewinds" the
-* FitsChan, so that the first card is accessed next. If Card is
-* set to a value which exceeds the total number of cards in the
-* FitsChan (as given by its Ncard attribute), it is regarded as
-* pointing at the "end-of-file". In this case, the value returned
-* in response to an enquiry is always one more than the number of
-* cards in the FitsChan.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-
-/* Encoding. */
-/* ========= */
-
-/*
-*att++
-* Name:
-* Encoding
-
-* Purpose:
-* System for encoding Objects as FITS headers.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* String.
-
-* Description:
-* This attribute specifies the encoding system to use when AST
-* Objects are stored as FITS header cards in a FitsChan. It
-c affects the behaviour of the astWrite and astRead functions when
-f affects the behaviour of the AST_WRITE and AST_READ routines when
-* they are used to transfer any AST Object to or from an external
-* representation consisting of FITS header cards (i.e. whenever a
-* write or read operation is performed using a FitsChan as the I/O
-* Channel).
-*
-* There are several ways (conventions) by which coordinate system
-* information may be represented in the form of FITS headers and
-* the Encoding attribute is used to specify which of these should
-* be used. The encoding options available are outlined in the
-* "Encodings Available" section below, and in more detail in the
-* sections which follow.
-*
-* Encoding systems differ in the range of possible Objects
-* (e.g. classes) they can represent, in the restrictions they
-* place on these Objects (e.g. compatibility with some
-* externally-defined coordinate system model) and in the number of
-* Objects that can be stored together in any particular set of
-* FITS header cards (e.g. multiple Objects, or only a single
-* Object). The choice of encoding also affects the range of
-* external applications which can potentially read and interpret
-* the FITS header cards produced.
-*
-* The encoding options available are not necessarily mutually
-* exclusive, and it may sometimes be possible to store multiple
-* Objects (or the same Object several times) using different
-* encodings within the same set of FITS header cards. This
-* possibility increases the likelihood of other applications being
-* able to read and interpret the information.
-*
-* By default, a FitsChan will attempt to determine which encoding
-* system is already in use, and will set the default Encoding
-* value accordingly (so that subsequent I/O operations adopt the
-* same conventions). It does this by looking for certain critical
-* FITS keywords which only occur in particular encodings. For
-* details of how this works, see the "Choice of Default Encoding"
-* section below. If you wish to ensure that a particular encoding
-* system is used, independently of any FITS cards already present,
-* you should set an explicit Encoding value yourself.
-
-* Encodings Available:
-* The Encoding attribute can take any of the following (case
-* insensitive) string values to select the corresponding encoding
-
-* system:
-*
-* - "DSS": Encodes coordinate system information in FITS header
-* cards using the convention developed at the Space Telescope
-* Science Institute (STScI) for the Digitised Sky Survey (DSS)
-* astrometric plate calibrations. The main advantages of this
-* encoding are that FITS images which use it are widely available
-* and it is understood by a number of important and
-* well-established astronomy applications. For further details,
-* see the section "The DSS Encoding" below.
-*
-* - "FITS-WCS": Encodes coordinate system information in FITS
-* header cards using the conventions described in the FITS
-* world coordinate system (FITS-WCS) papers by E.W. Greisen,
-* M. Calabretta, et al. The main advantages of this encoding are that
-* it should be understood by any FITS-WCS compliant application and
-* is likely to be adopted widely for FITS data in future. For further
-* details, see the section "The FITS-WCS Encoding" below.
-*
-* - "FITS-PC": Encodes coordinate system information in FITS
-* header cards using the conventions described in an earlier draft
-* of the FITS world coordinate system papers by E.W. Greisen and
-* M. Calabretta. This encoding uses a combination of CDELTi and
-* PCiiijjj keywords to describe the scale and rotation of the pixel
-* axes. This encoding is included to support existing data and
-* software which uses these now superceded conventions. In general,
-* the "FITS-WCS" encoding (which uses CDi_j or PCi_j keywords to
-* describe the scale and rotation) should be used in preference to
-* "FITS-PC".
-*
-* - "FITS-IRAF": Encodes coordinate system information in FITS
-* header cards using the conventions described in the document
-* "World Coordinate Systems Representations Within the FITS
-* Format" by R.J. Hanisch and D.G. Wells, 1988. This encoding is
-* currently employed by the IRAF data analysis facility, so its
-* use will facilitate data exchange with IRAF. Its main advantages
-* are that it is a stable convention which approximates to a
-* subset of the propsed FITS-WCS encoding (above). This makes it
-* suitable as an interim method for storing coordinate system
-* information in FITS headers until the FITS-WCS encoding becomes
-* stable. Since many datasets currently use the FITS-IRAF
-* encoding, conversion of data from FITS-IRAF to the final form of
-* FITS-WCS is likely to be well supported.
-*
-* - "FITS-AIPS": Encodes coordinate system information in FITS
-* header cards using the conventions originally introduced by the
-* AIPS data analysis facility. This is base on the use of CDELTi and
-* CROTAi keuwords to desribe the scale and rotation of each axis.
-* These conventions have been superceded but are still widely used.
-*
-* - "FITS-AIPS++": Encodes coordinate system information in FITS
-* header cards using the conventions used by the AIPS++ project.
-* This is an extension of FITS-AIPS which includes some of the
-* features of FITS-IRAF and FITS-PC.
-*
-* - "FITS-CLASS": Encodes coordinate system information in FITS
-* header cards using the conventions used by the CLASS project.
-* CLASS is a software package for reducing single-dish radio and
-* sub-mm spectroscopic data. See the section "CLASS FITS format" at
-* http://www.iram.fr/IRAMFR/GILDAS/doc/html/class-html/.
-*
-* - "NATIVE": Encodes AST Objects in FITS header cards using a
-* convention which is private to the AST library (but adheres to
-* the general FITS standard) and which uses FITS keywords that
-* will not clash with other encoding systems. The main advantages
-* of this are that any class of AST Object may be encoded, and any
-* (reasonable) number of Objects may be stored sequentially in the
-* same FITS header. This makes FITS headers an almost loss-less
-* communication path for passing AST Objects between applications
-* (although all such applications must, of course, make use of the
-* AST library to interpret the information). For further details,
-* see the section "The NATIVE Encoding" below.
-
-* Choice of Default Encoding:
-* If the Encoding attribute of a FitsChan is not set, the default
-* value it takes is determined by the presence of certain critical
-* FITS keywords within the FitsChan. The sequence of decisions
-
-* used to arrive at the default value is as follows:
-*
-* - If the FitsChan contains any keywords beginning with the
-* string "BEGAST", then NATIVE encoding is used,
-* - Otherwise, FITS-CLASS is used if the FitsChan contains a DELTAV
-* keyword and a keyword of the form VELO-xxx, where xxx indicates one
-* of the rest frames used by class (e.g. "VELO-LSR"), or "VLSR".
-* - Otherwise, if the FitsChan contains a CTYPE keyword which
-* represents a spectral axis using the conventions of the AIPS and
-* AIPS++ projects (e.g. "FELO-LSR", etc), then one of FITS-AIPS or
-* FITS-AIPS++ encoding is used. FITS-AIPS++ is used if any of the
-* keywords CDi_j, PROJP, LONPOLE or LATPOLE are
-* found in the FitsChan. Otherwise FITS-AIPS is used.
-* - Otherwise, if the FitsChan contains a keyword of the form
-* "PCiiijjj", where "i" and "j" are single digits, then
-* FITS-PC encoding is used,
-* - Otherwise, if the FitsChan contains a keyword of the form
-* "CDiiijjj", where "i" and "j" are single digits, then
-* FITS-IRAF encoding is used,
-* - Otherwise, if the FitsChan contains a keyword of the form
-* "CDi_j", and at least one of RADECSYS, PROJPi, or CjVALi
-* where "i" and "j" are single digits, then FITS-IRAF encoding is
-* used.
-* - Otherwise, if the FitsChan contains any keywords of the form
-* PROJPi, CjVALi or RADECSYS, where "i" and "j" are single digits,
-* then FITS-PC encoding is used.
-* - Otherwise, if the FitsChan contains a keyword of the form
-* CROTAi, where "i" is a single digit, then FITS-AIPS encoding is
-* used.
-* - Otherwise, if the FitsChan contains a keyword of the form
-* CRVALi, where "i" is a single digit, then FITS-WCS encoding is
-* used.
-* - Otherwise, if the FitsChan contains the "PLTRAH" keyword, then
-* DSS encoding is used,
-* - Otherwise, if none of these conditions is met (as would be the
-* case when using an empty FitsChan), then NATIVE encoding is
-* used.
-*
-* Except for the NATIVE and DSS encodings, all the above checks
-* also require that the header contains at least one CTYPE, CRPIX and
-* CRVAL keyword (otherwise the checking process continues to the next
-* case).
-*
-* Setting an explicit value for the Encoding attribute always
-* over-rides this default behaviour.
-*
-* Note that when writing information to a FitsChan, the choice of
-* encoding will depend greatly on the type of application you
-* expect to be reading the information in future. If you do not
-* know this, there may sometimes be an advantage in writing the
-* information several times, using a different encoding on each
-* occasion.
-
-* The DSS Encoding:
-* The DSS encoding uses FITS header cards to store a multi-term
-* polynomial which relates pixel positions on a digitised
-* photographic plate to celestial coordinates (right ascension and
-* declination). This encoding may only be used to store a single
-* AST Object in any set of FITS header cards, and that Object must
-* be a FrameSet which conforms to the STScI/DSS coordinate system
-* model (this means the Mapping which relates its base and current
-* Frames must include either a DssMap or a WcsMap with type
-* AST__TAN or AST__TPN).
-*
-c When reading a DSS encoded Object (using astRead), the FitsChan
-f When reading a DSS encoded Object (using AST_READ), the FitsChan
-* concerned must initially be positioned at the first card (its
-* Card attribute must equal 1) and the result of the read, if
-* successful, will always be a pointer to a FrameSet. The base
-* Frame of this FrameSet represents DSS pixel coordinates, and the
-* current Frame represents DSS celestial coordinates. Such a read
-* is always destructive and causes the FITS header cards required
-* for the construction of the FrameSet to be removed from the
-* FitsChan, which is then left positioned at the "end-of-file". A
-* subsequent read using the same encoding will therefore not
-* return another FrameSet, even if the FitsChan is rewound.
-*
-c When astWrite is used to store a FrameSet using DSS encoding,
-f When AST_WRITE is used to store a FrameSet using DSS encoding,
-* an attempt is first made to simplify the FrameSet to see if it
-* conforms to the DSS model. Specifically, the current Frame must
-* be a FK5 SkyFrame; the projection must be a tangent plane
-* (gnomonic) projection with polynomial corrections conforming to
-* DSS requirements, and north must be parallel to the second base
-* Frame axis.
-*
-* If the simplification process succeeds, a description of the
-* FrameSet is written to the FitsChan using appropriate DSS FITS
-* header cards. The base Frame of the FrameSet is used to form the
-* DSS pixel coordinate system and the current Frame gives the DSS
-* celestial coordinate system. A successful write operation will
-* over-write any existing DSS encoded data in the FitsChan, but
-* will not affect other (non-DSS) header cards. If a destructive
-* read of a DSS encoded Object has previously occurred, then an
-* attempt will be made to store the FITS header cards back in
-* their original locations.
-*
-* If an attempt to simplify a FrameSet to conform to the DSS model
-* fails (or if the Object supplied is not a FrameSet), then no
-c data will be written to the FitsChan and astWrite will return
-f data will be written to the FitsChan and AST_WRITE will return
-* zero. No error will result.
-
-* The FITS-WCS Encoding:
-* The FITS-WCS convention uses FITS header cards to describe the
-* relationship between pixels in an image (not necessarily
-* 2-dimensional) and one or more related "world coordinate systems".
-* The FITS-WCS encoding may only be used to store a single AST Object
-* in any set of FITS header cards, and that Object must be a FrameSet
-* which conforms to the FITS-WCS model (the FrameSet may, however,
-* contain multiple Frames which will be result in multiple FITS
-* "alternate axis descriptions"). Details of the use made by this
-* Encoding of the conventions described in the FITS-WCS papers are
-* given in the appendix "FITS-WCS Coverage" of this document. A few
-* main points are described below.
-*
-* The rotation and scaling of the intermediate world coordinate system
-* can be specified using either "CDi_j" keywords, or "PCi_j" together
-* with "CDELTi" keywords. When writing a FrameSet to a FitsChan, the
-* the value of the CDMatrix attribute of the FitsChan determines
-* which system is used.
-*
-* In addition, this encoding supports the "TAN with polynomial correction
-* terms" projection which was included in a draft of the FITS-WCS paper,
-* but was not present in the final version. A "TAN with polynomial
-* correction terms" projection is represented using a WcsMap with type
-* AST__TPN (rather than AST__TAN which is used to represent simple
-* TAN projections). When reading a FITS header, a CTYPE keyword value
-* including a "-TAN" code results in an AST__TPN projection if there are
-* any projection parameters (given by the PVi_m keywords) associated with
-* the latitude axis, or if there are projection parameters associated
-* with the longitude axis for m greater than 4. When writing a
-* FrameSet to a FITS header, an AST__TPN projection gives rise to a
-* CTYPE value including the normal "-TAN" code, but the projection
-* parameters are stored in keywords with names "QVi_m", instead of the
-* usual "PVi_m". Since these QV parameters are not part of the
-* FITS-WCS standard they will be ignored by other non-AST software,
-* resulting in the WCS being interpreted as a simple TAN projection
-* without any corrections. This should be seen as an interim solution
-* until such time as an agreed method for describing projection
-* distortions within FITS-WCS has been published.
-*
-* AST extends the range of celestial coordinate systems which may be
-* described using this encoding by allowing the inclusion of
-* "AZ--" and "EL--" as the coordinate specification within CTYPE
-* values. These form a longitude/latitude pair of axes which describe
-* azimuth and elevation. The geographic position of the observer
-* should be supplied using the OBSGEO-X/Y/Z keywords described in FITS-WCS
-* paper III. Currently, a simple model is used which includes diurnal
-* aberration, but ignores atmospheric refraction, polar motion, etc.
-* These may be added in a later release.
-*
-* If an AST SkyFrame that represents offset rather than absolute
-* coordinates (see attribute SkyRefIs) is written to a FitsChan using
-* FITS-WCS encoding, two alternate axis descriptions will be created.
-* One will describe the offset coordinates, and will use "OFLN" and
-* "OFLT" as the axis codes in the CTYPE keywords. The other will
-* describe absolute coordinates as specified by the System attribute
-* of the SkyFrame, using the usual CTYPE codes ("RA--"/"DEC-", etc).
-* In addition, the absolute coordinates description will contain
-* AST-specific keywords (SREF1/2, SREFP1/2 and SREFIS) that allow the
-* header to be read back into AST in order to reconstruct the original
-* SkyFrame.
-*
-c When reading a FITS-WCS encoded Object (using astRead), the FitsChan
-f When reading a FITS-WCS encoded Object (using AST_READ), the FitsChan
-* concerned must initially be positioned at the first card (its
-* Card attribute must equal 1) and the result of the read, if
-* successful, will always be a pointer to a FrameSet. The base
-* Frame of this FrameSet represents FITS-WCS pixel coordinates,
-* and the current Frame represents the physical coordinate system
-* described by the FITS-WCS primary axis descriptions. If
-* secondary axis descriptions are also present, then the FrameSet
-* may contain additional (non-current) Frames which represent
-* these. Such a read is always destructive and causes the FITS
-* header cards required for the construction of the FrameSet to be
-* removed from the FitsChan, which is then left positioned at the
-* "end-of-file". A subsequent read using the same encoding will
-* therefore not return another FrameSet, even if the FitsChan is
-* rewound.
-*
-c When astWrite is used to store a FrameSet using FITS-WCS
-f When AST_WRITE is used to store a FrameSet using FITS-WCS
-* encoding, an attempt is first made to simplify the FrameSet to
-* see if it conforms to the FITS-WCS model. If this simplification
-* process succeeds (as it often should, as the model is reasonably
-* flexible), a description of the FrameSet is written to the
-* FitsChan using appropriate FITS header cards. The base Frame of
-* the FrameSet is used to form the FITS-WCS pixel coordinate
-* system and the current Frame gives the physical coordinate
-* system to be described by the FITS-WCS primary axis
-* descriptions. Any additional Frames in the FrameSet may be used
-* to construct secondary axis descriptions, where appropriate.
-*
-* A successful write operation will over-write any existing
-* FITS-WCS encoded data in the FitsChan, but will not affect other
-* (non-FITS-WCS) header cards. If a destructive read of a FITS-WCS
-* encoded Object has previously occurred, then an attempt will be
-* made to store the FITS header cards back in their original
-* locations. Otherwise, the new cards will be inserted following
-* any other FITS-WCS related header cards present or, failing
-* that, in front of the current card (as given by the Card
-* attribute).
-*
-* If an attempt to simplify a FrameSet to conform to the FITS-WCS
-* model fails (or if the Object supplied is not a FrameSet), then
-c no data will be written to the FitsChan and astWrite will
-f no data will be written to the FitsChan and AST_WRITE will
-* return zero. No error will result.
-
-* The FITS-IRAF Encoding:
-* The FITS-IRAF encoding can, for most purposes, be considered as
-* a subset of the FITS-WCS encoding (above), although it differs
-* in the details of the FITS keywords used. It is used in exactly
-* the same way and has the same restrictions, but with the
-
-* addition of the following:
-*
-* - The only celestial coordinate systems that may be represented
-* are equatorial, galactic and ecliptic,
-* - Sky projections can be represented only if any associated
-* projection parameters are set to their default values.
-* - Secondary axis descriptions are not supported, so when writing
-* a FrameSet to a FitsChan, only information from the base and
-* current Frames will be stored.
-*
-* Note that this encoding is provided mainly as an interim measure to
-* provide a more stable alternative to the FITS-WCS encoding until the
-* FITS standard for encoding WCS information is finalised. The name
-* "FITS-IRAF" indicates the general keyword conventions used and does
-* not imply that this encoding will necessarily support all features of
-* the WCS scheme used by IRAF software. Nevertheless, an attempt has
-* been made to support a few such features where they are known to be
-* used by important sources of data.
-*
-* When writing a FrameSet using the FITS-IRAF encoding, axis rotations
-* are specified by a matrix of FITS keywords of the form "CDi_j", where
-* "i" and "j" are single digits. The alternative form "CDiiijjj", which
-* is also in use, is recognised when reading an Object, but is never
-* written.
-*
-* In addition, the experimental IRAF "ZPX" and "TNX" sky projections will
-* be accepted when reading, but will never be written (the corresponding
-* FITS "ZPN" or "distorted TAN" projection being used instead). However,
-* there are restrictions on the use of these experimental projections.
-* For "ZPX", longitude and latitude correction surfaces (appearing as
-* "lngcor" or "latcor" terms in the IRAF-specific "WAT" keywords) are
-* not supported. For "TNX" projections, only cubic surfaces encoded as
-* simple polynomials with "half cross-terms" are supported. If an
-* un-usable "TNX" or "ZPX" projection is encountered while reading
-* from a FitsChan, a simpler form of TAN or ZPN projection is used
-* which ignores the unsupported features and may therefore be
-* inaccurate. If this happens, a warning message is added to the
-* contents of the FitsChan as a set of cards using the keyword "ASTWARN".
-*
-* You should not normally attempt to mix the foreign FITS encodings within
-* the same FitsChan, since there is a risk that keyword clashes may occur.
-
-* The FITS-PC Encoding:
-* The FITS-PC encoding can, for most purposes, be considered as
-* equivalent to the FITS-WCS encoding (above), although it differs
-* in the details of the FITS keywords used. It is used in exactly
-* the same way and has the same restrictions.
-
-* The FITS-AIPS Encoding:
-* The FITS-AIPS encoding can, for most purposes, be considered as
-* equivalent to the FITS-WCS encoding (above), although it differs
-* in the details of the FITS keywords used. It is used in exactly
-* the same way and has the same restrictions, but with the
-
-* addition of the following:
-*
-* - The only celestial coordinate systems that may be represented
-* are equatorial, galactic and ecliptic,
-* - Spectral axes can only be represented if they represent
-* frequency, radio velocity or optical velocity, and are linearly
-* sampled in frequency. In addition, the standard of rest
-* must be LSRK, LSRD, barycentric or geocentric.
-* - Sky projections can be represented only if any associated
-* projection parameters are set to their default values.
-* - The AIT, SFL and MER projections can only be written if the CRVAL
-* keywords are zero for both longitude and latitude axes.
-* - Secondary axis descriptions are not supported, so when writing
-* a FrameSet to a FitsChan, only information from the base and
-* current Frames will be stored.
-* - If there are more than 2 axes in the base and current Frames, any
-* rotation must be restricted to the celestial plane, and must involve
-* no shear.
-
-* The FITS-AIPS++ Encoding:
-* The FITS-AIPS++ encoding is based on the FITS-AIPS encoding, but
-* includes some features of the FITS-IRAF and FITS-PC encodings.
-* Specifically, any celestial projections supported by FITS-PC may be
-* used, including those which require parameterisation, and the axis
-* rotation and scaling may be specified using CDi_j keywords. When
-* writing a FITS header, rotation will be specified using CROTA/CDELT
-* keywords if possible, otherwise CDi_j keywords will be used instead.
-
-* The FITS-CLASS Encoding:
-* The FITS-CLASS encoding uses the conventions of the CLASS project.
-* These are described in the section "Developer Manual"/"CLASS FITS
-
-* Format" contained in the CLASS documentation at:
-*
-* http://www.iram.fr/IRAMFR/GILDAS/doc/html/class-html/class.html.
-*
-
-* This encoding is similar to FITS-AIPS with the following restrictions:
-*
-* - When a SpecFrame is created by reading a FITS-CLASS header, the
-* attributes describing the observer's position (ObsLat, ObsLon and
-* ObsAlt) are left unset because the CLASS encoding does not specify
-* these values. Conversions to or from the topocentric standard of rest
-* will therefore be inaccurate (typically by up to about 0.5 km/s)
-* unless suitable values are assigned to these attributes after the
-* FrameSet has been created.
-* - When writing a FrameSet to a FITS-CLASS header, the current Frame
-* in the FrameSet must have at least 3 WCS axes, of which one must be
-* a linear spectral axis. The spectral axis in the created header will
-* always describe frequency. If the spectral axis in the supplied
-* FrameSet refers to some other system (e.g. radio velocity, etc),
-* then it will be converted to frequency.
-* - There must be a pair of celestial axes - either (RA,Dec) or
-* (GLON,GLAT). RA and Dec must be either FK4/B1950 or FK5/J2000.
-* - A limited range of projection codes (TAN, ARC, STG, AIT, SFL, SIN)
-* can be used. For AIT and SFL, the reference point must be at the
-* origin of longitude and latitude. For SIN, the associated projection
-* parameters must both be zero.
-* - No rotation of the celestial axes is allowed, unless the spatial
-* axes are degenerate (i.e. cover only a single pixel).
-* - The frequency axis in the created header will always describe
-* frequency in the source rest frame. If the supplied FrameSet uses
-* some other standard of rest then suitable conversion will be applied.
-* - The source velocity must be defined. In other words, the SpecFrame
-* attributes SourceVel and SourceVRF must have been assigned values.
-* - The frequency axis in a FITS-CLASS header does not represent
-* absolute frequency, but instead represents offsets from the rest
-* frequency in the standard of rest of the source.
-*
-* When writing a FrameSet out using FITS-CLASS encoding, the current
-* Frame may be temporarily modified if this will allow the header
-* to be produced. If this is done, the associated pixel->WCS Mapping
-* will also be modified to take account of the changes to the Frame.
-* The modifications performed include re-ordering axes (WCS axes, not
-* pixel axes), changing spectral coordinate system and standard of
-* rest, changing the celestial coordinate system and reference equinox,
-* and changing axis units.
-
-* The NATIVE Encoding:
-* The NATIVE encoding may be used to store a description of any
-* class of AST Object in the form of FITS header cards, and (for
-* most practical purposes) any number of these Object descriptions
-* may be stored within a single set of FITS cards. If multiple
-* Object descriptions are stored, they are written and read
-* sequentially. The NATIVE encoding makes use of unique FITS
-* keywords which are designed not to clash with keywords that have
-* already been used for other purposes (if a potential clash is
-* detected, an alternative keyword is constructed to avoid the
-* clash).
-*
-* When reading a NATIVE encoded object from a FitsChan (using
-c astRead), FITS header cards are read, starting at the current
-f AST_READ), FITS header cards are read, starting at the current
-* card (as determined by the Card attribute), until the start of
-* the next Object description is found. This description is then
-* read and converted into an AST Object, for which a pointer is
-* returned. Such a read is always destructive and causes all the
-* FITS header cards involved in the Object description to be
-* removed from the FitsChan, which is left positioned at the
-* following card.
-*
-* The Object returned may be of any class, depending on the
-* description that was read, and other AST routines may be used to
-* validate it (for example, by examining its Class or ID attribute
-c using astGetC). If further NATIVE encoded Object descriptions
-f using AST_GETC). If further NATIVE encoded Object descriptions
-c exist in the FitsChan, subsequent calls to astRead will return
-f exist in the FitsChan, subsequent calls to AST_READ will return
-* the Objects they describe in sequence (and destroy their
-* descriptions) until no more remain between the current card and
-* the "end-of-file".
-*
-c When astWrite is used to write an Object using NATIVE encoding,
-f When AST_WRITE is used to write an Object using NATIVE encoding,
-* a description of the Object is inserted immediately before the
-* current card (as determined by the Card attribute). Multiple
-* Object descriptions may be written in this way and are stored
-* separately (and sequentially if the Card attribute is not
-* modified between the writes). A write operation using the NATIVE
-* encoding does not over-write previously written Object
-* descriptions. Note, however, that subsequent behaviour is
-* undefined if an Object description is written inside a
-* previously-written description, so this should be avoided.
-*
-* When an Object is written to a FitsChan using NATIVE encoding,
-c astWrite should (barring errors) always transfer data and
-f AST_WRITE should (barring errors) always transfer data and
-* return a value of 1.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,Encoding,encoding,UNKNOWN_ENCODING)
-astMAKE_SET(FitsChan,Encoding,int,encoding,(
- value == NATIVE_ENCODING ||
- value == FITSPC_ENCODING ||
- value == FITSWCS_ENCODING ||
- value == FITSIRAF_ENCODING ||
- value == FITSAIPS_ENCODING ||
- value == FITSAIPSPP_ENCODING ||
- value == FITSCLASS_ENCODING ||
- value == DSS_ENCODING ? value :
- (astError( AST__BADAT, "astSetEncoding: Unknown encoding system %d "
- "supplied.", status, value ), UNKNOWN_ENCODING )))
-astMAKE_TEST(FitsChan,Encoding,( this->encoding != UNKNOWN_ENCODING ))
-
-/* DefB1950 */
-/* ======== */
-
-/*
-*att++
-* Name:
-* DefB1950
-
-* Purpose:
-* Use FK4 B1950 as defaults?
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer (boolean).
-
-* Description:
-* This attribute is a boolean value which specifies a default equinox
-* and reference frame to use when reading a FrameSet from a FitsChan
-* with a foreign (i.e. non-native) encoding. It is only used if the FITS
-* header contains RA and DEC axes but contains no information about the
-* reference frame or equinox. If this is the case, then values of FK4 and
-* B1950 are assumed if the DefB1950 attribute has a non-zero value and
-* ICRS is assumed if DefB1950 is zero. The default value for DefB1950
-* depends on the value of the Encoding attribute: for FITS-WCS encoding
-* the default is zero, and for all other encodings it is one.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,DefB1950,defb1950,-1)
-astMAKE_GET(FitsChan,DefB1950,int,1,(this->defb1950 == -1 ? (astGetEncoding(this)== FITSWCS_ENCODING?0:1): this->defb1950))
-astMAKE_SET(FitsChan,DefB1950,int,defb1950,( value ? 1 : 0 ))
-astMAKE_TEST(FitsChan,DefB1950,( this->defb1950 != -1 ))
-
-/* TabOK */
-/* ===== */
-
-/*
-*att++
-* Name:
-* TabOK
-
-* Purpose:
-* Should the FITS-WCS -TAB algorithm be recognised?
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer.
-
-* Description:
-* This attribute is an integer value which indicates if the "-TAB"
-* algorithm, defined in FITS-WCS paper III, should be supported by
-* the FitsChan. The default value is zero. A zero or negative value
-* results in no support for -TAB axes (i.e. axes that have "-TAB"
-* in their CTYPE keyword value). In this case, the
-c astWrite
-f AST_WRITE
-* method will return zero if the write operation would required the
-* use of the -TAB algorithm, and the
-c astRead
-f AST_READ
-* method will return
-c a NULL pointer
-f AST__NULL
-* if any axis in the supplied header uses the -TAB algorithm.
-
-* If TabOK is set to a non-zero positive integer, these methods will
-* recognise and convert axes described by the -TAB algorithm, as
-* follows:
-*
-c The astWrite
-f The AST_WRITE
-* method will generate headers that use the -TAB algorithm (if
-* possible) if no other known FITS-WCS algorithm can be used to
-* describe the supplied FrameSet. This will result in a table of
-* coordinate values and index vectors being stored in the FitsChan.
-* After the write operation, the calling application should check to
-* see if such a table has been stored in the FitsChan. If so, the
-* table should be retrived from the FitsChan using the
-c astGetTables
-f AST_GETTABLES
-* method, and the data (and headers) within it copied into a new
-* FITS binary table extension. See
-c astGetTables
-f AST_GETTABLES
-* for more information. The FitsChan uses a FitsTable object to store
-* the table data and headers. This FitsTable will contain the required
-* columns and headers as described by FITS-WCS paper III - the
-* coordinates array will be in a column named "COORDS", and the index
-* vector(s) will be in columns named "INDEX<i>" (where <i> is the index
-* of the corresponding FITS WCS axis). Note, index vectors are only
-* created if required. The EXTNAME value will be set to the value of the
-* AST__TABEXTNAME constant (currently "WCS-TAB"). The EXTVER header
-* will be set to the positive integer value assigned to the TabOK
-* attribute. No value will be stored for the EXTLEVEL header, and should
-* therefore be considered to default to 1.
-*
-c The astRead
-f The AST_READ
-* method will generate a FrameSet from headers that use the -TAB
-* algorithm so long as the necessary FITS binary tables are made
-* available. There are two ways to do this: firstly, if the application
-* knows which FITS binary tables will be needed, then it can create a
-* Fitstable describing each such table and store it in the FitsChan
-* (using method
-c astPutTables or astPutTable) before invoking the astRead method.
-f AST_PUTTABLES or AST_PUTTABLE) before invoking the AST_READ method.
-* Secondly, if the application does not know which FITS binary tables
-* will be needed by
-c astRead,
-f AST_READ,
-* then it can register a call-back function with the FitsChan using
-* method
-c astTableSource.
-f AST_TABLESOURCE.
-* This call-back function will be called from within
-c astRead
-f AST_READ
-* if and when a -TAB header is encountered. When called, its arguments
-* will give the name, version and level of the FITS extension containing
-* a required table. The call-back function should read this table from
-* an external FITS file, and create a corresponding FitsTable which
-* it should then return to
-c astRead. Note, currently astRead
-f AST_READ. Note, currently AST_READ
-* can only handle -TAB headers that describe 1-dimensional (i.e.
-* separable) axes.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,TabOK,tabok,-INT_MAX)
-astMAKE_GET(FitsChan,TabOK,int,0,(this->tabok == -INT_MAX ? 0 : this->tabok))
-astMAKE_SET(FitsChan,TabOK,int,tabok,value)
-astMAKE_TEST(FitsChan,TabOK,( this->tabok != -INT_MAX ))
-
-/* CarLin */
-/* ====== */
-
-/*
-*att++
-* Name:
-* CarLin
-
-* Purpose:
-* Ignore spherical rotations on CAR projections?
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer (boolean).
-
-* Description:
-* This attribute is a boolean value which specifies how FITS "CAR"
-* (plate carree, or "Cartesian") projections should be treated when
-* reading a FrameSet from a foreign encoded FITS header. If zero (the
-* default), it is assumed that the CAR projection conforms to the
-* conventions described in the FITS world coordinate system (FITS-WCS)
-* paper II "Representation of Celestial Coordinates in FITS" by
-* M. Calabretta & E.W. Greisen. If CarLin is non-zero, then these
-* conventions are ignored, and it is assumed that the mapping from pixel
-* coordinates to celestial coordinates is a simple linear transformation
-* (hence the attribute name "CarLin"). This is appropriate for some older
-* FITS data which claims to have a "CAR" projection, but which in fact do
-* not conform to the conventions of the FITS-WCS paper.
-*
-* The FITS-WCS paper specifies that headers which include a CAR projection
-* represent a linear mapping from pixel coordinates to "native spherical
-* coordinates", NOT celestial coordinates. An extra mapping is then
-* required from native spherical to celestial. This mapping is a 3D
-* rotation and so the overall Mapping from pixel to celestial coordinates
-* is NOT linear. See the FITS-WCS papers for further details.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,CarLin,carlin,-1)
-astMAKE_GET(FitsChan,CarLin,int,1,(this->carlin == -1 ? 0 : this->carlin))
-astMAKE_SET(FitsChan,CarLin,int,carlin,( value ? 1 : 0 ))
-astMAKE_TEST(FitsChan,CarLin,( this->carlin != -1 ))
-
-/* PolyTan */
-/* ======= */
-
-/*
-*att++
-* Name:
-* PolyTan
-
-* Purpose:
-* Use PVi_m keywords to define distorted TAN projection?
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer.
-
-* Description:
-* This attribute is a boolean value which specifies how FITS "TAN"
-* projections should be treated when reading a FrameSet from a foreign
-* encoded FITS header. If zero, the projection is assumed to conform
-* to the published FITS-WCS standard. If positive, the convention
-* for a distorted TAN projection included in an early draft version
-* of FITS-WCS paper II are assumed. In this convention the
-* coefficients of a polynomial distortion to be applied to
-* intermediate world coordinates are specified by the PVi_m keywords.
-* This convention was removed from the paper before publication and so
-* does not form part of the standard. Indeed, it is incompatible with
-* the published standard because it re-defines the meaning of the
-* first five PVi_m keywords on the longitude axis, which are reserved
-* by the published standard for other purposes. However, headers that
-* use this convention are still to be found, for instance the SCAMP
-* utility (http://www.astromatic.net/software/scamp) creates them.
-*
-* The default value for the PolyTan attribute is -1. A negative
-* values causes the used convention to depend on the contents
-* of the FitsChan. If the FitsChan contains any PVi_m keywords for
-* the latitude axis, or if it contains PVi_m keywords for the
-* longitude axis with "m" greater than 4, then the distorted TAN
-* convention is used. Otherwise, the standard convention is used.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,PolyTan,polytan,-INT_MAX)
-astMAKE_SET(FitsChan,PolyTan,int,polytan,value)
-astMAKE_TEST(FitsChan,PolyTan,( this->polytan != -INT_MAX ))
-astMAKE_GET(FitsChan,PolyTan,int,-1,(this->polytan == -INT_MAX ? -1 : this->polytan))
-
-/* Iwc */
-/* === */
-
-/*
-*att++
-* Name:
-* Iwc
-
-* Purpose:
-* Include a Frame representing FITS-WCS intermediate world coordinates?
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer (boolean).
-
-* Description:
-* This attribute is a boolean value which is used when a FrameSet is
-* read from a FitsChan with a foreign FITS encoding (e.g. FITS-WCS) using
-c astRead.
-f AST_READ.
-* If it has a non-zero value then the returned FrameSet will include
-* Frames representing "intermediate world coordinates" (IWC). These
-* Frames will have Domain name "IWC" for primary axis descriptions, and
-* "IWCa" for secondary axis descriptions, where "a" is replaced by
-* the single alternate axis description character, as used in the
-* FITS-WCS header. The default value for "Iwc" is zero.
-*
-* FITS-WCS paper 1 defines IWC as a Cartesian coordinate system with one
-* axis for each WCS axis, and is the coordinate system produced by the
-* rotation matrix (represented by FITS keyword PCi_j, CDi_j, etc).
-* For instance, for a 2-D FITS-WCS header describing projected
-* celestial longitude and latitude, the intermediate world
-* coordinates represent offsets in degrees from the reference point
-* within the plane of projection.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,Iwc,iwc,-1)
-astMAKE_GET(FitsChan,Iwc,int,1,(this->iwc == -1 ? 0 : this->iwc))
-astMAKE_SET(FitsChan,Iwc,int,iwc,( value ? 1 : 0 ))
-astMAKE_TEST(FitsChan,Iwc,( this->iwc != -1 ))
-
-/*
-*att++
-* Name:
-* CDMatrix
-
-* Purpose:
-* Use CDi_j keywords to represent pixel scaling, rotation, etc?
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer (boolean).
-
-* Description:
-* This attribute is a boolean value which specifies how the linear
-* transformation from pixel coordinates to intermediate world
-* coordinates should be represented within a FitsChan when using
-* FITS-WCS encoding. This transformation describes the scaling,
-* rotation, shear, etc., of the pixel axes.
-*
-* If the attribute has a non-zero value then the transformation is
-* represented by a set of CDi_j keywords representing a square matrix
-* (where "i" is the index of an intermediate world coordinate axis
-* and "j" is the index of a pixel axis). If the attribute has a zero
-* value the transformation is represented by a set of PCi_j keywords
-* (which also represent a square matrix) together with a corresponding
-* set of CDELTi keywords representing the axis scalings. See FITS-WCS
-* paper II "Representation of Celestial Coordinates in FITS" by
-* M. Calabretta & E.W. Greisen, for a complete description of these two
-* schemes.
-*
-* The default value of the CDMatrix attribute is determined by the
-* contents of the FitsChan at the time the attribute is accessed. If
-* the FitsChan contains any CDi_j keywords then the default value is
-* non-zero. Otherwise it is zero. Note, reading a FrameSet from a
-* FitsChan will in general consume any CDi_j keywords present in the
-* FitsChan. Thus the default value for CDMatrix following a read will
-* usually be zero, even if the FitsChan originally contained some
-* CDi_j keywords. This behaviour is similar to that of the Encoding
-* attribute, the default value for which is determined by the contents
-* of the FitsChan at the time the attribute is accessed. If you wish
-* to retain the original value of the CDMatrix attribute (that is,
-* the value before reading the FrameSet) then you should enquire the
-* default value before doing the read, and then set that value
-* explicitly.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,CDMatrix,cdmatrix,-1)
-astMAKE_SET(FitsChan,CDMatrix,int,cdmatrix,( value ? 1 : 0 ))
-astMAKE_TEST(FitsChan,CDMatrix,( this->cdmatrix != -1 ))
-
-/* Clean */
-/* ===== */
-
-/*
-*att++
-* Name:
-* Clean
-
-* Purpose:
-* Remove cards used whilst reading even if an error occurs?
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer (boolean).
-
-* Description:
-* This attribute indicates whether or not cards should be removed from
-* the FitsChan if an error occurs within
-c astRead.
-f AST_READ.
-* A succesful read on a FitsChan always results in the removal of
-* the cards which were involved in the description of the returned
-* Object. However, in the event of an error during the read (for instance
-* if the cards in the FitsChan have illegal values, or if some required
-* cards are missing) no cards will be removed from the FitsChan if
-* the Clean attribute is zero (the default). If Clean is non-zero then
-* any cards which were used in the aborted attempt to read an object
-* will be removed.
-*
-* This provides a means of "cleaning" a FitsChan of WCS related cards
-* which works even in the event of the cards not forming a legal WCS
-* description.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,Clean,clean,-1)
-astMAKE_SET(FitsChan,Clean,int,clean,( value ? 1 : 0 ))
-astMAKE_TEST(FitsChan,Clean,( this->clean != -1 ))
-
-/*
-*att++
-* Name:
-* FitsAxisOrder
-
-* Purpose:
-* Frame title.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* String.
-
-* Description:
-* This attribute specifies the order for the WCS axes in any new
-* FITS-WCS headers created using the
-c astWrite
-f AST_WRITE
-* method.
-*
-* The value of the FitsAxisOrder attribute can be either "<auto>"
-* (the default value), "<copy>" or a space-separated list of axis
-* symbols:
-*
-* "<auto>": causes the WCS axis order to be chosen automatically so that
-* the i'th WCS axis in the new FITS header is the WCS axis which is
-* more nearly parallel to the i'th pixel axis.
-*
-* "<copy>": causes the WCS axis order to be set so that the i'th WCS
-* axis in the new FITS header is the i'th WCS axis in the current
-* Frame of the FrameSet being written out to the header.
-*
-* "Sym1 Sym2...": the space-separated list is seached in turn for
-* the Symbol attribute of each axis in the current Frame of the
-* FrameSet. The order in which these Symbols occur within the
-* space-separated list defines the order of the WCS axes in the
-* new FITS header. An error is reported if Symbol for a current
-* Frame axis is not present in the supplied list. However, no error
-* is reported if the list contains extra words that do not correspond
-* to the Symbol of any current Frame axis.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,FitsAxisOrder,fitsaxisorder,astFree( this->fitsaxisorder ))
-astMAKE_GET(FitsChan,FitsAxisOrder,const char *,NULL,(this->fitsaxisorder ? this->fitsaxisorder : "<auto>" ))
-astMAKE_SET(FitsChan,FitsAxisOrder,const char *,fitsaxisorder,astStore( this->fitsaxisorder, value, strlen( value ) + (size_t) 1 ))
-astMAKE_TEST(FitsChan,FitsAxisOrder,( this->fitsaxisorder != NULL ))
-
-/* FitsDigits. */
-/* =========== */
-
-/*
-*att++
-* Name:
-* FitsDigits
-
-* Purpose:
-* Digits of precision for floating point FITS values.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer.
-
-* Description:
-* This attribute gives the number of significant decimal digits to
-* use when formatting floating point values for inclusion in the
-* FITS header cards within a FitsChan.
-*
-* By default, a positive value is used which results in no loss of
-c information, assuming that the value's precision is double.
-f information, assuming that the value is double precision.
-* Usually, this causes no problems.
-*
-* However, to adhere strictly to the recommendations of the FITS
-* standard, the width of the formatted value (including sign,
-* decimal point and exponent) ought not to be more than 20
-* characters. If you are concerned about this, you should set
-* FitsDigits to a negative value, such as -15. In this case, the
-* absolute value (+15) indicates the maximum number of significant
-* digits to use, but the actual number used may be fewer than this
-* to ensure that the FITS recommendations are satisfied. When
-* using this approach, the resulting number of significant digits
-* may depend on the value being formatted and on the presence of
-* any sign, decimal point or exponent.
-*
-* The value of this attribute is effective when FITS header cards
-* are output, either using
-c astFindFits or by the action of the FitsChan's sink function
-f AST_FINDFITS or by the action of the FitsChan's sink routine
-* when it is finally deleted.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-astMAKE_CLEAR(FitsChan,FitsDigits,fitsdigits,DBL_DIG)
-astMAKE_GET(FitsChan,FitsDigits,int,DBL_DIG,this->fitsdigits)
-astMAKE_SET(FitsChan,FitsDigits,int,fitsdigits,value)
-astMAKE_TEST(FitsChan,FitsDigits,( this->fitsdigits != DBL_DIG ))
-
-/* CardComm */
-/* ======== */
-
-/*
-*att++
-* Name:
-* CardComm
-
-* Purpose:
-* The comment for the current card in a FitsChan.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* String, read-only.
-
-* Description:
-* This attribute gives the comment for the current card of the
-* FitsChan. A zero-length string is returned if the card has no comment.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-
-/* CardName */
-/* ======== */
-
-/*
-*att++
-* Name:
-* CardName
-
-* Purpose:
-* The keyword name of the current card in a FitsChan.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* String, read-only.
-
-* Description:
-* This attribute gives the name of the keyword for the
-* current card of the FitsChan.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-
-/* CardType */
-/* ======== */
-
-/*
-*att++
-* Name:
-* CardType
-
-* Purpose:
-* The data type of the current card in a FitsChan.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer, read-only.
-
-* Description:
-* This attribute gives the data type of the keyword value for the
-* current card of the FitsChan. It will be one of the following
-* integer constants: AST__NOTYPE, AST__COMMENT, AST__INT, AST__FLOAT,
-* AST__STRING, AST__COMPLEXF, AST__COMPLEXI, AST__LOGICAL,
-* AST__CONTINUE, AST__UNDEF.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-
-/* Ncard */
-/* ===== */
-
-/*
-*att++
-* Name:
-* Ncard
-
-* Purpose:
-* Number of FITS header cards in a FitsChan.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer, read-only.
-
-* Description:
-* This attribute gives the total number of FITS header cards
-* stored in a FitsChan. It is updated as cards are added or
-* deleted.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-
-/* Nkey */
-/* ==== */
-
-/*
-*att++
-* Name:
-* Nkey
-
-* Purpose:
-* Number of unique FITS keywords in a FitsChan.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* Integer, read-only.
-
-* Description:
-* This attribute gives the total number of unique FITS keywords
-* stored in a FitsChan. It is updated as cards are added or
-* deleted. If no keyword occurrs more than once in the FitsChan, the
-* Ncard and Nkey attributes will be equal. If any keyword occurrs
-* more than once, the Nkey attribute value will be smaller than
-* the Ncard attribute value.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-
-/* Warnings. */
-/* ======== */
-
-/*
-*att++
-* Name:
-* Warnings
-
-* Purpose:
-* Controls the issuing of warnings about various conditions.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* String
-
-* Description:
-* This attribute controls the issuing of warnings about selected
-* conditions when an Object or keyword is read from or written to a
-* FitsChan. The value supplied for the Warnings attribute should
-* consist of a space separated list of condition names (see the
-* AllWarnings attribute for a list of the currently defined names).
-* Each name indicates a condition which should be reported. The default
-* value for Warnings is the string "BadKeyName BadKeyValue Tnx Zpx
-* BadCel BadMat BadPV BadCTYPE".
-*
-* The text of any warning will be stored within the FitsChan in the
-* form of one or more new header cards with keyword ASTWARN. If
-* required, applications can check the FitsChan for ASTWARN cards
-c (using astFindFits) after the call to astRead or astWrite has been
-f (using AST_FINDFITS) after the call to AST_READ or AST_WRITE has been
-* performed, and report the text of any such cards to the user. ASTWARN
-* cards will be propagated to any output header unless they are
-c deleted from the FitsChan using astDelFits.
-f deleted from the FitsChan using astDelFits.
-
-* Notes:
-* This attribute only controls the warnings that are to be stored as
-* a set of header cards in the FitsChan as described above. It has no
-* effect on the storage of warnings in the parent Channel structure.
-* All warnings are stored in the parent Channel structure, from where
-* they can be retrieved using the
-c astWarnings
-f AST_WARNINGS
-* function.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-
-/* Clear the Warnings value by freeing the allocated memory and assigning
- a NULL pointer. */
-astMAKE_CLEAR(FitsChan,Warnings,warnings,astFree( this->warnings ))
-
-/* If the Warnings value is not set, supply a default in the form of a
- pointer to the constant string "BadKeyName BadKeyValue Tnx Zpx BadCel BadMat BadCTYPE". */
-astMAKE_GET(FitsChan,Warnings,const char *,NULL,( this->warnings ? this->warnings :
- "BadKeyName BadKeyValue Tnx Zpx BadPV BadCel BadMat BadCTYPE" ))
-
-/* Set a Warnings value by freeing any previously allocated memory, allocating
- new memory, storing the string and saving the pointer to the copy.
- First check that the list does not contain any unknown conditions. If
- it does, an error is reported by GoodWarns and the current attribute value
- is retained. */
-astMAKE_SET(FitsChan,Warnings,const char *,warnings,( GoodWarns( value, status ) ?
- astStore( this->warnings, value, strlen( value ) + (size_t) 1 ) :
- this->warnings))
-
-/* The Warnings value is set if the pointer to it is not NULL. */
-astMAKE_TEST(FitsChan,Warnings,( this->warnings != NULL ))
-
-/* AllWarnings. */
-/* ============ */
-
-/*
-*att++
-* Name:
-* AllWarnings
-
-* Purpose:
-* A list of all currently available condition names.
-
-* Type:
-* Public attribute.
-
-* Synopsis:
-* String, read-only
-
-* Description:
-* This read-only attribute is a space separated list of all the conditions
-* names recognized by the Warnings attribute. The names are listed
-* below.
-
-* Conditions:
-* The following conditions are currently recognised (all are
-* case-insensitive):
-*
-* - "BadCel": This condition arises when reading a FrameSet from a
-* non-Native encoded FitsChan if an unknown celestial co-ordinate
-* system is specified by the CTYPE keywords.
-*
-* - "BadCTYPE": This condition arises when reading a FrameSet from a
-* non-Native encoded FitsChan if an illegal algorithm code is specified
-* by a CTYPE keyword, and the illegal code can be converted to an
-* equivalent legal code.
-*
-* - "BadKeyName": This condition arises if a FITS keyword name is
-* encountered that contains an illegal character (i.e. one not allowed
-* by the FITS standard).
-*
-* - "BadKeyValue": This condition arises if the value of a FITS keyword
-* cannot be determined from the content of the header card.
-*
-* - "BadLat": This condition arises when reading a FrameSet from a
-* non-Native encoded FitsChan if the latitude of the reference point
-* has an absolute value greater than 90 degrees. The actual absolute
-* value used is set to exactly 90 degrees in these cases.
-*
-* - "BadMat": This condition arises if the matrix describing the
-* transformation from pixel offsets to intermediate world coordinates
-* cannot be inverted. This matrix describes the scaling, rotation, shear,
-* etc., applied to the pixel axes, and is specified by keywords such as
-* PCi_j, CDi_j, CROTA, etc. For example, the matrix will not be invertable
-* if any rows or columns consist entirely of zeros. The FITS-WCS Paper I
-* "Representation of World Coordinates in FITS" by Greisen & Calabretta
-* requires that this matrix be invertable. Many operations (such as
-* grid plotting) will not be possible if the matrix cannot be inverted.
-*
-* - "BadPV": This condition arises when reading a FrameSet from a
-* non-Native encoded FitsChan. It is issued if a PVi_m header is found
-* that refers to a projection parameter that is not used by the
-* projection type specified by CTYPE, or the PV values are otherwise
-* inappropriate for the projection type.
-*
-* - "BadVal": This condition arises when reading a FrameSet from a
-* non-Native encoded FitsChan if it is not possible to convert the
-* value of a FITS keywords to the expected type. For instance, this
-* can occur if the FITS header contains a string value for a keyword
-* which should have a floating point value, or if the keyword has no
-* value at all (i.e. is a comment card).
-*
-* - "Distortion": This condition arises when reading a FrameSet from a
-* non-Native encoded FitsChan if any of the CTYPE keywords specify an
-* unsupported distortion code using the "4-3-3" format specified in
-* FITS-WCS paper IV. Such distortion codes are ignored.
-*
-* - "NoCTYPE": This condition arises if a default CTYPE value is used
-c within astRead, due to no value being present in the supplied FitsChan.
-f within AST_READ, due to no value being present in the supplied FitsChan.
-* This condition is only tested for when using non-Native encodings.
-*
-* - "NoEquinox": This condition arises if a default equinox value is used
-c within astRead, due to no value being present in the supplied FitsChan.
-f within AST_READ, due to no value being present in the supplied FitsChan.
-* This condition is only tested for when using non-Native encodings.
-*
-* - "NoRadesys": This condition arises if a default reference frame is
-c used for an equatorial co-ordinate system within astRead, due to no
-f used for an equatorial co-ordinate system within AST_READ, due to no
-* value being present in the supplied FitsChan. This condition is only
-* tested for when using non-Native encodings.
-*
-* - "NoLonpole": This condition arises if a default value is used for
-c the LONPOLE keyword within astRead, due to no value being present
-f the LONPOLE keyword within AST_READ, due to no value being present
-* in the supplied FitsChan. This condition is only tested for when
-* using non-Native encodings.
-*
-* - "NoLatpole": This condition arises if a default value is used for
-c the LATPOLE keyword within astRead, due to no value being present
-f the LATPOLE keyword within AST_READ, due to no value being present
-* in the supplied FitsChan. This condition is only tested for when
-* using non-Native encodings.
-*
-* - "NoMjd-obs": This condition arises if a default value is used for
-c the date of observation within astRead, due to no value being present
-f the date of observation within AST_READ, due to no value being present
-* in the supplied FitsChan. This condition is only tested for when using
-* non-Native encodings.
-*
-* - "Tnx": This condition arises if a FrameSet is read from a FITS
-* header containing an IRAF "TNX" projection which includes terms
-* not supproted by AST. Such terms are ignored and so the resulting
-* FrameSet may be inaccurate.
-*
-* - "Zpx": This condition arises if a FrameSet is read from a FITS
-* header containing an IRAF "ZPX" projection which includes "lngcor"
-* or "latcor" correction terms. These terms are not supported by AST
-* and are ignored. The resulting FrameSet may therefore be inaccurate.
-
-* Applicability:
-* FitsChan
-* All FitsChans have this attribute.
-*att--
-*/
-
-/* Copy constructor. */
-/* ----------------- */
-
-static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
-/*
-* Name:
-* Copy
-
-* Purpose:
-* Copy constructor for FitsChan objects.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void Copy( const AstObject *objin, AstObject *objout, int *status )
-
-* Description:
-* This function implements the copy constructor for FitsChan objects.
-
-* Parameters:
-* objin
-* Pointer to the FitsChan to be copied.
-* objout
-* Pointer to the FitsChan being constructed.
-* status
-* Pointer to the inherited status variable.
-
-* Notes:
-* - The source and sink functions are not propagated (i.e. the
-* pointers are set NULL in the output FitsChan).
-* - This constructor makes a deep copy, including a copy of the
-* keyword values.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- const char *class; /* Pointer to object class */
- AstFitsChan *in; /* Pointer to input FitsChan */
- AstFitsChan *out; /* Pointer to output FitsChan */
- int *flags;
- int icard;
- int old_ignore_used; /* Original value of external variable ignore_used */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(objin);
-
-/* Obtain pointers to the input and output FitsChans. */
- in = (AstFitsChan *) objin;
- out = (AstFitsChan *) objout;
-
-/* Nullify all pointers in the output FitsChan so that the input
- data will not be deleted in the event of an error occurring. */
- out->card = NULL;
- out->head = NULL;
- out->keyseq = NULL;
- out->keywords = NULL;
- out->source = NULL;
- out->saved_source = NULL;
- out->source_wrap = NULL;
- out->sink = NULL;
- out->sink_wrap = NULL;
- out->warnings = NULL;
- out->tabsource = NULL;
- out->tabsource_wrap = NULL;
-
-/* Store the object class. */
- class = astGetClass( in );
-
-/* Ensure all cards are copied, including those already read by astRead. */
- old_ignore_used = ignore_used;
- ignore_used = 0;
-
-/* Save the current card index in the input FitsChan. */
- icard = astGetCard( in );
-
-/* Rewind the input FitsChan. */
- astClearCard( in );
-
-/* Copy all the FitsCard structures from input to output. */
- while( !astFitsEof( in ) && astOK ){
-
-/* Get a pointer to the flags mask for this card. */
- flags = CardFlags( in, status );
-
-/* Store a new card in the output, holding the same information as the
- input card. */
- NewCard( out, CardName( in, status ), CardType( in, status ), CardData( in, NULL, status ),
- CardComm( in, status ), (flags?(*flags):0), status );
-
-/* Move on to the next input card. */
- MoveCard( in, 1, "astCopy", class, status );
- }
-
-/* Set the current card in both input and output to the current input
- card on entry. */
- astSetCard( in, icard );
- astSetCard( out, icard );
-
-/* Copy the list of keyword sequence numbers used. */
- if( in->keyseq ) out->keyseq = astCopy( in->keyseq );
-
-/* Copy the Warnings attribute value */
- if( in->warnings ) out->warnings = astStore( NULL, in->warnings,
- strlen( in->warnings ) + 1 );
-
-/* Copy any tables currently in the FitsChan structure. */
- if( in->tables ) out->tables = astCopy( in->tables );
-
-/* Reinstate the original setting of the external ignore_used variable. */
- ignore_used = old_ignore_used;
-
-/* If an error occurred, delete the contents of the output Object. */
- if( !astOK ) Delete( objout, status );
-}
-
-/* Destructor. */
-/* ----------- */
-
-static void Delete( AstObject *obj, int *status ) {
-/*
-* Name:
-* Delete
-
-* Purpose:
-* Destructor for FitsChan objects.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* void Delete( AstObject *obj, int *status )
-
-* Description:
-* This function implements the destructor for FitsChan objects.
-
-* Parameters:
-* obj
-* Pointer to the FitsChan 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: */
- AstFitsChan *this; /* Pointer to FitsChan */
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) obj;
-
-/* Write out the contents of the FitsChan using the sink function
- provided when it was created. */
- WriteToSink( this, status );
-
-/* Remove all cards from the FitsChan. */
- EmptyFits( this, status );
-}
-
-/* Dump function. */
-/* -------------- */
-
-static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
-/*
-* Name:
-* Dump
-
-* Purpose:
-* Dump function for FitsChan 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 FitsChan class to an output Channel.
-
-* Parameters:
-* this
-* Pointer to the FitsChan whose data are being written.
-* channel
-* Pointer to the Channel to which the data are being written.
-* status
-* Pointer to the inherited status variable.
-*/
-#define KEY_LEN 50 /* Maximum length of a keyword */
-
-/* Local Variables: */
- AstFitsChan *this; /* Pointer to the FitsChan structure */
- astDECLARE_GLOBALS /* Declare the thread specific global data */
- char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */
- const char *class; /* Object class */
- const char *sval; /* Pointer to string value */
- int cardtype; /* Keyword data type */
- int flags; /* Keyword flags */
- int icard; /* Index of current card */
- int ival; /* Integer value */
- int ncard; /* No. of cards dumped so far */
- int old_ignore_used; /* Original value of external variable ignore_used */
- int set; /* Attribute value set? */
- void *data; /* Pointer to keyword data value */
-
-/* Check the global error status. */
- if ( !astOK ) return;
-
-/* Get a pointer to the structure holding thread-specific global data. */
- astGET_GLOBALS(this_object);
-
-/* Obtain a pointer to the FitsChan structure. */
- this = (AstFitsChan *) this_object;
-
-/* Store the object class. */
- class = astGetClass( this );
-
-/* Save the index of ht ecurrent card. */
- icard = astGetCard( this );
-
-/* Write out values representing the instance variables for the
- FitsChan class. Accompany these with appropriate comment strings,
- possibly depending on the values being written.*/
-
-/* Card. */
-/* ----- */
- astWriteInt( channel, "Card", 1, 1, icard, "Index of current card" );
-
-/* Encoding. */
-/* --------- */
- set = TestEncoding( this, status );
- ival = set ? GetEncoding( this, status ) : astGetEncoding( this );
- if( ival > UNKNOWN_ENCODING && ival <= MAX_ENCODING ) {
- astWriteString( channel, "Encod", set, 1, xencod[ival], "Encoding system" );
- } else {
- astWriteString( channel, "Encod", set, 1, UNKNOWN_STRING, "Encoding system" );
- }
-
-/* FitsAxisOrder. */
-/* -------------- */
- set = TestFitsAxisOrder( this, status );
- sval = set ? GetFitsAxisOrder( this, status ) : astGetFitsAxisOrder( this );
- astWriteString( channel, "FAxOrd", set, 1, sval,
- "Order of WCS axes in new FITS headers" );
-
-/* FitsDigits. */
-/* ----------- */
- set = TestFitsDigits( this, status );
- ival = set ? GetFitsDigits( this, status ) : astGetFitsDigits( this );
- astWriteInt( channel, "FitsDg", set, 1, ival, "No. of digits for floating point values" );
-
-/* DefB1950 */
-/* -------- */
- set = TestDefB1950( this, status );
- ival = set ? GetDefB1950( this, status ) : astGetDefB1950( this );
- astWriteInt( channel, "DfB1950", set, 1, ival, (ival ? "Default to FK4 B1950": "Default to ICRS") );
-
-/* TabOK */
-/* ----- */
- set = TestTabOK( this, status );
- ival = set ? GetTabOK( this, status ) : astGetTabOK( this );
- astWriteInt( channel, "TabOK", set, 1, ival, ( ival > 0 ? "EXTVER value for -TAB headers": "Do not support -TAB CTYPE codes") );
-
-/* CDMatrix */
-/* -------- */
- set = TestCDMatrix( this, status );
- ival = set ? GetCDMatrix( this, status ) : astGetCDMatrix( this );
- astWriteInt( channel, "CdMat", set, 1, ival, (ival ? "Use CD Matrix":"Use PC matrix") );
-
-/* CarLin */
-/* ------ */
- set = TestCarLin( this, status );
- ival = set ? GetCarLin( this, status ) : astGetCarLin( this );
- astWriteInt( channel, "CarLin", set, 1, ival, (ival ? "Use simple linear CAR projections": "Use full FITS-WCS CAR projections") );
-
-/* PolyTan */
-/* ------- */
- set = TestPolyTan( this, status );
- ival = set ? GetPolyTan( this, status ) : astGetPolyTan( this );
- astWriteInt( channel, "PolyTan", set, 0, ival, (ival ? "Use distorted TAN convention": "Use standard TAN convention") );
-
-/* Iwc */
-/* --- */
- set = TestIwc( this, status );
- ival = set ? GetIwc( this, status ) : astGetIwc( this );
- astWriteInt( channel, "Iwc", set, 1, ival, (ival ? "Include an IWC Frame": "Do not include an IWC Frame") );
-
-/* Clean */
-/* ----- */
- set = TestClean( this, status );
- ival = set ? GetClean( this, status ) : astGetClean( this );
- astWriteInt( channel, "Clean", set, 0, ival, "Always remove used cards?" );
-
-/* Warnings. */
-/* --------- */
- set = TestWarnings( this, status );
- sval = set ? GetWarnings( this, status ) : astGetWarnings( this );
- astWriteString( channel, "Warn", set, 1, sval, "Warnings to be reported" );
-
-/* Now do instance variables which are not attributes. */
-/* =================================================== */
-
-/* Ensure all cards are copied, including those already read by astRead. */
- old_ignore_used = ignore_used;
- ignore_used = 0;
-
-/* Rewind the FitsChan. */
- astClearCard( this );
-
-/* Dump each card. */
- ncard = 1;
- while( !astFitsEof( this ) && astOK ){
-
-/* Write out the keyword name. */
- if( CardName( this, status ) ){
- (void) sprintf( buff, "Nm%d", ncard );
- astWriteString( channel, buff, 1, 1, CardName( this, status ),
- "FITS keyword name" );
- }
-
-/* Write out the keyword type. */
- cardtype = CardType( this, status );
- (void) sprintf( buff, "Ty%d", ncard );
- astWriteString( channel, buff, 1, 1, type_names[ cardtype ],
- "FITS keyword data type" );
-
-/* Write out the flag values if any are non-zero. */
- flags = *CardFlags( this, status );
- if( flags ){
- (void) sprintf( buff, "Fl%d", ncard );
- astWriteInt( channel, buff, 1, 1, flags, "FITS keyword flags" );
- }
-
-/* Write out the data value, if defined, using the appropriate data type. */
- data = CardData( this, NULL, status );
- if( data && cardtype != AST__UNDEF ){
- if( cardtype == AST__FLOAT ){
- (void) sprintf( buff, "Dt%d", ncard );
- astWriteDouble( channel, buff, 1, 1, *( (double *) data ),
- "FITS keyword value" );
- } else if( cardtype == AST__STRING || cardtype == AST__CONTINUE ){
- (void) sprintf( buff, "Dt%d", ncard );
- astWriteString( channel, buff, 1, 1, (char *) data,
- "FITS keyword value" );
- } else if( cardtype == AST__INT ){
- (void) sprintf( buff, "Dt%d", ncard );
- astWriteInt( channel, buff, 1, 1, *( (int *) data ),
- "FITS keyword value" );
- } else if( cardtype == AST__LOGICAL ){
- (void) sprintf( buff, "Dt%d", ncard );
- astWriteInt( channel, buff, 1, 1, *( (int *) data ),
- "FITS keyword value" );
- } else if( cardtype == AST__COMPLEXF ){
- (void) sprintf( buff, "Dr%d", ncard );
- astWriteDouble( channel, buff, 1, 1, *( (double *) data ),
- "FITS keyword real value" );
- (void) sprintf( buff, "Di%d", ncard );
- astWriteDouble( channel, buff, 1, 1, *( ( (double *) data ) + 1 ),
- "FITS keyword imaginary value" );
- } else if( cardtype == AST__COMPLEXI ){
- (void) sprintf( buff, "Dr%d", ncard );
- astWriteInt( channel, buff, 1, 1, *( (int *) data ),
- "FITS keyword real value" );
- (void) sprintf( buff, "Di%d", ncard );
- astWriteInt( channel, buff, 1, 1, *( ( (int *) data ) + 1 ),
- "FITS keyword imaginary value" );
- }
- }
-
-/* Write out the keyword comment. */
- if( CardComm( this, status ) ){
- (void) sprintf( buff, "Cm%d", ncard );
- astWriteString( channel, buff, 1, 1, CardComm( this, status ),
- "FITS keyword comment" );
- }
-
-/* Move on to the next card. */
- ncard++;
- MoveCard( this, 1, "astDump", class, status );
- }
-
-/* Dump any FitTables. */
- if( this->tables ) {
- astWriteObject( channel, "Tables", 1, 1, this->tables,
- "A KeyMap holding associated binary tables" );
- }
-
-/* Reinstate the original setting of the external ignore_used variable. */
- ignore_used = old_ignore_used;
-
-/* Reinstate the original current card. */
- astSetCard( this, icard );
-#undef KEY_LEN
-}
-
-/* Standard class functions. */
-/* ========================= */
-
-/* Implement the astIsAFitsChan and astCheckFitsChan functions using the macros
- defined for this purpose in the "object.h" header file. */
-astMAKE_ISA(FitsChan,Channel)
-astMAKE_CHECK(FitsChan)
-AstFitsChan *astFitsChan_( const char *(* source)( void ),
- void (* sink)( const char * ),
- const char *options, int *status, ...) {
-
-/*
-*++
-* Name:
-c astFitsChan
-f AST_FITSCHAN
-
-* Purpose:
-* Create a FitsChan.
-
-* Type:
-* Public function.
-
-* Synopsis:
-c #include "fitschan.h"
-c AstFitsChan *astFitsChan( const char *(* source)( void ),
-c void (* sink)( const char * ),
-c const char *options, ... )
-f RESULT = AST_FITSCHAN( SOURCE, SINK, OPTIONS, STATUS )
-
-* Class Membership:
-* FitsChan constructor.
-
-* Description:
-* This function creates a new FitsChan and optionally initialises
-* its attributes.
-*
-* A FitsChan is a specialised form of Channel which supports I/O
-* operations involving the use of FITS (Flexible Image Transport
-* System) header cards. Writing an Object to a FitsChan (using
-c astWrite) will, if the Object is suitable, generate a
-f AST_WRITE) will, if the Object is suitable, generate a
-* description of that Object composed of FITS header cards, and
-* reading from a FitsChan will create a new Object from its FITS
-* header card description.
-*
-* While a FitsChan is active, it represents a buffer which may
-* contain zero or more 80-character "header cards" conforming to
-* FITS conventions. Any sequence of FITS-conforming header cards
-* may be stored, apart from the "END" card whose existence is
-* merely implied. The cards may be accessed in any order by using
-* the FitsChan's integer Card attribute, which identifies a "current"
-* card, to which subsequent operations apply. Searches
-c based on keyword may be performed (using astFindFits), new
-c cards may be inserted (astPutFits, astPutCards, astSetFits<X>) and
-c existing ones may be deleted (astDelFits) or changed (astSetFits<X>).
-f based on keyword may be performed (using AST_FINDFITS), new
-f cards may be inserted (AST_PUTFITS, AST_PUTCARDS, AST_SETFITS<X>) and
-f existing ones may be deleted (AST_DELFITS) or changed (AST_SETFITS<X>).
-*
-* When you create a FitsChan, you have the option of specifying
-* "source" and "sink" functions which connect it to external data
-* stores by reading and writing FITS header cards. If you provide
-* a source function, it is used to fill the FitsChan with header cards
-* when it is accessed for the first time. If you do not provide a
-* source function, the FitsChan remains empty until you explicitly enter
-c data into it (e.g. using astPutFits, astPutCards, astWrite
-f data into it (e.g. using AST_PUTFITS, AST_PUTCARDS, AST_WRITE
-* or by using the SourceFile attribute to specifying a text file from
-* which headers should be read). When the FitsChan is deleted, any
-* remaining header cards in the FitsChan can be saved in either of
-* two ways: 1) by specifying a value for the SinkFile attribute (the
-* name of a text file to which header cards should be written), or 2)
-* by providing a sink function (used to to deliver header cards to an
-* external data store). If you do not provide a sink function or a
-* value for SinkFile, any header cards remaining when the FitsChan
-* is deleted will be lost, so you should arrange to extract them
-* first if necessary
-c (e.g. using astFindFits or astRead).
-f (e.g. using AST_FINDFITS or AST_READ).
-*
-* Coordinate system information may be described using FITS header
-* cards using several different conventions, termed
-* "encodings". When an AST Object is written to (or read from) a
-* FitsChan, the value of the FitsChan's Encoding attribute
-* determines how the Object is converted to (or from) a
-* description involving FITS header cards. In general, different
-* encodings will result in different sets of header cards to
-* describe the same Object. Examples of encodings include the DSS
-* encoding (based on conventions used by the STScI Digitised Sky
-* Survey data), the FITS-WCS encoding (based on a proposed FITS
-* standard) and the NATIVE encoding (a near loss-less way of
-* storing AST Objects in FITS headers).
-*
-* The available encodings differ in the range of Objects they can
-* represent, in the number of Object descriptions that can coexist
-* in the same FitsChan, and in their accessibility to other
-* (external) astronomy applications (see the Encoding attribute
-* for details). Encodings are not necessarily mutually exclusive
-* and it may sometimes be possible to describe the same Object in
-* several ways within a particular set of FITS header cards by
-* using several different encodings.
-*
-c The detailed behaviour of astRead and astWrite, when used with
-f The detailed behaviour of AST_READ and AST_WRITE, when used with
-* a FitsChan, depends on the encoding in use. In general, however,
-c all use of astRead is destructive, so that FITS header cards
-f all use of AST_READ is destructive, so that FITS header cards
-* are consumed in the process of reading an Object, and are
-* removed from the FitsChan (this deletion can be prevented for
-* specific cards by calling the
-c astRetainFits function).
-f AST_RETAINFITS routine).
-*
-* If the encoding in use allows only a single Object description
-* to be stored in a FitsChan (e.g. the DSS, FITS-WCS and FITS-IRAF
-c encodings), then write operations using astWrite will
-f encodings), then write operations using AST_WRITE will
-* over-write any existing Object description using that
-* encoding. Otherwise (e.g. the NATIVE encoding), multiple Object
-* descriptions are written sequentially and may later be read
-* back in the same sequence.
-
-* Parameters:
-c source
-f SOURCE = FUNCTION (Given)
-c Pointer to a source function which takes no arguments and
-c returns a pointer to a null-terminated string. This function
-c will be used by the FitsChan to obtain input FITS header
-c cards. On each invocation, it should read the next input card
-c from some external source (such as a FITS file), and return a
-c pointer to the (null-terminated) contents of the card. It
-c should return a NULL pointer when there are no more cards to
-c be read.
-c
-c If "source" is NULL, the FitsChan will remain empty until
-c cards are explicitly stored in it (e.g. using astPutCards,
-c astPutFits or via the SourceFile attribute).
-f A source routine, which is a function taking two arguments: a
-f character argument of length 80 to contain a FITS card, and an
-f integer error status argument. It should return an integer value.
-f This function will be used by the FitsChan to obtain input
-f FITS header cards. On each invocation, it should read the
-f next input card from some external source (such as a FITS
-f file), and return the contents of the card via its character
-f argument. It should return a function result of one unless
-f there are no more cards to be read, in which case it should
-f return zero. If an error occurs, it should set its error
-f status argument to an error value before returning.
-f
-f If the null routine AST_NULL is supplied as the SOURCE value,
-f the FitsChan will remain empty until cards are explicitly
-f stored in it (e.g. using AST_PUTCARDS, AST_PUTFITS or via the
-f SourceFile attribute).
-c sink
-f SINK = SUBROUTINE (Given)
-c Pointer to a sink function that takes a pointer to a
-c null-terminated string as an argument and returns void. If
-c no value has been set for the SinkFile attribute, this
-c function will be used by the FitsChan to deliver any FITS
-c header cards it contains when it is finally deleted. On
-c each invocation, it should deliver the contents of the character
-c string passed to it as a FITS header card to some external
-c data store (such as a FITS file).
-f A sink routine, which is a subroutine which takes two
-f arguments: a character argument of length 80 to contain a
-f FITS card, and an integer error status argument. If no
-f value has been set for the SinkFile attribute, this routine
-f will be used by the FitsChan to deliver any FITS header cards
-f it contains when it is finally deleted. On each invocation,
-f it should deliver the contents of the character string passed
-f to it as a FITS header card to some external data store (such
-f as a FITS file). If an error occurs, it should set its error
-f status argument to an error value before returning.
-*
-c If "sink" is NULL,
-f If the null routine AST_NULL is supplied as the SINK value,
-* and no value has been set for the SinkFile attribute, the
-* contents of the FitsChan will be lost when it is deleted.
-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 FitsChan. 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.
-f A character string containing an optional comma-separated
-f list of attribute assignments to be used for initialising the
-f new FitsChan. The syntax used is identical to that for the
-f AST_SET routine.
-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).
-*
-* Note, the FITSCHAN_OPTIONS environment variable may be used
-* to specify default options for all newly created FitsChans.
-f STATUS = INTEGER (Given and Returned)
-f The global status.
-
-* Returned Value:
-c astFitsChan()
-f AST_FITSCHAN = INTEGER
-* A pointer to the new FitsChan.
-
-* Notes:
-f - The names of the routines supplied for the SOURCE and SINK
-f arguments should appear in EXTERNAL statements in the Fortran
-f routine which invokes AST_FITSCHAN. However, this is not generally
-f necessary for the null routine AST_NULL (so long as the AST_PAR
-f include file has been used).
-c - No FITS "END" card will be written via the sink function. You
-f - No FITS "END" card will be written via the sink routine. You
-* should add this card yourself after the FitsChan has been
-* deleted.
-* - A null Object pointer (AST__NULL) will be returned if this
-* function is invoked with the AST error status set, or if it
-* should fail for any reason.
-f - Note that the null routine AST_NULL (one underscore) is
-f different to AST__NULL (two underscores), which is the null Object
-f pointer.
-
-* Status Handling:
-* The protected interface to this function includes an extra
-* parameter at the end of the parameter list descirbed above. This
-* parameter is a pointer to the integer inherited status
-* variable: "int *status".
-*--
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstFitsChan *new; /* Pointer to new FitsChan */
- 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 FitsChan, allocating memory and initialising the
- virtual function table as well if necessary. This interface is for
- use by other C functions within AST, and uses the standard "wrapper"
- functions included in this class. */
- new = astInitFitsChan( NULL, sizeof( AstFitsChan ), !class_init,
- &class_vtab, "FitsChan", source, SourceWrap,
- sink, SinkWrap );
-
-/* If successful, note that the virtual function table has been
- initialised. */
- if ( astOK ) {
- class_init = 1;
-
-/* Apply any default options specified by "<class>_OPTIONS" environment
- variable. */
- astEnvSet( new );
-
-/* Obtain the variable argument list and pass it along with the
- options string to the astVSet method to initialise the new
- FitsChan's attributes. */
- va_start( args, status );
- astVSet( new, options, NULL, args );
- va_end( args );
-
-/* If an error occurred, clean up by deleting the new object. */
- if ( !astOK ) new = astDelete( new );
- }
-
-/* Return a pointer to the new FitsChan. */
- return new;
-}
-
-AstFitsChan *astFitsChanId_( const char *(* source)( void ),
- void (* sink)( const char * ),
- const char *options, ... ) {
-
-/*
-* Name:
-* astFitsChanId_
-
-* Purpose:
-* Create a FitsChan.
-
-* Type:
-* Private function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstFitsChan *astFitsChanId_( const char *(* source)( void ),
-* void (* sink)( const char * ),
-* const char *options, ... )
-
-* Class Membership:
-* FitsChan constructor.
-
-* Description:
-* This function implements the external (public) C interface to the
-* astFitsChan constructor function. Another function (astFitsChanForId)
-* should be called to create a FitsChan for use within other languages.
-* Both functions return an ID value (instead of a true C pointer) to
-* external users, and must be provided because astFitsChan_ 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 astFitsChan_ 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.
-
-* Parameters:
-* As for astFitsChan_.
-
-* Returned Value:
-* The ID value associated with the new FitsChan.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstFitsChan *new; /* Pointer to new FitsChan */
- va_list args; /* Variable argument list */
- int *status; /* Pointer to inherited status value */
-
-/* Get a pointer to the inherited status value. */
- status = astGetStatusPtr;
-
-/* Get a pointer to the thread specific global data structure. */
- astGET_GLOBALS(NULL);
-
-/* Check the global status. */
- if ( !astOK ) return NULL;
-
-/* Initialise the FitsChan, allocating memory and initialising the
- virtual function table as well if necessary. This interface is for
- use by external C functions and uses the standard "wrapper"
- functions included in this class. */
- new = astInitFitsChan( NULL, sizeof( AstFitsChan ), !class_init,
- &class_vtab, "FitsChan", source, SourceWrap,
- sink, SinkWrap );
-
-/* If successful, note that the virtual function table has been
- initialised. */
- if ( astOK ) {
- class_init = 1;
-
-/* Apply any default options specified by "<class>_OPTIONS" environment
- variable. */
- astEnvSet( new );
-
-/* Obtain the variable argument list and pass it along with the
- options string to the astVSet method to initialise the new
- FitsChan's attributes. */
- va_start( args, options );
- astVSet( new, options, NULL, args );
- va_end( args );
-
-/* If an error occurred, clean up by deleting the new object. */
- if ( !astOK ) new = astDelete( new );
- }
-
-/* Return an ID value for the new FitsChan. */
- return astMakeId( new );
-}
-
-AstFitsChan *astFitsChanForId_( const char *(* source)( void ),
- char *(* source_wrap)( const char *(*)( void ), int * ),
- void (* sink)( const char * ),
- void (* sink_wrap)( void (*)( const char * ),
- const char *, int * ),
- const char *options, ... ) {
-
-/*
-*+
-* Name:
-* astFitsChanFor
-
-* Purpose:
-* Initialise a FitsChan from a foreign language interface.
-
-* Type:
-* Public function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstFitsChan *astFitsChanFor( const char *(* source)( void ),
-* char *(* source_wrap)( const char *(*)
-* ( void ), int * ),
-* void (* sink)( const char * ),
-* void (* sink_wrap)( void (*)( const char * ),
-* const char *, int * ),
-* const char *options, ... )
-
-* Class Membership:
-* FitsChan constructor.
-
-* Description:
-* This function creates a new FitsChan from a foreign language
-* interface and optionally initialises its attributes.
-*
-* A FitsChan implements FITS input/output for the AST library.
-* Writing an Object to a FitsChan (using astWrite) will generate a
-* textual representation of that Object in terms of FITS header cards,
-* and reading from a FitsChan (using astRead) will create a new Object
-* from its FITS representation.
-*
-* Normally, when you use a FitsChan, you should provide "source"
-* and "sink" functions which connect it to an external data store
-* by reading and writing the resulting text. This function also
-* requires you to provide "wrapper" functions which will invoke
-* the source and sink functions.
-
-* Parameters:
-* source
-* Pointer to a "source" function which will be used to obtain
-* FITS header cards. Generally, this will be obtained by
-* casting a pointer to a source function which is compatible
-* with the "source_wrap" wrapper function (below). The pointer
-* should later be cast back to its original type by the
-* "source_wrap" function before the function is invoked.
-*
-* If "source" is NULL, the FitsChan will remain empty until
-* cards are added explicitly (e.g. using astPutCards or astPutFits).
-* source_wrap
-* Pointer to a function which can be used to invoke the
-* "source" function supplied (above). This wrapper function is
-* necessary in order to hide variations in the nature of the
-* source function, such as may arise when it is supplied by a
-* foreign (non-C) language interface.
-*
-* The single parameter of the "source_wrap" function is a
-* pointer to the "source" function, and it should cast this
-* function pointer (as necessary) and invoke the function with
-* appropriate arguments to obtain the next FITS header card.
-* The "source_wrap" function should then return a pointer
-* to a dynamically allocated, null terminated string containing
-* the text that was read. The string will be freed (using
-* astFree) when no longer required and the "source_wrap"
-* function need not concern itself with this. A NULL pointer
-* should be returned if there is no more input to read.
-*
-* If "source" is NULL, the FitsChan will remain empty until
-* cards are added explicitly (e.g. using astPutCards or astPutFits).
-* sink
-* Pointer to a "sink" function which will be used to deliver
-* FITS header cards. Generally, this will be obtained by
-* casting a pointer to a sink function which is compatible with
-* the "sink_wrap" wrapper function (below). The pointer should
-* later be cast back to its original type by the "sink_wrap"
-* function before the function is invoked.
-*
-* If "sink" is NULL, the contents of the FitsChan will not be
-* written out before being deleted.
-* sink_wrap
-* Pointer to a function which can be used to invoke the "sink"
-* function supplied (above). This wrapper function is necessary
-* in order to hide variations in the nature of the sink
-* function, such as may arise when it is supplied by a foreign
-* (non-C) language interface.
-*
-* The first parameter of the "sink_wrap" function is a pointer
-* to the "sink" function, and the second parameter is a pointer
-* to a const, null-terminated character string containing the
-* text to be written. The "sink_wrap" function should cast the
-* "sink" function pointer (as necessary) and invoke the
-* function with appropriate arguments to deliver the line of
-* output text. The "sink_wrap" function then returns void.
-*
-* If "sink_wrap" is NULL, the contents of the FitsChan will not be
-* written out before being deleted.
-* options
-* Pointer to a null-terminated string containing an optional
-* comma-separated list of attribute assignments to be used for
-* initialising the new FitsChan. The syntax used is identical to
-* that for the astSet function and may include "printf" format
-* specifiers identified by "%" symbols in the normal way.
-* ...
-* If the "options" string contains "%" format specifiers, then
-* an optional list of additional 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 function (and for the C "printf"
-* function).
-
-* Returned Value:
-* astFitsChanFor()
-* A pointer to the new FitsChan.
-
-* Notes:
-* - A null Object pointer (AST__NULL) will be returned if this
-* function is invoked with the global error status set, or if it
-* should fail for any reason.
-* - This function is only available through the public interface
-* to the FitsChan class (not the protected interface) and is
-* intended solely for use in implementing foreign language
-* interfaces to this class.
-*-
-
-* Implememtation Notes:
-* - This function behaves exactly like astFitsChanId_, in that it
-* returns ID values and not true C pointers, but it has two
-* additional arguments. These are pointers to the "wrapper
-* functions" which are needed to accommodate foreign language
-* interfaces.
-*/
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstFitsChan *new; /* Pointer to new FitsChan */
- va_list args; /* Variable argument list */
- int *status; /* Pointer to inherited status value */
-
-/* Get a pointer to the inherited status value. */
- status = astGetStatusPtr;
-
-/* Check the global status. */
- if ( !astOK ) return NULL;
-
-/* Get a pointer to the thread specific global data structure. */
- astGET_GLOBALS(NULL);
-
-/* Initialise the FitsChan, allocating memory and initialising the
- virtual function table as well if necessary. */
- new = astInitFitsChan( NULL, sizeof( AstFitsChan ), !class_init,
- &class_vtab, "FitsChan", source, source_wrap,
- sink, sink_wrap );
-
-/* If successful, note that the virtual function table has been
- initialised. */
- if ( astOK ) {
- class_init = 1;
-
-/* Apply any default options specified by "<class>_OPTIONS" environment
- variable. */
- astEnvSet( new );
-
-/* Obtain the variable argument list and pass it along with the
- options string to the astVSet method to initialise the new
- FitsChan's attributes. */
- va_start( args, options );
- astVSet( new, options, NULL, args );
- va_end( args );
-
-/* If an error occurred, clean up by deleting the new object. */
- if ( !astOK ) new = astDelete( new );
- }
-
-/* Return an ID value for the new FitsChan. */
- return astMakeId( new );
-}
-
-AstFitsChan *astInitFitsChan_( void *mem, size_t size, int init,
- AstFitsChanVtab *vtab, const char *name,
- const char *(* source)( void ),
- char *(* source_wrap)( const char *(*)( void ), int * ),
- void (* sink)( const char * ),
- void (* sink_wrap)( void (*)( const char * ),
- const char *, int * ), int *status ) {
-
-/*
-*+
-* Name:
-* astInitFitsChan
-
-* Purpose:
-* Initialise a FitsChan.
-
-* Type:
-* Protected function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstFitsChan *astInitFitsChan_( void *mem, size_t size, int init,
-* AstFitsChanVtab *vtab, const char *name,
-* const char *(* source)( void ),
-* char *(* source_wrap)( const char *(*)( void ), int * ),
-* void (* sink)( const char * ),
-* void (* sink_wrap)( void (*)( const char * ),
-* const char *, int * ) )
-
-* Class Membership:
-* FitsChan initialiser.
-
-* Description:
-* This function is provided for use by class implementations to
-* initialise a new FitsChan object. It allocates memory (if
-* necessary) to accommodate the FitsChan plus any additional data
-* associated with the derived class. It then initialises a
-* FitsChan 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 FitsChan at the start of the memory passed
-* via the "vtab" parameter.
-
-* Parameters:
-* mem
-* A pointer to the memory in which the FitsChan is to be
-* initialised. This must be of sufficient size to accommodate
-* the FitsChan data (sizeof(FitsChan)) 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 FitsChan (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 FitsChan structure, so a valid value must be
-* supplied even if not required for allocating memory.
-* init
-* A boolean flag indicating if the FitsChan'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 FitsChan.
-* 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).
-* source
-* Pointer to a "source" function which will be used to obtain
-* FITS header cards. Generally, this will be obtained by
-* casting a pointer to a source function which is compatible
-* with the "source_wrap" wrapper function (below). The pointer
-* should later be cast back to its original type by the
-* "source_wrap" function before the function is invoked.
-*
-* If "source" is NULL, the FitsChan will remain empty until
-* cards are added explicitly (e.g. using astPutCards or astPutFits).
-* source_wrap
-* Pointer to a function which can be used to invoke the
-* "source" function supplied (above). This wrapper function is
-* necessary in order to hide variations in the nature of the
-* source function, such as may arise when it is supplied by a
-* foreign (non-C) language interface.
-*
-* The single parameter of the "source_wrap" function is a
-* pointer to the "source" function, and it should cast this
-* function pointer (as necessary) and invoke the function with
-* appropriate arguments to obtain the next FITS header card.
-* The "source_wrap" function should then return a pointer
-* to a dynamically allocated, null terminated string containing
-* the text that was read. The string will be freed (using
-* astFree) when no longer required and the "source_wrap"
-* function need not concern itself with this. A NULL pointer
-* should be returned if there is no more input to read.
-*
-* If "source" is NULL, the FitsChan will remain empty until
-* cards are added explicitly (e.g. using astPutCards or astPutFits).
-* sink
-* Pointer to a "sink" function which will be used to deliver
-* FITS header cards. Generally, this will be obtained by
-* casting a pointer to a sink function which is compatible with
-* the "sink_wrap" wrapper function (below). The pointer should
-* later be cast back to its original type by the "sink_wrap"
-* function before the function is invoked.
-*
-* If "sink" is NULL, the contents of the FitsChan will not be
-* written out before being deleted.
-* sink_wrap
-* Pointer to a function which can be used to invoke the "sink"
-* function supplied (above). This wrapper function is necessary
-* in order to hide variations in the nature of the sink
-* function, such as may arise when it is supplied by a foreign
-* (non-C) language interface.
-*
-* The first parameter of the "sink_wrap" function is a pointer
-* to the "sink" function, and the second parameter is a pointer
-* to a const, null-terminated character string containing the
-* text to be written. The "sink_wrap" function should cast the
-* "sink" function pointer (as necessary) and invoke the
-* function with appropriate arguments to deliver the line of
-* output text. The "sink_wrap" function then returns void.
-*
-* If "sink_wrap" is NULL, the contents of the FitsChan will not be
-* written out before being deleted.
-
-* Returned Value:
-* A pointer to the new FitsChan.
-
-* 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: */
- AstFitsChan *new; /* Pointer to new FitsChan */
-
-/* Check the global status. */
- if ( !astOK ) return NULL;
-
-/* If necessary, initialise the virtual function table. */
- if ( init ) astInitFitsChanVtab( vtab, name );
-
-/* Initialise a Channel structure (the parent class) as the first
- component within the FitsChan structure, allocating memory if
- necessary. I am not sure why FitsChan has its own source_wrap and
- sink_wrap items, rather than just using those inherited from Channel.
- It may be possible to do away with the fitschan wrappers and just use
- the channel wrapper, but I have not yet tried this. Old mail from RFWS
- suggests that it may be because the F77 FitsChan source and sink
- interfaces handle fixed length strings (80 characters), whereas
- Channel sournce and sink handle variable length strings. This needs
- investigating. */
- new = (AstFitsChan *) astInitChannel( mem, size, 0,
- (AstChannelVtab *) vtab, name,
- NULL, NULL, NULL, NULL );
- if ( astOK ) {
-
-/* Initialise the FitsChan data. */
-/* ---------------------------- */
- new->head = NULL;
- new->card = NULL;
- new->keyseq = NULL;
- new->keywords = NULL;
- new->defb1950 = -1;
- new->tabok = -INT_MAX;
- new->cdmatrix = -1;
- new->carlin = -1;
- new->polytan = -INT_MAX;
- new->iwc = -1;
- new->clean = -1;
- new->fitsdigits = DBL_DIG;
- new->fitsaxisorder = NULL;
- new->encoding = UNKNOWN_ENCODING;
- new->warnings = NULL;
- new->tables = NULL;
-
-/* Save the pointers to the source and sink functions and the wrapper
- functions that invoke them. */
- new->source = source;
- new->saved_source = NULL;
- new->source_wrap = source_wrap;
- new->sink = sink;
- new->sink_wrap = sink_wrap;
- new->tabsource = NULL;
- new->tabsource_wrap = NULL;
-
-/* Rewind the FitsChan so that the next read operation will return the
- first card. */
- new->card = new->head;
-
-/* 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;
-}
-AstFitsChan *astLoadFitsChan_( void *mem, size_t size,
- AstFitsChanVtab *vtab, const char *name,
- AstChannel *channel, int *status ) {
-
-/*
-*+
-* Name:
-* astLoadFitsChan
-
-* Purpose:
-* Load a FitsChan.
-
-* Type:
-* Protected function.
-
-* Synopsis:
-* #include "fitschan.h"
-* AstFitsChan *astLoadFitsChan( void *mem, size_t size,
-* AstFitsChanVtab *vtab, const char *name,
-* AstChannel *channel )
-
-* Class Membership:
-* FitsChan loader.
-
-* Description:
-* This function is provided to load a new FitsChan 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
-* FitsChan structure in this memory, using data read from the input
-* Channel.
-*
-* If the "init" flag is set, it also initialises the contents of a
-* virtual function table for a FitsChan at the start of the memory
-* passed via the "vtab" parameter.
-
-* Parameters:
-* mem
-* A pointer to the memory into which the FitsChan is to be
-* loaded. This must be of sufficient size to accommodate the
-* FitsChan data (sizeof(FitsChan)) 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 FitsChan (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 FitsChan 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(AstFitsChan) is used instead.
-* vtab
-* Pointer to the start of the virtual function table to be
-* associated with the new FitsChan. If this is NULL, a pointer
-* to the (static) virtual function table for the FitsChan 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 "FitsChan" is used instead.
-
-* Returned Value:
-* A pointer to the new FitsChan.
-
-* 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.
-*-
-*/
-#define KEY_LEN 50 /* Maximum length of a keyword */
-
-/* Local Variables: */
- astDECLARE_GLOBALS /* Pointer to thread-specific global data */
- AstFitsChan *new; /* Pointer to the new FitsChan */
- char *comment; /* Pointer to keyword comment */
- char *keynm; /* Keyword name */
- char *text; /* Textual version of integer value */
- char buff[ KEY_LEN + 1 ]; /* Buffer for keyword string */
- double dval[2]; /* Double precision data values */
- int flags; /* Keyword flags */
- int free_data; /* Should data memory be freed? */
- int ival[2]; /* Integer data values */
- int ncard; /* No. of FitsCards read so far */
- int type; /* Keyword type */
- void *data; /* Pointer to keyword data value */
-
-/* Initialise. */
- new = NULL;
-
-/* Check the global error status. */
- if ( !astOK ) return new;
-
-/* Get a pointer to the thread specific global data structure. */
- astGET_GLOBALS(channel);
-
-/* If a NULL virtual function table has been supplied, then this is
- the first loader to be invoked for this FitsChan. In this case the
- FitsChan belongs to this class, so supply appropriate values to be
- passed to the parent class loader (and its parent, etc.). */
- if ( !vtab ) {
- size = sizeof( AstFitsChan );
- vtab = &class_vtab;
- name = "FitsChan";
-
-/* If required, initialise the virtual function table for this class. */
- if ( !class_init ) {
- astInitFitsChanVtab( 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 FitsChan. */
- new = astLoadChannel( mem, size, (AstChannelVtab *) 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, "FitsChan" );
-
-/* Initialise the KeyMap holding the keywords in the FitsChan. */
- new->keywords = NULL;
-
-/* Initialise the list of keyword sequence numbers. */
- new->keyseq = NULL;
-
-/* Set the pointers to the source and sink functions, and their
- wrapper functions, to NULL (we cannot restore these since they
- refer to process-specific addresses). */
- new->source = NULL;
- new->saved_source = NULL;
- new->source_wrap = NULL;
- new->sink = NULL;
- new->sink_wrap = NULL;
- new->tabsource = NULL;
- new->tabsource_wrap = NULL;
-
-/* Now read each individual data item from this list and use it to
- initialise the appropriate instance variable(s) for this class. */
-
-/* Encoding. */
-/* --------- */
- text = astReadString( channel, "encod", UNKNOWN_STRING );
- if( text && strcmp( text, UNKNOWN_STRING ) ) {
- new->encoding = FindString( MAX_ENCODING + 1, xencod, text,
- "the FitsChan component 'Encod'",
- "astRead", astGetClass( channel ), status );
- } else {
- new->encoding = UNKNOWN_ENCODING;
- }
- if ( TestEncoding( new, status ) ) SetEncoding( new, new->encoding, status );
- text = astFree( text );
-
-/* FitsAxisOrder. */
-/* -------------- */
- new->fitsaxisorder = astReadString( channel, "faxord", NULL );
-
-/* FitsDigits. */
-/* ----------- */
- new->fitsdigits = astReadInt( channel, "fitsdg", DBL_DIG );
- if ( TestFitsDigits( new, status ) ) SetFitsDigits( new, new->fitsdigits, status );
-
-/* DefB1950 */
-/* -------- */
- new->defb1950 = astReadInt( channel, "dfb1950", -1 );
- if ( TestDefB1950( new, status ) ) SetDefB1950( new, new->defb1950, status );
-
-/* TabOK */
-/* ----- */
- new->tabok = astReadInt( channel, "tabok", -INT_MAX );
- if ( TestTabOK( new, status ) ) SetTabOK( new, new->tabok, status );
-
-/* CDMatrix */
-/* -------- */
- new->cdmatrix = astReadInt( channel, "cdmat", -1 );
- if ( TestCDMatrix( new, status ) ) SetCDMatrix( new, new->cdmatrix, status );
-
-/* CarLin */
-/* ------ */
- new->carlin = astReadInt( channel, "carlin", -1 );
- if ( TestCarLin( new, status ) ) SetCarLin( new, new->carlin, status );
-
-/* PolyTan */
-/* ------- */
- new->polytan = astReadInt( channel, "polytan", -1 );
- if ( TestPolyTan( new, status ) ) SetPolyTan( new, new->polytan, status );
-
-/* Iwc */
-/* --- */
- new->iwc = astReadInt( channel, "iwc", -1 );
- if ( TestIwc( new, status ) ) SetIwc( new, new->iwc, status );
-
-/* Clean */
-/* ----- */
- new->clean = astReadInt( channel, "clean", -1 );
- if ( TestClean( new, status ) ) SetClean( new, new->clean, status );
-
-/* Warnings. */
-/* --------- */
- new->warnings = astReadString( channel, "warn", NULL );
-
-/* Card. */
-/* ----- */
-
-/* Initialise the index of the card to be read next. */
- ncard = 1;
- new->card = NULL;
- new->head = NULL;
-
-/* Load each card. */
- type = AST__NOTYPE + 1;
- while( type != AST__NOTYPE && astOK ){
-
-/* Get the keyword type. */
- (void) sprintf( buff, "ty%d", ncard );
- text = astReadString( channel, buff, " " );
- if( strcmp( text, " " ) ) {
- type = FindString( 9, type_names, text,
- "a FitsChan keyword data type",
- "astRead", astGetClass( channel ), status );
- } else {
- type = AST__NOTYPE;
- }
- text = astFree( text );
-
-/* Only proceed if the keyword type was found. */
- if( type != AST__NOTYPE ){
-
-/* Get the keyword name. Use a default blank name. */
- (void) sprintf( buff, "nm%d", ncard );
- keynm = astReadString( channel, buff, " " );
-
-/* Get the data value, using the appropriate data type, unless the
- keyword is a comment keyword or is undefined. */
- free_data = 0;
- if( type == AST__FLOAT ){
- (void) sprintf( buff, "dt%d", ncard );
- dval[ 0 ] = astReadDouble( channel, buff, AST__BAD );
- data = (void *) dval;
- } else if( type == AST__STRING || type == AST__CONTINUE ){
- (void) sprintf( buff, "dt%d", ncard );
- data = (void *) astReadString( channel, buff, "" );
- free_data = 1;
- } else if( type == AST__INT ){
- (void) sprintf( buff, "dt%d", ncard );
- ival[ 0 ] = astReadInt( channel, buff, 0 );
- data = (void *) ival;
- } else if( type == AST__LOGICAL ){
- (void) sprintf( buff, "dt%d", ncard );
- ival[ 0 ] = astReadInt( channel, buff, 0 );
- data = (void *) ival;
- } else if( type == AST__COMPLEXF ){
- (void) sprintf( buff, "dr%d", ncard );
- dval[ 0 ] = astReadDouble( channel, buff, AST__BAD );
- (void) sprintf( buff, "di%d", ncard );
- dval[ 1 ] = astReadDouble( channel, buff, AST__BAD );
- data = (void *) dval;
- } else if( type == AST__COMPLEXI ){
- (void) sprintf( buff, "dr%d", ncard );
- ival[ 0 ] = astReadInt( channel, buff, 0 );
- (void) sprintf( buff, "di%d", ncard );
- ival[ 1 ] = astReadInt( channel, buff, 0 );
- data = (void *) ival;
- } else {
- data = NULL;
- }
-
-/* Get the keyword flags (only written by versions of AST later than
- V1.4). These are packed into an int. */
- (void) sprintf( buff, "fl%d", ncard );
- flags = astReadInt( channel, buff, 0 );
-
-/* If the flags were not found, use the keyword deletion flag written by
- AST V1.4 and earlier. */
- if( !flags ) {
- (void) sprintf( buff, "dl%d", ncard );
- flags = astReadInt( channel, buff, 0 );
- }
-
-/* Get the keyword comment. */
- (void) sprintf( buff, "cm%d", ncard );
- comment = astReadString( channel, buff, NULL );
-
-/* Append a new card to the output FitsChan. */
- NewCard( new, keynm, type, data, comment, flags, status );
-
-/* Free the character strings, and data (if required). */
- comment = (char *) astFree( (void *) comment );
- keynm = (char *) astFree( (void *) keynm );
- if( free_data ) data = astFree( data );
- }
-
-/* Move on to the next card. */
- ncard++;
- }
-
-/* Set up the current card index. */
- astSetCard( new, astReadInt( channel, "card", 0 ) );
-
-/* Load any FitTables. */
- new->tables = astReadObject( channel, "tables", NULL );
- }
-
-/* If an error occurred, clean up by deleting the new FitsChan. */
- if ( !astOK ) new = astDelete( new );
-
-/* Return the new FitsChan 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 astWriteFits_( AstFitsChan *this, int *status ){
- if( !this ) return;
- (**astMEMBER(this,FitsChan,WriteFits))(this, status );
-}
-
-void astReadFits_( AstFitsChan *this, int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,ReadFits))(this, status );
-}
-
-void astEmptyFits_( AstFitsChan *this, int *status ){
- if( !this ) return;
- (**astMEMBER(this,FitsChan,EmptyFits))(this, status );
-}
-
-void astShowFits_( AstFitsChan *this, int *status ){
- if( !this ) return;
- (**astMEMBER(this,FitsChan,ShowFits))(this, status );
-}
-
-void astPutCards_( AstFitsChan *this, const char *cards, int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,PutCards))(this,cards, status );
-}
-
-void astPutFits_( AstFitsChan *this, const char *card, int overwrite, int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,PutFits))(this,card,overwrite, status );
-}
-
-void astDelFits_( AstFitsChan *this, int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,DelFits))(this, status );
-}
-
-void astPurgeWCS_( AstFitsChan *this, int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,PurgeWCS))(this, status );
-}
-
-AstKeyMap *astGetTables_( AstFitsChan *this, int *status ){
- if( !astOK ) return NULL;
- return (**astMEMBER(this,FitsChan,GetTables))(this, status );
-}
-
-void astPutTables_( AstFitsChan *this, AstKeyMap *tables, int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,PutTables))(this, tables, status );
-}
-
-void astPutTable_( AstFitsChan *this, AstFitsTable *table, const char *extnam,
- int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,PutTable))(this, table, extnam, status );
-}
-
-void astRemoveTables_( AstFitsChan *this, const char *key, int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,RemoveTables))(this, key, status );
-}
-
-void astRetainFits_( AstFitsChan *this, int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,RetainFits))(this, status );
-}
-
-int astFitsEof_( AstFitsChan *this, int *status ){
- if( !this ) return 1;
- return (**astMEMBER(this,FitsChan,FitsEof))( this, status );
-}
-
-void astSetFitsCom_( AstFitsChan *this, const char *name,
- const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsCom))( this, name, comment, overwrite, status );
-}
-
-void astSetFitsI_( AstFitsChan *this, const char *name, int value,
- const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsI))( this, name, value, comment, overwrite, status );
-}
-
-void astSetFitsF_( AstFitsChan *this, const char *name, double value,
- const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsF))( this, name, value, comment, overwrite, status );
-}
-
-void astSetFitsS_( AstFitsChan *this, const char *name, const char *value,
- const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsS))( this, name, value, comment, overwrite, status );
-}
-
-void astSetFitsCN_( AstFitsChan *this, const char *name, const char *value,
- const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsCN))( this, name, value, comment, overwrite, status );
-}
-
-void astSetFitsCF_( AstFitsChan *this, const char *name, double *value,
- const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsCF))( this, name, value, comment, overwrite, status );
-}
-
-void astSetFitsCI_( AstFitsChan *this, const char *name, int *value,
- const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsCI))( this, name, value, comment, overwrite, status );
-}
-
-void astSetFitsL_( AstFitsChan *this, const char *name, int value,
- const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsL))( this, name, value, comment, overwrite, status );
-}
-
-void astSetFitsU_( AstFitsChan *this, const char *name, const char *comment,
- int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsU))( this, name, comment, overwrite, status );
-}
-
-void astSetFitsCM_( AstFitsChan *this, const char *comment, int overwrite, int *status ) {
- if ( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetFitsCM))( this, comment, overwrite, status );
-}
-
-void astClearCard_( AstFitsChan *this, int *status ){
- if( !this ) return;
- (**astMEMBER(this,FitsChan,ClearCard))( this, status );
-}
-
-void astSetCard_( AstFitsChan *this, int card, int *status ){
- if( !this ) return;
- (**astMEMBER(this,FitsChan,SetCard))( this, card, status );
-}
-
-int astTestCard_( AstFitsChan *this, int *status ){
- if( !this ) return 0;
- return (**astMEMBER(this,FitsChan,TestCard))( this, status );
-}
-
-int astGetCard_( AstFitsChan *this, int *status ){
- if( !this ) return 0;
- return (**astMEMBER(this,FitsChan,GetCard))( this, status );
-}
-
-int astGetNcard_( AstFitsChan *this, int *status ){
- if( !this ) return 0;
- return (**astMEMBER(this,FitsChan,GetNcard))( this, status );
-}
-
-int astGetCardType_( AstFitsChan *this, int *status ){
- if( !this ) return AST__NOTYPE;
- return (**astMEMBER(this,FitsChan,GetCardType))( this, status );
-}
-
-const char *astGetCardComm_( AstFitsChan *this, int *status ){
- if( !this ) return NULL;
- return (**astMEMBER(this,FitsChan,GetCardComm))( this, status );
-}
-
-const char *astGetCardName_( AstFitsChan *this, int *status ){
- if( !this ) return NULL;
- return (**astMEMBER(this,FitsChan,GetCardName))( this, status );
-}
-
-int astGetNkey_( AstFitsChan *this, int *status ){
- if( !this ) return 0;
- return (**astMEMBER(this,FitsChan,GetNkey))( this, status );
-}
-
-int astGetClean_( AstFitsChan *this, int *status ){
- if( !this ) return 0;
- return (**astMEMBER(this,FitsChan,GetClean))( this, status );
-}
-
-const char *astGetAllWarnings_( AstFitsChan *this, int *status ){
- if( !this ) return NULL;
- return (**astMEMBER(this,FitsChan,GetAllWarnings))( this, status );
-}
-
-int astGetFitsCF_( AstFitsChan *this, const char *name, double *value, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,GetFitsCF))( this, name, value, status );
-}
-
-int astGetFitsCI_( AstFitsChan *this, const char *name, int *value, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,GetFitsCI))( this, name, value, status );
-}
-
-int astGetFitsF_( AstFitsChan *this, const char *name, double *value, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,GetFitsF))( this, name, value, status );
-}
-
-int astGetFitsI_( AstFitsChan *this, const char *name, int *value, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,GetFitsI))( this, name, value, status );
-}
-
-int astGetFitsL_( AstFitsChan *this, const char *name, int *value, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,GetFitsL))( this, name, value, status );
-}
-
-int astTestFits_( AstFitsChan *this, const char *name, int *there, int *status ){
- if( there ) *there = 0;
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,TestFits))( this, name, there, status );
-}
-
-int astGetFitsS_( AstFitsChan *this, const char *name, char **value, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,GetFitsS))( this, name, value, status );
-}
-
-int astGetFitsCN_( AstFitsChan *this, const char *name, char **value, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,GetFitsCN))( this, name, value, status );
-}
-
-int astFitsGetCom_( AstFitsChan *this, const char *name, char **comment, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,FitsGetCom))( this, name, comment, status );
-}
-
-int astKeyFields_( AstFitsChan *this, const char *filter, int maxfld,
- int *ubnd, int *lbnd, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,KeyFields))( this, filter, maxfld,
- ubnd, lbnd, status );
-}
-
-int astFindFits_( AstFitsChan *this, const char *name, char *card, int inc, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,FindFits))( this, name, card, inc, status );
-}
-
-int astGetEncoding_( AstFitsChan *this, int *status ){
- if( !astOK ) return UNKNOWN_ENCODING;
- return (**astMEMBER(this,FitsChan,GetEncoding))( this, status );
-}
-
-int astGetCDMatrix_( AstFitsChan *this, int *status ){
- if( !astOK ) return 0;
- return (**astMEMBER(this,FitsChan,GetCDMatrix))( this, status );
-}
-void astSetTableSource_( AstFitsChan *this,
- void (*tabsource)( void ),
- void (*tabsource_wrap)( void (*)( void ),
- AstFitsChan *, const char *,
- int, int, int * ),
- int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,SetTableSource))( this, tabsource,
- tabsource_wrap, status );
-}
-void astTableSource_( AstFitsChan *this,
- void (* tabsource)( AstFitsChan *, const char *,
- int, int, int * ),
- int *status ){
- if( !astOK ) return;
- (**astMEMBER(this,FitsChan,TableSource))( this, tabsource, status );
-}
-
-/*
- * A diagnostic function which lists the contents of a FitsChan to
- * standard output.
- */
-
-/*
-static void ListFC( AstFitsChan *, const char * );
-
-static void ListFC( AstFitsChan *this, const char *ttl ) {
- FitsCard *cardo;
- char card[ 81 ];
- printf("%s\n----------------------------------------\n", ttl );
- cardo = (FitsCard *) this->card;
- astClearCard( this );
- while( !astFitsEof( this ) && astOK ){
- FormatCard( this, card, "List" );
- if( this->card == cardo ) {
- printf( "%s <<<<< currrent card <<<<< \n", card );
- } else {
- printf( "%s\n", card );
- }
- MoveCard( this, 1, "List", "FitsChan" );
- }
- this->card = cardo;
-}
-*/
-
-
-
-
-
-
-
-
-
-
-