[starlink-ast] 01/02: New upstream version 7.3.3+dfsg

Ole Streicher olebole-guest at moszumanska.debian.org
Tue Jan 7 13:50:44 UTC 2014


This is an automated email from the git hooks/post-receive script.

olebole-guest pushed a commit to branch debian
in repository starlink-ast.

commit d571212b2c8fb3a279f56fb0ba1b87012a1a6800
Author: Ole Streicher <debian at liska.ath.cx>
Date:   Tue Jan 7 09:58:37 2014 +0100

    New upstream version 7.3.3+dfsg
---
 ast.news     |  22 ++-
 box.c        |  27 ++-
 circle.c     |  25 ++-
 configure    |  20 +--
 configure.ac |   2 +-
 ellipse.c    |  31 +++-
 ffitschan.c  |  10 ++
 fitschan.c   | 561 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 fitschan.h   |  15 ++
 fregion.c    |  13 ++
 interval.c   |  27 ++-
 matrixmap.c  |  29 ++-
 memory.c     |  20 ++-
 memory.h     |   2 +
 object.c     | 105 ++++++++++-
 object.h     |   9 +
 object.h.in  |   9 +
 polygon.c    | 145 +++++++++++++--
 region.c     |  68 ++++++++
 region.h     |   4 +
 skyframe.c   |  13 +-
 slamap.c     |  10 +-
 sphmap.c     | 165 +++++++++++++++++-
 sun210.tex   | 169 ++++++++++++++++--
 sun211.tex   | 159 +++++++++++++++--
 table.c      |   8 +-
 version.h    |   6 +-
 27 files changed, 1518 insertions(+), 156 deletions(-)

diff --git a/ast.news b/ast.news
index bd167c6..f9fc0f4 100644
--- a/ast.news
+++ b/ast.news
@@ -1,6 +1,6 @@
 AST Library
 -----------
-   A new release (V7.3.2) of the Starlink AST (astrometry) library is
+   A new release (V7.3.3) of the Starlink AST (astrometry) library is
 now available.
 
    AST provides a comprehensive range of facilities for attaching
@@ -16,6 +16,26 @@ environment-independent.
 Main Changes in this Version
 ----------------------------
 
+- The FitsChan class has new attributes CardName and CardComm, which hold
+the keyword name and comment of the current card.
+
+- When reading FITS-WCS headers that include polynomial distortion in the
+SIP format, any inverse transformation specified in the header is now
+ignored and a new inverse is created to replace it based on the supplied
+forward transformation. Previously, an inverse was created only if the
+header did not include an inverse. The accuracy of the inverse
+transformation has also been improved, although it may now be slower to
+evaluate in some circumstances.
+
+- A bug has been fixed that could over-write the FitsChan CarLin attribute
+with a non-zero value if the header contains a spectral axis.
+
+- The default options for each newly created FitsChan can now be
+specified via the environment variable FITSCHAN_OPTIONS.
+
+Main Changes in V7.3.2
+----------------------
+
 - Fix support for reading GLS projections from FITS headers.
 
 - The KeyMap class has new sorting options "KeyAgeUp" and "KeyAgeDown" that
diff --git a/box.c b/box.c
index 95da446..a20ec07 100644
--- a/box.c
+++ b/box.c
@@ -95,6 +95,10 @@ f     The Box class does not define any new routines beyond those
 *        Use a more robust algorithm for determining the order of the
 *        vertices whan a Box is simplified to a Polygon. The old method
 *        sometimes resulted in an unbounded "inside-out" polygon.
+*     4-NOV-2013 (DSB):
+*        Modify RegPins so that it can handle uncertainty regions that straddle
+*        a discontinuity. Previously, such uncertainty Regions could have a huge
+*        bounding box resulting in matching region being far too big.
 *class--
 */
 
@@ -3012,6 +3016,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    AstRegion *tunc;             /* Uncertainity Region from "this" */
    double **ptr;                /* Pointer to axis values in "ps2" */
    double *large;               /* A corner position in the larger Box */
+   double *safe;                /* An interior point in "this" */
    double *lbnd_tunc;           /* Lower bounds of "this" uncertainty Region */
    double *lbnd_unc;            /* Lower bounds of supplied uncertainty Region */
    double *p;                   /* Pointer to next axis value */
@@ -3058,18 +3063,28 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
                 astGetNaxes( unc ), nc );
    }
 
+/* Get the centre of the region in the base Frame. We use this as a "safe"
+   interior point within the region. */
+   safe = astRegCentre( this, NULL, NULL, 0, AST__BASE );
+
 /* We now find the maximum distance on each axis that a point can be from the
    boundary of the Box for it still to be considered to be on the boundary.
    First get the Region which defines the uncertainty within the Box being
-   checked (in its base Frame), and get its bounding box. */
+   checked (in its base Frame), re-centre it on the interior point found
+   above (to avoid problems if the uncertainty region straddles a
+   discontinuity), and get its bounding box. */
    tunc = astGetUncFrm( this, AST__BASE );
+   if( safe ) astRegCentre( tunc, safe, NULL, 0, AST__CURRENT );
    lbnd_tunc = astMalloc( sizeof( double )*(size_t) nc );
    ubnd_tunc = astMalloc( sizeof( double )*(size_t) nc );
    astGetRegionBounds( tunc, lbnd_tunc, ubnd_tunc );
 
-/* Also get the Region which defines the uncertainty of the supplied points
-   and get its bounding box. */
+/* Also get the Region which defines the uncertainty of the supplied
+   points and get its bounding box. First re-centre the uncertainty at the
+   interior position to avoid problems from uncertainties that straddle a
+   discontinuity. */
    if( unc ) {
+      if( safe ) astRegCentre( unc, safe, NULL, 0, AST__CURRENT );
       lbnd_unc = astMalloc( sizeof( double )*(size_t) nc );
       ubnd_unc = astMalloc( sizeof( double )*(size_t) nc );
       astGetRegionBounds( unc, lbnd_unc, ubnd_unc );
@@ -3078,8 +3093,9 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
       ubnd_unc = NULL;
    }
 
-/* The required border width for each axis is half of the total width of
-   the two bounding boxes. Use a zero sized box "unc" if no box was supplied. */
+/* The required border width for each axis is half of the total width
+   of the two bounding boxes. Use a zero sized box "unc" if no box was
+   supplied. */
    wid = astMalloc( sizeof( double )*(size_t) nc );
    large = astMalloc( sizeof( double )*(size_t) nc );
    small = astMalloc( sizeof( double )*(size_t) nc );
@@ -3184,6 +3200,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    wid = astFree( wid );
    large = astFree( large );
    small = astFree( small );
+   safe = astFree( safe );
 
 /* If an error has occurred, return zero. */
    if( !astOK ) {
diff --git a/circle.c b/circle.c
index 1497fd8..d5df0cc 100644
--- a/circle.c
+++ b/circle.c
@@ -58,6 +58,10 @@ c     - AST_CIRCLEPARS: Get the geometric parameters of the Circle
 *  History:
 *     31-AUG-2004 (DSB):
 *        Original version.
+*     4-NOV-2013 (DSB):
+*        Modify RegPins so that it can handle uncertainty regions that straddle
+*        a discontinuity. Previously, such uncertainty Regions could have a huge
+*        bounding box resulting in matching region being far too big.
 *class--
 */
 
@@ -1359,6 +1363,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    double *lbnd_tunc;           /* Lower bounds of "this" uncertainty Region */
    double *lbnd_unc;            /* Lower bounds of supplied uncertainty Region */
    double *p;                   /* Pointer to next axis value */
+   double *safe;                /* An interior point in "this" */
    double *ubnd_tunc;           /* Upper bounds of "this" uncertainty Region */
    double *ubnd_unc;            /* Upper bounds of supplied uncertainty Region */
    double drad;                 /* Radius increment corresponding to border width */
@@ -1401,23 +1406,32 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
                 astGetNaxes( unc ), nc );
    }
 
+/* Get the centre of the region in the base Frame. We use this as a "safe"
+   interior point within the region. */
+   safe = astRegCentre( this, NULL, NULL, 0, AST__BASE );
+
 /* We now find the maximum distance on each axis that a point can be from the
    boundary of the Circle for it still to be considered to be on the boundary.
    First get the Region which defines the uncertainty within the Circle being
-   checked (in its base Frame), and get its bounding box. */
+   checked (in its base Frame), re-centre it on the interior point found
+   above (to avoid problems if the uncertainty region straddles a
+   discontinuity), and get its bounding box. */
    tunc = astGetUncFrm( this, AST__BASE );
-
+   if( safe ) astRegCentre( tunc, safe, NULL, 0, AST__CURRENT );
    lbnd_tunc = astMalloc( sizeof( double )*(size_t) nc );
    ubnd_tunc = astMalloc( sizeof( double )*(size_t) nc );
    astGetRegionBounds( tunc, lbnd_tunc, ubnd_tunc );
 
-/* Find the geodesic length withi the base Frame of "this" of the diagonal of
+/* Find the geodesic length within the base Frame of "this" of the diagonal of
    the bounding box. */
    l1 = astDistance( frm, lbnd_tunc, ubnd_tunc );
 
-/* Also get the Region which defines the uncertainty of the supplied points
-   and get its bounding box. */
+/* Also get the Region which defines the uncertainty of the supplied
+   points and get its bounding box. First re-centre the uncertainty at the
+   interior position to avoid problems from uncertainties that straddle a
+   discontinuity. */
    if( unc ) {
+      if( safe ) astRegCentre( unc, safe, NULL, 0, AST__CURRENT );
       lbnd_unc = astMalloc( sizeof( double )*(size_t) nc );
       ubnd_unc = astMalloc( sizeof( double )*(size_t) nc );
       astGetRegionBounds( unc, lbnd_unc, ubnd_unc );
@@ -1522,6 +1536,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    ubnd_tunc = astFree( ubnd_tunc );
    if( unc ) lbnd_unc = astFree( lbnd_unc );
    if( unc ) ubnd_unc = astFree( ubnd_unc );
+   safe = astFree( safe );
 
 /* If an error has occurred, return zero. */
    if( !astOK ) {
diff --git a/configure b/configure
index b0b24ae..c83e97e 100755
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
 #! /bin/sh
 # From configure.ac Revision.
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by Starlink Autoconf 2.59 for ast 7.3.2.
+# Generated by Starlink Autoconf 2.59 for ast 7.3.3.
 #
 # Report bugs to <starlink at jiscmail.ac.uk>.
 #
@@ -424,8 +424,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='ast'
 PACKAGE_TARNAME='ast'
-PACKAGE_VERSION='7.3.2'
-PACKAGE_STRING='ast 7.3.2'
+PACKAGE_VERSION='7.3.3'
+PACKAGE_STRING='ast 7.3.3'
 PACKAGE_BUGREPORT='starlink at jiscmail.ac.uk'
 
 ac_unique_file="ast_link.in"
@@ -980,7 +980,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures ast 7.3.2 to adapt to many kinds of systems.
+\`configure' configures ast 7.3.3 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1046,7 +1046,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of ast 7.3.2:";;
+     short | recursive ) echo "Configuration of ast 7.3.3:";;
    esac
   cat <<\_ACEOF
 
@@ -1198,7 +1198,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-ast configure 7.3.2
+ast configure 7.3.3
 generated by Starlink Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1212,7 +1212,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by ast $as_me 7.3.2, which was
+It was created by ast $as_me 7.3.3, which was
 generated by Starlink Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1857,7 +1857,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='ast'
- VERSION='7.3.2'
+ VERSION='7.3.3'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -25259,7 +25259,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by ast $as_me 7.3.2, which was
+This file was extended by ast $as_me 7.3.3, which was
 generated by Starlink Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -25322,7 +25322,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-ast config.status 7.3.2
+ast config.status 7.3.3
 configured by $0, generated by Starlink Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
diff --git a/configure.ac b/configure.ac
index 552e318..efdd9c2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ dnl   1.5.  It should work with autoconf versions 2.50 or better, and
 dnl   automake 1.6 or better.
 
 dnl   Initialisation: package name and version number
-AC_INIT(ast, 7.3.2, starlink at jiscmail.ac.uk)
+AC_INIT(ast, 7.3.3, starlink at jiscmail.ac.uk)
 
 dnl   Require autoconf-2.50 at least
 AC_PREREQ(2.50)
diff --git a/ellipse.c b/ellipse.c
index 53154f5..bf91c48 100644
--- a/ellipse.c
+++ b/ellipse.c
@@ -58,6 +58,13 @@ c     - AST_ELLIPSEPARS: Get the geometric parameters of the Ellipse
 *  History:
 *     7-SEP-2004 (DSB):
 *        Original version.
+*     4-NOV-2013 (DSB):
+*        Modify RegPins so that it can handle uncertainty regions that straddle
+*        a discontinuity. Previously, such uncertainty Regions could have a huge
+*        bounding box resulting in matching region being far too big.
+*     6-JAN-2014 (DSB):
+*        Ensure cached information is available in RegCentre even if no new 
+*        centre is supplied.
 *class--
 */
 
@@ -1280,6 +1287,9 @@ static double *RegCentre( AstRegion *this_region, double *cen, double **ptr,
 /* Get a pointer to the Ellipse structure. */
    this = (AstEllipse *) this_region;
 
+/* Ensure cached information is available. */
+   Cache( this, status );
+
 /* Get the number of axis values per point in the current Frame. */
    ncc = astGetNout( this_region->frameset );
 
@@ -1300,9 +1310,6 @@ static double *RegCentre( AstRegion *this_region, double *cen, double **ptr,
    pointer. */
    } else {
 
-/* Ensure cached information is available. */
-      Cache( this, status );
-
 /* Get a pointer to the axis values stored in the Region structure. */
       rptr = astGetPoints( this_region->points );
 
@@ -1436,6 +1443,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    AstRegion *tunc;             /* Uncertainity Region from "this" */
    double **ptr;                /* Pointer to axis values in "ps2" */
    double *p;                   /* Pointer to next axis value */
+   double *safe;                /* An interior point in "this" */
    double drad;                 /* Radius increment corresponding to border width */
    double l1;                   /* Length of bounding box diagonal */
    double l2;                   /* Length of bounding box diagonal */
@@ -1476,11 +1484,18 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
                 astGetNaxes( unc ) );
    }
 
+/* Get the centre of the region in the base Frame. We use this as a "safe"
+   interior point within the region. */
+   safe = astRegCentre( this, NULL, NULL, 0, AST__BASE );
+
 /* We now find the maximum distance on each axis that a point can be from the
    boundary of the Ellipse for it still to be considered to be on the boundary.
    First get the Region which defines the uncertainty within the Ellipse being
-   checked (in its base Frame), and get its bounding box. */
+   checked (in its base Frame), re-centre it on the interior point found
+   above (to avoid problems if the uncertainty region straddles a
+   discontinuity), and get its bounding box. */
    tunc = astGetUncFrm( this, AST__BASE );
+   if( safe ) astRegCentre( tunc, safe, NULL, 0, AST__CURRENT );
    astGetRegionBounds( tunc, lbnd_tunc, ubnd_tunc );
 
 /* Find the geodesic length within the base Frame of "this" of the diagonal of
@@ -1488,9 +1503,12 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    frm = astGetFrame( this_region->frameset, AST__BASE );
    l1 = astDistance( frm, lbnd_tunc, ubnd_tunc );
 
-/* Also get the Region which defines the uncertainty of the supplied points
-   and get its bounding box in the same Frame. */
+/* Also get the Region which defines the uncertainty of the supplied
+   points and get its bounding box. First re-centre the uncertainty at the
+   interior position to avoid problems from uncertainties that straddle a
+   discontinuity. */
    if( unc ) {
+      if( safe ) astRegCentre( unc, safe, NULL, 0, AST__CURRENT );
       astGetRegionBounds( unc, lbnd_unc, ubnd_unc );
 
 /* Find the geodesic length of the diagonal of this bounding box. */
@@ -1595,6 +1613,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
 
    tunc = astAnnul( tunc );
    frm = astAnnul( frm );
+   safe = astFree( safe );
 
 /* If an error has occurred, return zero. */
    if( !astOK ) {
diff --git a/ffitschan.c b/ffitschan.c
index 9336158..40aa78f 100644
--- a/ffitschan.c
+++ b/ffitschan.c
@@ -931,6 +931,16 @@ F77_SUBROUTINE(ast_emptyfits)( INTEGER(THIS),
    )
 }
 
+F77_SUBROUTINE(ast_showfits)( INTEGER(THIS),
+                              INTEGER(STATUS) ) {
+   GENPTR_INTEGER(THIS)
+
+   astAt( "AST_SHOWFITS", NULL, 0 );
+   astWatchSTATUS(
+      astShowFits( astI2P( *THIS ) );
+   )
+}
+
 
 F77_INTEGER_FUNCTION(ast_gettables)( INTEGER(THIS),
                                      INTEGER(STATUS) ) {
diff --git a/fitschan.c b/fitschan.c
index 371b943..20744a7 100644
--- a/fitschan.c
+++ b/fitschan.c
@@ -115,6 +115,8 @@ f     encodings), then write operations using AST_WRITE will
 *
 *     - 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?
@@ -149,6 +151,7 @@ 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
@@ -166,6 +169,7 @@ 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
@@ -1077,6 +1081,30 @@ f     - AST_WRITEFITS: Write all cards out to the sink function
 *        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.
 *class--
 */
 
@@ -1664,6 +1692,8 @@ 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 * );
@@ -1819,6 +1849,7 @@ 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 Shpc1( double, double, int, double *, double *, int * );
+static void ShowFits( AstFitsChan *, 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 * );
@@ -3807,7 +3838,6 @@ static char *CardComm( AstFitsChan *this, int *status ){
 
 *  Synopsis:
 *     #include "fitschan.h"
-
 *     char *CardComm( AstFitsChan *this, int *status )
 
 *  Class Membership:
@@ -3974,7 +4004,6 @@ static int *CardFlags( AstFitsChan *this, int *status ){
 }
 
 static char *CardName( AstFitsChan *this, int *status ){
-
 /*
 *  Name:
 *     CardName
@@ -3987,7 +4016,6 @@ static char *CardName( AstFitsChan *this, int *status ){
 
 *  Synopsis:
 *     #include "fitschan.h"
-
 *     char *CardName( AstFitsChan *this, int *status )
 
 *  Class Membership:
@@ -4032,7 +4060,6 @@ static char *CardName( AstFitsChan *this, int *status ){
 }
 
 static int CardType( AstFitsChan *this, int *status ){
-
 /*
 *  Name:
 *     CardType
@@ -4045,7 +4072,6 @@ static int CardType( AstFitsChan *this, int *status ){
 
 *  Synopsis:
 *     #include "fitschan.h"
-
 *     int CardType( AstFitsChan *this, int *status )
 
 *  Class Membership:
@@ -6484,7 +6510,6 @@ static int CnvValue( AstFitsChan *this, int type, int undef, void *buff,
 
 *  Synopsis:
 *     #include "fitschan.h"
-
 *     int CnvValue( AstFitsChan *this, int type, int undef, void *buff,
 *                   const char *method, int *status )
 
@@ -15777,6 +15802,16 @@ const char *GetAttrib( AstObject *this_object, const char *attrib, int *status )
          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" ) ) {
@@ -15999,6 +16034,105 @@ static int GetCard( AstFitsChan *this, int *status ){
    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 ){
 /*
 *+
@@ -17230,6 +17364,7 @@ void astInitFitsChanVtab_(  AstFitsChanVtab *vtab, const char *name, int *status
    vtab->FindFits = FindFits;
    vtab->KeyFields = KeyFields;
    vtab->ReadFits = ReadFits;
+   vtab->ShowFits = ShowFits;
    vtab->WriteFits = WriteFits;
    vtab->EmptyFits = EmptyFits;
    vtab->FitsEof = FitsEof;
@@ -17285,6 +17420,8 @@ void astInitFitsChanVtab_(  AstFitsChanVtab *vtab, const char *name, int *status
    vtab->SetWarnings = SetWarnings;
    vtab->GetWarnings = GetWarnings;
    vtab->GetCardType = GetCardType;
+   vtab->GetCardName = GetCardName;
+   vtab->GetCardComm = GetCardComm;
    vtab->GetNcard = GetNcard;
    vtab->GetNkey = GetNkey;
    vtab->GetAllWarnings = GetAllWarnings;
@@ -18168,11 +18305,13 @@ static AstMapping *IsMapTab1D( AstMapping *map, double scale, const char *unit,
 */
 
 /* 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 */
@@ -18184,13 +18323,20 @@ static AstMapping *IsMapTab1D( AstMapping *map, double scale, const char *unit,
    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;
@@ -18210,23 +18356,81 @@ static AstMapping *IsMapTab1D( AstMapping *map, double scale, const char *unit,
    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 ) {
 
-/* If the Mapping could not be split, try again on a copy of the Mapping
-   in which all PermMaps provide an alternative implementation of the
-   astMapSplit method. */
+/* 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;
 
-/* Revert the Mapping Invert attribute to its original value. */
-   astInvert( map );
-
 /* 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
@@ -18575,9 +18779,15 @@ static AstMapping *IsMapTab2D( AstMapping *map, double scale, const char *unit,
 */
 
 /* Local Variables: */
-   AstMapping *ret;        /* Returned WCS axis Mapping */
    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 indicies of corresponding pixel axes */
+   int wcs_axes[ 2 ];      /* Zero-based indicies of selected WCS axes */
+   int inperm[ 1 ];
+   int outperm[ 2 ];
 
 /* Initialise */
    ret = NULL;
@@ -18600,8 +18810,46 @@ static AstMapping *IsMapTab2D( AstMapping *map, double scale, const char *unit,
       *max1 = 1;
       *max2 = 1;
 
-/* Combine the Mappings in parallel to form the returned Mapping. */
-      ret = (AstMapping *) astCmpMap( ret1, ret2, 0, " ", status );
+/* 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 );
 
@@ -23425,6 +23673,7 @@ f        The global status.
 
 /* Local Variables: */
    AstObject *obj;
+   int oldclean;
 
 /* Check the global status. */
    if( !astOK ) return;
@@ -23432,6 +23681,16 @@ f        The global status.
 /* 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
@@ -23466,6 +23725,14 @@ f        The global 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 ) {
@@ -25477,6 +25744,8 @@ static void SetAttrib( AstObject *this_object, const char *setting, int *status
    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,
@@ -26287,6 +26556,85 @@ static void Shpc1( double xmin, double xmax, int n, double *d, double *w,
 
 }
 
+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:
@@ -26684,24 +27032,25 @@ static AstMapping *SIPMapping( double *dim, FitsStore *store, char s,
    } else {
       pmap = astPolyMap( 2, 2, ncoeff_f, coeff_f, ncoeff_i, coeff_i, "", status );
 
-/* If only one transformation was supplied, attempt create the other by sampling
-   the supplied transformation, and fitting a polynomial to the sampled
-   positions. If the fit fails to reach 0.1 pixel accuracy, forget it and
-   rely on the iterative inverse provided by the PolyMap class. */
-      if( ncoeff_f == 0 || ncoeff_i == 0 ){
-         lbnd[ 0 ] = 1.0;
-         lbnd[ 1 ] = 1.0;
-         ubnd[ 0 ] = dim[ 0 ] != AST__BAD ? dim[ 0 ] : 1000.0;
-         ubnd[ 1 ] = dim[ 1 ] != AST__BAD ? dim[ 1 ] : 1000.0;
-         pmap2 = astPolyTran( pmap, (ncoeff_f == 0), 0.001, 0.1, 6, lbnd,
-                              ubnd );
-         if( pmap2 ) {
-            (void) astAnnul( pmap );
-            pmap = pmap2;
-         } else {
-            astSet( pmap, "IterInverse=1,NiterInverse=6,TolInverse=1.0E-8",
-                    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
@@ -28183,7 +28532,7 @@ static AstFitsChan *SpecTrans( AstFitsChan *this, int encoding,
 *        to a CDj_is array.
 *
 *     7) EQUINOX keywords with string values equal to a date preceded
-*        by the leter B or J (eg "B1995.0"). These are converted to the
+*        by the letter B or J (eg "B1995.0"). These are converted to the
 *        corresponding Julian floating point value without any epoch
 *        specifier.
 *
@@ -31342,6 +31691,8 @@ static int TestAttrib( AstObject *this_object, const char *attrib, int *status )
    } else if ( !strcmp( attrib, "ncard" ) ||
                !strcmp( attrib, "nkey" ) ||
                !strcmp( attrib, "cardtype" ) ||
+               !strcmp( attrib, "cardcomm" ) ||
+               !strcmp( attrib, "cardname" ) ||
                !strcmp( attrib, "allwarnings" ) ){
       result = 0;
 
@@ -32826,21 +33177,6 @@ static AstMapping *WcsCelestial( AstFitsChan *this, FitsStore *store, char s,
          Warn( this, "noctype", buf, method, class, status );
       } else {
 
-/* 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;
-         }
-
 /* 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
@@ -32869,6 +33205,21 @@ static AstMapping *WcsCelestial( AstFitsChan *this, FitsStore *store, char s,
 /* 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 "
@@ -32914,6 +33265,16 @@ static AstMapping *WcsCelestial( AstFitsChan *this, FitsStore *store, char s,
          }
          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,
@@ -38176,7 +38537,6 @@ static void WriteObject( AstChannel *this_channel, const char *name,
 }
 
 static void WriteToSink( AstFitsChan *this, int *status ){
-
 /*
 *  Name:
 *     WriteToSink
@@ -38189,7 +38549,6 @@ static void WriteToSink( AstFitsChan *this, int *status ){
 
 *  Synopsis:
 *     #include "fitschan.h"
-
 *     void WriteToSink( AstFitsChan *this, int *status )
 
 *  Class Membership:
@@ -38994,15 +39353,15 @@ f     data will be written to the FitsChan and AST_WRITE will return
 *     until such time as an agreed method for describing projection
 *     distortions within FITS-WCS has been published.
 *
-*     AST extends the range of celestial coordinate sytstems which may be
-*     described using this encoding by inclusion of the allowing the use of
+*     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 leter release.
+*     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
@@ -39011,7 +39370,7 @@ f     data will be written to the FitsChan and AST_WRITE will return
 *     "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).
-*     Inaddition, the absolute coordinates description will contain
+*     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.
@@ -39443,10 +39802,7 @@ astMAKE_TEST(FitsChan,TabOK,( this->tabok != -INT_MAX ))
 *     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. Furthermore, if
-*     CarLin is non-zero, it is assumed that CDELT and CD keywords are
-*     in units of degrees rather than radians (as required by the
-*     FITS-WCS papers).
+*     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
@@ -39718,6 +40074,60 @@ 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 */
 /* ======== */
 
@@ -40589,6 +40999,9 @@ 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.
 
@@ -40646,6 +41059,10 @@ f     pointer.
    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. */
@@ -40660,6 +41077,7 @@ f     pointer.
 /* Return a pointer to the new FitsChan. */
    return new;
 }
+
 AstFitsChan *astFitsChanId_( const char *(* source)( void ),
                              void (* sink)( const char * ),
                              const char *options, ... ) {
@@ -40732,6 +41150,10 @@ AstFitsChan *astFitsChanId_( const char *(* source)( void ),
    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. */
@@ -40746,6 +41168,7 @@ AstFitsChan *astFitsChanId_( const char *(* source)( void ),
 /* 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 * ),
@@ -40913,6 +41336,10 @@ AstFitsChan *astFitsChanForId_( const char *(* source)( void ),
    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. */
@@ -40927,6 +41354,7 @@ AstFitsChan *astFitsChanForId_( const char *(* source)( void ),
 /* 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 ),
@@ -41470,6 +41898,11 @@ void astEmptyFits_( AstFitsChan *this, int *status ){
    (**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 );
@@ -41610,6 +42043,16 @@ int astGetCardType_( AstFitsChan *this, int *status ){
    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 );
diff --git a/fitschan.h b/fitschan.h
index 87dad81..0a63fe6 100644
--- a/fitschan.h
+++ b/fitschan.h
@@ -240,6 +240,7 @@ typedef struct AstFitsChanVtab {
    void (* ReadFits)( AstFitsChan *, int * );
    void (* WriteFits)( AstFitsChan *, int * );
    void (* EmptyFits)( AstFitsChan *, int * );
+   void (* ShowFits)( AstFitsChan *, int * );
    void (* PurgeWCS)( AstFitsChan *, int * );
    void (* PutCards)( AstFitsChan *, const char *, int * );
    void (* PutFits)( AstFitsChan *, const char [81], int, int * );
@@ -286,6 +287,8 @@ typedef struct AstFitsChanVtab {
    int (* GetNcard)( AstFitsChan *, int * );
 
    int (* GetCardType)( AstFitsChan *, int * );
+   const char *(* GetCardName)( AstFitsChan *, int * );
+   const char *(* GetCardComm)( AstFitsChan *, int * );
 
    int (* GetNkey)( AstFitsChan *, int * );
 
@@ -433,6 +436,7 @@ void astInitFitsChanGlobals_( AstFitsChanGlobals * );
    void astReadFits_( AstFitsChan *, int * );
    void astWriteFits_( AstFitsChan *, int * );
    void astEmptyFits_( AstFitsChan *, int * );
+   void astShowFits_( AstFitsChan *, int * );
    void astPurgeWCS_( AstFitsChan *, int * );
    void astPutCards_( AstFitsChan *, const char *, int * );
    void astPutFits_( AstFitsChan *, const char [81], int, int * );
@@ -529,6 +533,8 @@ void astInitFitsChanGlobals_( AstFitsChanGlobals * );
    int astGetNcard_( AstFitsChan *, int * );
 
    int astGetCardType_( AstFitsChan *, int * );
+   const char *astGetCardName_( AstFitsChan *, int * );
+   const char *astGetCardComm_( AstFitsChan *, int * );
 
    int astGetNkey_( AstFitsChan *, int * );
 
@@ -689,6 +695,9 @@ astINVOKE(V,astWriteFits_(astCheckFitsChan(this),STATUS_PTR))
 #define astEmptyFits(this) \
 astINVOKE(V,astEmptyFits_(astCheckFitsChan(this),STATUS_PTR))
 
+#define astShowFits(this) \
+astINVOKE(V,astShowFits_(astCheckFitsChan(this),STATUS_PTR))
+
 #define astTableSource(this,tabsource) \
 astINVOKE(V,astTableSource_(astCheckFitsChan(this),tabsource,STATUS_PTR))
 
@@ -802,6 +811,12 @@ astINVOKE(V,astGetAllWarnings_(astCheckFitsChan(this),STATUS_PTR))
 #define astGetCardType(this) \
 astINVOKE(V,astGetCardType_(astCheckFitsChan(this),STATUS_PTR))
 
+#define astGetCardName(this) \
+astINVOKE(V,astGetCardName_(astCheckFitsChan(this),STATUS_PTR))
+
+#define astGetCardComm(this) \
+astINVOKE(V,astGetCardComm_(astCheckFitsChan(this),STATUS_PTR))
+
 #define astGetNcard(this) \
 astINVOKE(V,astGetNcard_(astCheckFitsChan(this),STATUS_PTR))
 
diff --git a/fregion.c b/fregion.c
index 5e5637c..f72d51a 100644
--- a/fregion.c
+++ b/fregion.c
@@ -19,6 +19,7 @@
 *     AST_MAPREGION
 *     AST_GETREGIONBOUNDS
 *     AST_GETREGIONFRAME
+*     AST_GETREGIONFRAMESET
 *     AST_OVERLAP
 *     AST_SETUNC
 *     AST_GETUNC
@@ -116,6 +117,18 @@ F77_INTEGER_FUNCTION(ast_getregionframe)( INTEGER(THIS),
    return RESULT;
 }
 
+F77_INTEGER_FUNCTION(ast_getregionframeset)( INTEGER(THIS),
+                                             INTEGER(STATUS) ) {
+   GENPTR_INTEGER(THIS)
+   F77_INTEGER_TYPE(RESULT);
+
+   astAt( "AST_GETREGIONFRAMESET", NULL, 0 );
+   astWatchSTATUS(
+      RESULT = astP2I( astGetRegionFrameSet( astI2P( *THIS ) ) );
+   )
+   return RESULT;
+}
+
 F77_INTEGER_FUNCTION(ast_getunc)( INTEGER(THIS),
                                   LOGICAL(DEF),
                                   INTEGER(STATUS) ) {
diff --git a/interval.c b/interval.c
index 6980996..649bad5 100644
--- a/interval.c
+++ b/interval.c
@@ -72,6 +72,13 @@ f     The Interval class does not define any new routines beyond those
 *        Over-ride astRegBasePick.
 *     26-JAN-2009 (DSB):
 *        Over-ride astMapMerge.
+*     4-NOV42-2013 (DSB):
+*        - Change RegCentre so that it does not report an error for an unbounded 
+*        Interval if the centre is merely being inquired rather than set. This is 
+*        the documented behaviour of the astRegCentre method.
+*        - Modify RegPins so that it can handle uncertainty regions that straddle
+*        a discontinuity. Previously, such uncertainty Regions could have a huge
+*        bounding box resulting in matching region being far too big.
 *class--
 */
 
@@ -2569,7 +2576,7 @@ static double *RegCentre( AstRegion *this_region, double *cen, double **ptr,
       }
 
 /* If the Interval is not equivalent to a Box, report an error */
-   } else {
+   } else if( cen || ptr ) {
       astError( AST__REGCN, "astRegCentre(%s): The supplied %s is not a "
                 "closed Interval and so cannot be re-centred.", status,
                 astGetClass( this ), astGetClass( this ) );
@@ -2652,6 +2659,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    double *lbnd_tunc;        /* Lower bounds of "this" uncertainty Region */
    double *lbnd_unc;         /* Lower bounds of supplied uncertainty Region */
    double *p;                /* Pointer to next axis value */
+   double *safe;             /* An interior point in "this" */
    double *small_lbnd;       /* Lower bounds of smaller interval */
    double *small_ubnd;       /* Upper bounds of smaller interval */
    double *ubnd_tunc;        /* Upper bounds of "this" uncertainty Region */
@@ -2705,18 +2713,28 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
                 astGetNaxes( unc ), nc );
    }
 
+/* Get the centre of the region in the base Frame. We use this as a "safe"
+   interior point within the region. */
+   safe = astRegCentre( this, NULL, NULL, 0, AST__BASE );
+
 /* We now find the maximum distance on each axis that a point can be from
    the boundary of the Interval for it still to be considered to be on the
    boundary. First get the Region which defines the uncertainty within the
-   Interval being checked (in its base Frame), and get its bounding box. */
+   Interval being checked (in its base Frame), re-centre it on the interior
+   point found above (to avoid problems if the uncertainty region straddles
+   a discontinuity), and get its bounding box. */
    tunc = astGetUncFrm( this, AST__BASE );
+   if( safe ) astRegCentre( tunc, safe, NULL, 0, AST__CURRENT );
    lbnd_tunc = astMalloc( sizeof( double )*(size_t) nc );
    ubnd_tunc = astMalloc( sizeof( double )*(size_t) nc );
    astGetRegionBounds( tunc, lbnd_tunc, ubnd_tunc );
 
-/* Also get the Region which defines the uncertainty of the supplied points
-   and get its bounding box. */
+/* Also get the Region which defines the uncertainty of the supplied
+   points and get its bounding box. First re-centre the uncertainty at the
+   interior position to avoid problems from uncertainties that straddle a
+   discontinuity. */
    if( unc ) {
+      if( safe ) astRegCentre( unc, safe, NULL, 0, AST__CURRENT );
       lbnd_unc = astMalloc( sizeof( double )*(size_t) nc );
       ubnd_unc = astMalloc( sizeof( double )*(size_t) nc );
       astGetRegionBounds( unc, lbnd_unc, ubnd_unc );
@@ -2863,6 +2881,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    large_ubnd = astFree( large_ubnd );
    small_lbnd = astFree( small_lbnd );
    small_ubnd = astFree( small_ubnd );
+   safe = astFree( safe );
 
 /* If an error has occurred, return zero. */
    if( !astOK ) {
diff --git a/matrixmap.c b/matrixmap.c
index 0be7d28..5436b95 100644
--- a/matrixmap.c
+++ b/matrixmap.c
@@ -147,6 +147,9 @@ f     The MatrixMap class does not define any new routines beyond those
 *          matrix would contain only bad elements.
 *        - Report an error if an attempt is made to create a MatrixMap
 *          containing only bad elements.
+*     4-NOV-2013 (DSB):
+*        Allow a full form MatrixMap to be simplified to a diagonal form 
+*        MatrixMap if all the off-diagonal values are zero.
 *class--
 */
 
@@ -1618,6 +1621,7 @@ static int MapMerge( AstMapping *this, int where, int series, int *nmap,
    const char *class2;   /* Pointer to second Mapping class string */
    const char *nclass;   /* Pointer to neighbouring Mapping class */
    double *b;            /* Pointer to scale terms */
+   double *new_mat;      /* Pointer to elements of new MatrixMap */
    int *invlt;           /* New invert flags list pointer */
    int do1;              /* Would a backward swap make a simplification? */
    int do2;              /* Would a forward swap make a simplification? */
@@ -1626,6 +1630,7 @@ static int MapMerge( AstMapping *this, int where, int series, int *nmap,
    int i;                /* Loop counter */
    int ic[2];            /* Copies of supplied invert flags to swap */
    int invert;           /* Should the inverted Mapping be used? */
+   int j;                /* Loop counter */
    int neighbour;        /* Index of Mapping with which to swap */
    int nin;              /* Number of input coordinates for MatrixMap */
    int nmapt;            /* No. of Mappings in list */
@@ -1698,6 +1703,28 @@ static int MapMerge( AstMapping *this, int where, int series, int *nmap,
             map2 = (AstMapping *) astZoomMap( nin, (mm->f_matrix)[ 0 ], "", status );
          }
       }
+
+/* If the MatrixMap is a full matrix but all off-diagnal elements are
+   zero, it can be replaced by a diagonal MatrixMap. */
+   } else if( mm->form == FULL && nin == nout && mm->f_matrix ){
+      new_mat = astMalloc( sizeof( double )*nin );
+      b = mm->f_matrix;
+      for( i = 0; i < nin && new_mat; i++ ){
+         for( j = 0; j < nout; j++,b++ ){
+            if( i == j ) {
+               new_mat[ i ] = *b;
+            } else if( *b != 0.0 ) {
+               new_mat = astFree( new_mat );
+               break;
+            }
+         }
+      }
+
+      if( new_mat ) {
+         map2 = (AstMapping *) astMatrixMap( nin, nout, 1, new_mat, "",
+                                             status );
+         new_mat = astFree( new_mat );
+      }
    }
 
 /* If the MatrixMap can be replaced, annul the MatrixMap pointer in the
@@ -2541,7 +2568,7 @@ static void MatPermSwap( AstMapping **maps, int *inverts, int imm, int *status )
 *     void MatPermSwap( AstMapping **maps, int *inverts, int imm )
 
 *  Class Membership:
-*     WinMap member function
+*     MatrixMap member function
 
 *  Description:
 *     A list of two Mappings is supplied containing a PermMap and a
diff --git a/memory.c b/memory.c
index 2a05f98..51511ce 100644
--- a/memory.c
+++ b/memory.c
@@ -147,6 +147,8 @@
 *        not free any memory.
 *     21-NOV-2011 (DSB):
 *        Correct matchend value returned by astChrSplitRE.
+*     6-JAN-2014 (DSB):
+*        Optimise access to cache to avoid valgrind warnings.
 */
 
 /* Configuration results. */
@@ -2302,8 +2304,8 @@ void *astMalloc_( size_t size, int init, int *status ) {
 
 /* If the cache is being used and a cached memory block of the required size
    is available, remove it from the cache array and use it. */
-      mem = ( size <= MXCSIZE ) ? cache[ size ] : NULL;
-      if( use_cache && mem ) {
+      mem = ( use_cache && size <= MXCSIZE ) ? cache[ size ] : NULL;
+      if( mem ) {
          cache[ size ] = mem->next;
          mem->next = NULL;
          mem->size = (size_t) size;
@@ -4157,7 +4159,9 @@ void astActiveMemory_( const char *label ) {
    next = Active_List;
    if( next ) {
       while( next ) {
-         if( !next->perm ) printf( "%d ", next->id );
+         if( !next->perm ) {
+            printf( "%d(%s:%d) ", next->id, next->file, next->line );
+         }
          next = next->next;
       }
    } else {
@@ -4794,6 +4798,16 @@ static void Issue( Memory *mem, int *status ) {
    (i.e. each time it is remove from the cache or malloced). */
    if( !Keep_ID || mem->id < 0 ) mem->id = ++Next_ID;
 
+/* Record the file name and line number where it was issued. */
+   if( AST__GLOBALS && AST__GLOBALS->Error.Current_File ) {
+      strncpy( mem->file, AST__GLOBALS->Error.Current_File, sizeof(mem->file) );
+      mem->file[ sizeof(mem->file) - 1 ] = 0;
+      mem->line = AST__GLOBALS->Error.Current_Line;
+   } else {
+      mem->file[ 0 ] = 0;
+      mem->line = 0;
+   }
+
 /* Indicate if this is a permanent memory block (i.e. it will usually not
    be freed by AST). */
    mem->perm = Perm_Mem;
diff --git a/memory.h b/memory.h
index aa5f1f9..e92efce 100644
--- a/memory.h
+++ b/memory.h
@@ -160,6 +160,8 @@ typedef struct Memory {
    struct Memory *prev; /* Pointer to the previous linked Memory structure */
    int id;      /* A unique identifier for every allocated memory chunk */
    int perm;    /* Is this chunk part of an acceptable once-off "memory leak"? */
+   int line;    /* Line number in "file" (below). */
+   char file[50];/* The source file that made the top-level call to AST */
 #endif
 
 } Memory;
diff --git a/object.c b/object.c
index 56b90aa..b3f2cae 100644
--- a/object.c
+++ b/object.c
@@ -216,11 +216,13 @@ f     - AST_VERSION: Return the verson of the AST library being used.
 *     2-SEP-2011 (DSB):
 *        Add functions astToString and astFromString.
 *     13-SEP-2013 (DSB):
-*        Report an error in astAnnul if the supplied object handle is owned by 
+*        Report an error in astAnnul if the supplied object handle is owned by
 *        a different thread. Note, the Object itself does not need to be owned
-*        by the current thread, since it should be possible for a thread to 
-*        relinquish a pointer to an object (i.e. a handle) without actually 
-*        owning the object itself. 
+*        by the current thread, since it should be possible for a thread to
+*        relinquish a pointer to an object (i.e. a handle) without actually
+*        owning the object itself.
+*     6-JAN-2014 (DSB):
+*        Added method astEnvSet.
 *class--
 */
 
@@ -268,6 +270,7 @@ f     - AST_VERSION: Return the verson of the AST library being used.
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <limits.h>
 
@@ -451,6 +454,7 @@ static void SetID( AstObject *, const char *, int * );
 static void SetIdent( AstObject *, const char *, int * );
 static void Show( AstObject *, int * );
 static void VSet( AstObject *, const char *, char **, va_list, int * );
+static void EnvSet( AstObject *, int * );
 
 static int GetUseDefs( AstObject *, int * );
 static int TestUseDefs( AstObject *, int * );
@@ -1773,6 +1777,91 @@ static void EmptyObjectCache( int *status ){
    }
 }
 
+static void EnvSet( AstObject *this, int *status ) {
+/*
+*+
+*  Name:
+*     astEnvSet
+
+*  Purpose:
+*     Set default values for an Object's attributes.
+
+*  Type:
+*     Protected virtual function.
+
+*  Synopsis:
+*     #include "object.h"
+*     void astEnvSet( AstObject *this )
+
+*  Class Membership:
+*     Object method.
+
+*  Description:
+*     This function assigns a set of attribute values for an Object,
+*     the attributes and their values being specified by means of an
+*     environment variable of the form "<CLASSNAME>_OPTIONS" that has
+*     a value of the form:
+*
+*        "attribute1 = value1, attribute2 = value2, ... "
+*
+*     Here, "attribute" specifies an attribute name and the value to
+*     the right of each "=" sign should be a suitable textual
+*     representation of the value to be assigned to that
+*     attribute. This will be interpreted according to the attribute's
+*     data type.
+
+*  Parameters:
+*     this
+*        Pointer to the Object.
+
+*  Notes:
+*     - See astVSet for details of how the setting strings are
+*     interpreted.
+*-
+*/
+
+/* Local Variables: */
+   char varname[ 100 ];
+   const char *attrs = NULL;
+   const char *class = NULL;
+
+/* Check the global error status. */
+   if ( !astOK ) return;
+
+/* Get the string holding default attribute values for the class of the
+   supplied object. This string is held in the class virtual function
+   table. */
+   attrs = this->vtab->defaults;
+
+/* If this is the first time the defaults have been requested, get the
+   list of defaults from the environment variable "<CLASSNAME>_OPTIONS"
+   and store in the virtual function table. */
+   if( !attrs ) {
+
+/* Get the class name. */
+      class = astGetClass( this );
+
+/* Form the upper-case name of the environment variable. */
+      if( class ) {
+         sprintf( varname, "%s_OPTIONS", class );
+         astChrCase( NULL, varname, 1, sizeof( varname ) );
+
+/* Get the value of the environment variable. */
+         attrs = getenv( varname );
+
+/* If no defaults were specified store the string "None". */
+         if( ! attrs ) attrs = "None";
+
+/* Store a copy in the virtual function table. */
+         this->vtab->defaults = astStore( NULL, attrs, strlen( attrs ) + 1 );
+      }
+   }
+
+/* If any defaults were specified, set the corresponding attributes. */
+   if( attrs && strcmp( attrs, "None" ) ) astSet( this, attrs, status );
+
+}
+
 static int Equal( AstObject *this, AstObject *that, int *status ){
 /*
 *+
@@ -5300,6 +5389,7 @@ void astInitObjectVtab_(  AstObjectVtab *vtab, const char *name, int *status ) {
    vtab->TestAttrib = TestAttrib;
    vtab->TestID = TestID;
    vtab->TestIdent = TestIdent;
+   vtab->EnvSet = EnvSet;
    vtab->VSet = VSet;
    vtab->Cast = Cast;
    vtab->GetObjSize = GetObjSize;
@@ -5332,6 +5422,9 @@ void astInitObjectVtab_(  AstObjectVtab *vtab, const char *name, int *status ) {
    vtab->dump_class = NULL;
    vtab->dump_comment = NULL;
 
+/* Initialise the default attributes to use when creating objects. */
+   vtab->defaults = NULL;
+
 /* The virtual function table for each class contains a list of pointers
    to memory blocks which have previously been used to store an Object of
    the same class, but which have since been deleted using astDelete.
@@ -5736,6 +5829,10 @@ int astTestAttrib_( AstObject *this, const char *attrib, int *status ) {
    if ( !astOK ) return 0;
    return (**astMEMBER(this,Object,TestAttrib))( this, attrib, status );
 }
+void astEnvSet_( AstObject *this, int *status ) {
+   if ( !astOK ) return;
+   (**astMEMBER(this,Object,EnvSet))( this, status );
+}
 void astVSet_( AstObject *this, const char *settings, char **text, va_list args, int *status ) {
    if ( !astOK ) return;
    (**astMEMBER(this,Object,VSet))( this, settings, text, args, status );
diff --git a/object.h b/object.h
index 1960d8e..76d3b34 100644
--- a/object.h
+++ b/object.h
@@ -1328,6 +1328,11 @@ typedef struct AstObjectVtab {
    lowest-level, component). */
    AstClassIdentifier *top_id;
 
+/* Pointer to a dynamically allocated string holding the default
+   attribute values to use when creating new objects. These are read from
+   environment variables of the form "<CLASSNAME>_OPTIONS". */
+   const char *defaults;
+
 /* Properties specific to this class. */
    void ( *CleanAttribs )( AstObject *, int * );
    AstObject *( *Cast )( AstObject *, AstObject *, int * );
@@ -1350,6 +1355,7 @@ typedef struct AstObjectVtab {
    void (* SetIdent)( AstObject *, const char *, int * );
    void (* Show)( AstObject *, int * );
    void (* VSet)( AstObject *, const char *, char **, va_list, int * );
+   void (* EnvSet)( AstObject *, int * );
 
    void *(* GetProxy)( AstObject *, int * );
    void (* SetProxy)( AstObject *, void *, int * );
@@ -1540,6 +1546,7 @@ void astSetDump_( AstObjectVtab *, void (*)( AstObject *, AstChannel *, int * ),
 void astSetVtab_( AstObject *, AstObjectVtab *, int * );
 void astSetID_( AstObject *, const char *, int * );
 void astSetIdent_( AstObject *, const char *, int * );
+void astEnvSet_( AstObject *, int * );
 void astVSet_( AstObject *, const char *, char **, va_list, int * );
 
 #endif
@@ -1714,6 +1721,8 @@ astINVOKE(V,astSetVtab_((AstObject *)object,(AstObjectVtab *)(vtab),STATUS_PTR))
 #define astSetIdent(this,id) astINVOKE(V,astSetIdent_(astCheckObject(this),id,STATUS_PTR))
 #define astVSet(this,settings,text,args) \
 astINVOKE(V,astVSet_(astCheckObject(this),settings,text,args,STATUS_PTR))
+#define astEnvSet(this) \
+astINVOKE(V,astEnvSet_(astCheckObject(this),STATUS_PTR))
 #define astTestAttrib(this,attrib) \
 astINVOKE(V,astTestAttrib_(astCheckObject(this),attrib,STATUS_PTR))
 #define astTestID(this) astINVOKE(V,astTestID_(astCheckObject(this),STATUS_PTR))
diff --git a/object.h.in b/object.h.in
index fd0e009..1872f32 100644
--- a/object.h.in
+++ b/object.h.in
@@ -1328,6 +1328,11 @@ typedef struct AstObjectVtab {
    lowest-level, component). */
    AstClassIdentifier *top_id;
 
+/* Pointer to a dynamically allocated string holding the default
+   attribute values to use when creating new objects. These are read from
+   environment variables of the form "<CLASSNAME>_OPTIONS". */
+   const char *defaults;
+
 /* Properties specific to this class. */
    void ( *CleanAttribs )( AstObject *, int * );
    AstObject *( *Cast )( AstObject *, AstObject *, int * );
@@ -1350,6 +1355,7 @@ typedef struct AstObjectVtab {
    void (* SetIdent)( AstObject *, const char *, int * );
    void (* Show)( AstObject *, int * );
    void (* VSet)( AstObject *, const char *, char **, va_list, int * );
+   void (* EnvSet)( AstObject *, int * );
 
    void *(* GetProxy)( AstObject *, int * );
    void (* SetProxy)( AstObject *, void *, int * );
@@ -1540,6 +1546,7 @@ void astSetDump_( AstObjectVtab *, void (*)( AstObject *, AstChannel *, int * ),
 void astSetVtab_( AstObject *, AstObjectVtab *, int * );
 void astSetID_( AstObject *, const char *, int * );
 void astSetIdent_( AstObject *, const char *, int * );
+void astEnvSet_( AstObject *, int * );
 void astVSet_( AstObject *, const char *, char **, va_list, int * );
 
 #endif
@@ -1714,6 +1721,8 @@ astINVOKE(V,astSetVtab_((AstObject *)object,(AstObjectVtab *)(vtab),STATUS_PTR))
 #define astSetIdent(this,id) astINVOKE(V,astSetIdent_(astCheckObject(this),id,STATUS_PTR))
 #define astVSet(this,settings,text,args) \
 astINVOKE(V,astVSet_(astCheckObject(this),settings,text,args,STATUS_PTR))
+#define astEnvSet(this) \
+astINVOKE(V,astEnvSet_(astCheckObject(this),STATUS_PTR))
 #define astTestAttrib(this,attrib) \
 astINVOKE(V,astTestAttrib_(astCheckObject(this),attrib,STATUS_PTR))
 #define astTestID(this) astINVOKE(V,astTestID_(astCheckObject(this),STATUS_PTR))
diff --git a/polygon.c b/polygon.c
index de066dc..36f8449 100644
--- a/polygon.c
+++ b/polygon.c
@@ -85,6 +85,15 @@ f     - AST_OUTLINE<X>: Create a Polygon outlining values in a pixel array
 *        Added astOutline<X>.
 *     30-JUN-2009 (DSB):
 *        Override astGetBounded.
+*     4-NOV-2013 (DSB):
+*        Modify RegPins so that it can handle uncertainty regions that straddle
+*        a discontinuity. Previously, such uncertainty Regions could have a huge
+*        bounding box resulting in matching region being far too big.
+*     6-DEC-2013 (DSB):
+*        Reverse the order of the vertices when the Polygon is created,
+*        if necessary, to ensure that the unnegated Polygon is bounded.
+*        The parent Region class assumes that unnegated regions are
+*        bounded.
 *class--
 */
 
@@ -292,6 +301,7 @@ static void Cache( AstPolygon *, int * );
 static void Copy( const AstObject *, AstObject *, int * );
 static void Delete( AstObject *, int * );
 static void Dump( AstObject *, AstChannel *, int * );
+static void EnsureInside( AstPolygon *, int * );
 static void FindMax( Segment *, AstFrame *, double *, double *, int, int, int * );
 static void RegBaseBox( AstRegion *this, double *, double *, int * );
 static void ResetCache( AstRegion *this, int * );
@@ -971,6 +981,102 @@ static AstPointSet *DownsizePoly( AstPointSet *pset, double maxerr,
    return result;
 }
 
+static void EnsureInside( AstPolygon *this, int *status ){
+/*
+*  Name:
+*     EnsureInside
+
+*  Purpose:
+*     Ensure the unnegated Polygon represents the inside of the polygon.
+
+*  Type:
+*     Private function.
+
+*  Synopsis:
+*     #include "polygon.h"
+*     void EnsureInside( AstPolygon *this, int *status )
+
+*  Class Membership:
+*     Polygon member function
+
+*  Description:
+*     Reversing the order of the vertices of a Polygon is like negating
+*     the Polygon. But the parent Region class assumes that an unnegated
+*     region bounded by closed curves (e.g. boxes, circles, ellipses, etc)
+*     is bounded. So we need to have a way to ensure that a Polygon also
+*     follows this convention. So this function reverses the order of the
+*     vertices in the Polygon, if necessary, to ensure that the unnegated
+*     Polygon is bounded.
+
+*  Parameters:
+*     this
+*        The Polygon.
+*     status
+*        Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+   AstRegion *this_region;
+   double **ptr;
+   double *p;
+   double *q;
+   double tmp;
+   int bounded;
+   int i;
+   int j;
+   int jmid;
+   int negated;
+   int np;
+
+/* Check the global error status. */
+   if ( !astOK ) return;
+
+/* Is the unnegated Polygon unbounded? If so, we need to reverse the
+   vertices. */
+   bounded = astGetBounded( this );
+   negated = astGetNegated( this );
+   if( ( bounded && negated ) || ( !bounded && !negated ) ) {
+      this_region = (AstRegion *) this;
+
+/* Get a pointer to the arrays holding the coordinates at the Polygon
+   vertices. */
+      ptr = astGetPoints( this_region->points );
+
+/* Get the number of vertices. */
+      np = astGetNpoint( this_region->points );
+
+/* Store the index of the last vertex to swap. For odd "np" the central
+   vertex does not need to be swapped. */
+      jmid = np/2;
+
+/* Loop round the two axes spanned by the Polygon. */
+      for( i = 0; i < 2; i++ ) {
+
+/* Get pointers to the first pair of axis values to be swapped - i.e. the
+   first and last axis values. */
+         p = ptr[ i ];
+         q = p + np - 1;
+
+/* Loop round all pairs of axis values. */
+         for( j = 0; j < jmid; j++ ) {
+
+/* Swap the pair. */
+            tmp = *p;
+            *(p++) = *q;
+            *(q--) = tmp;
+         }
+      }
+
+/* Invert the value of the "Negated" attribute to cancel out the effect
+   of the above vertex reversal. */
+      astNegate( this );
+
+/* Indicate the cached information in the Polygon structure is stale. */
+      this->stale = 1;
+   }
+}
+
 /*
 *  Name:
 *     FindInsidePoint
@@ -3046,6 +3152,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    double **ptr1;               /* Pointer to axis values in "pset1" */
    double **ptr2;               /* Pointer to axis values in "pset2" */
    double **vptr;               /* Pointer to axis values at vertices */
+   double *safe;                /* An interior point in "this" */
    double edge_len;             /* Length of current edge */
    double end[2];               /* Position of end of current edge */
    double l1;                   /* Length of bounding box diagonal */
@@ -3112,13 +3219,19 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
 /* Create a mask array if required. */
    if( mask ) *mask = astMalloc( sizeof(int)*(size_t) np );
 
+/* Get the centre of the region in the base Frame. We use this as a "safe"
+   interior point within the region. */
+   safe = astRegCentre( this, NULL, NULL, 0, AST__BASE );
+
 /* We now find the maximum distance on each axis that a point can be from the
    boundary of the Polygon for it still to be considered to be on the boundary.
    First get the Region which defines the uncertainty within the Polygon
-   being checked (in its base Frame), and get its bounding box. The current
-   Frame of the uncertainty Region is the same as the base Frame of the
-   Polygon. */
+   being checked (in its base Frame), re-centre it on the interior point
+   found above (to avoid problems if the uncertainty region straddles a
+   discontinuity), and get its bounding box. The current Frame of the
+   uncertainty Region is the same as the base Frame of the Polygon. */
    tunc = astGetUncFrm( this, AST__BASE );
+   if( safe ) astRegCentre( tunc, safe, NULL, 0, AST__CURRENT );
    astGetRegionBounds( tunc, lbnd_tunc, ubnd_tunc );
 
 /* Find the geodesic length within the base Frame of "this" of the diagonal of
@@ -3126,9 +3239,12 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
    frm = astGetFrame( this_region->frameset, AST__BASE );
    l1 = astDistance( frm, lbnd_tunc, ubnd_tunc );
 
-/* Also get the Region which defines the uncertainty of the supplied points
-   and get its bounding box in the same Frame. */
+/* Also get the Region which defines the uncertainty of the supplied
+   points and get its bounding box. First re-centre the uncertainty at the
+   interior position to avoid problems from uncertainties that straddle a
+   discontinuity. */
    if( unc ) {
+      if( safe ) astRegCentre( unc, safe, NULL, 0, AST__CURRENT );
       astGetRegionBounds( unc, lbnd_unc, ubnd_unc );
 
 /* Find the geodesic length of the diagonal of this bounding box. */
@@ -3213,6 +3329,7 @@ static int RegPins( AstRegion *this_region, AstPointSet *pset, AstRegion *unc,
 /* Free resources. */
    tunc = astAnnul( tunc );
    frm = astAnnul( frm );
+   safe = astFree( safe );
    pset1 = astAnnul( pset1 );
    pset2 = astAnnul( pset2 );
 
@@ -4615,14 +4732,12 @@ static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
 */
 
 /* Local Variables: */
-   AstPolygon *in;                /* Pointer to input Polygon */
    AstPolygon *out;               /* Pointer to output Polygon  */
 
 /* Check the global error status. */
    if ( !astOK ) return;
 
-/* Obtain pointers to the input and output Polygons. */
-   in = (AstPolygon *) objin;
+/* Obtain pointers to the output Polygon. */
    out = (AstPolygon *) objout;
 
 /* For safety, first clear any references to the input memory from
@@ -4729,15 +4844,9 @@ static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
 *        Pointer to the inherited status variable.
 */
 
-/* Local Variables: */
-   AstPolygon *this;                 /* Pointer to the Polygon structure */
-
 /* Check the global error status. */
    if ( !astOK ) return;
 
-/* Obtain a pointer to the Polygon structure. */
-   this = (AstPolygon *) this_object;
-
 /* Write out values representing the instance variables for the
    Polygon class.  Accompany these with appropriate comment strings,
    possibly depending on the values being written.*/
@@ -5217,6 +5326,10 @@ AstPolygon *astInitPolygon_( void *mem, size_t size, int init, AstPolygonVtab *v
          new->acw = 1;
          new->stale = 1;
 
+/* Ensure the vertices are stored such that the unnegated Polygon
+   represents the inside of the polygon. */
+         EnsureInside( new, status );
+
 /* If an error occurred, clean up by deleting the new Polygon. */
          if ( !astOK ) new = astDelete( new );
       }
@@ -5375,6 +5488,10 @@ AstPolygon *astLoadPolygon_( void *mem, size_t size, AstPolygonVtab *vtab,
    current conevtion (based on STC). */
       if( ! order ) astNegate( new );
 
+/* Ensure the vertices are stored such that the unnegated Polygon
+   represents the inside of the polygon. */
+      EnsureInside( new, status );
+
 /* If an error occurred, clean up by deleting the new Polygon. */
       if ( !astOK ) new = astDelete( new );
    }
diff --git a/region.c b/region.c
index 0f12c60..79037aa 100644
--- a/region.c
+++ b/region.c
@@ -111,6 +111,8 @@ c     - astGetRegionBounds: Get the bounds of a Region
 f     - AST_GETREGIONBOUNDS: Get the bounds of a Region
 c     - astGetRegionFrame: Get a copy of the Frame represent by a Region
 f     - AST_GETREGIONFRAME: Get a copy of the Frame represent by a Region
+f     - astGetRegionFrameSet: Get a copy of the Frameset encapsulated by a Region
+f     - AST_GETREGIONFRAMESET: Get a copy of the Frameset encapsulated by a Region
 c     - astGetRegionMesh: Get a mesh of points covering a Region
 f     - AST_GETREGIONMESH: Get a mesh of points covering a Region
 c     - astGetRegionPoints: Get the positions that define a Region
@@ -213,6 +215,8 @@ f     - AST_SHOWMESH: Display a mesh of points on the surface of a Region
 *        component regions.
 *     15-JUN-2012 (DSB):
 *        Guard against division by zero in RegBase Grid if "ipr" is zero.
+*     7-NOV-2013 (DSB):
+*        Added method astGetRegionFrameSet.
 *class--
 
 *  Implementation Notes:
@@ -879,6 +883,7 @@ static int MaskUS( AstRegion *, AstMapping *, int, int, const int[], const int[]
 
 static AstAxis *GetAxis( AstFrame *, int, int * );
 static AstFrame *GetRegionFrame( AstRegion *, int * );
+static AstFrameSet *GetRegionFrameSet( AstRegion *, int * );
 static AstFrame *PickAxes( AstFrame *, int, const int[], AstMapping **, int * );
 static AstFrame *RegFrame( AstRegion *, int * );
 static AstFrameSet *Conv( AstFrameSet *, AstFrameSet *, int * );
@@ -4228,6 +4233,64 @@ f     function is invoked with STATUS set to an error value, or if it
    return result;
 }
 
+static AstFrameSet *GetRegionFrameSet( AstRegion *this, int *status ) {
+/*
+*++
+*  Name:
+c     astGetRegionFrameSet
+f     AST_GETREGIONFRAMESET
+
+*  Purpose:
+*     Obtain a pointer to the encapsulated FrameSet within a Region.
+
+*  Type:
+*     Public virtual function.
+
+*  Synopsis:
+c     #include "region.h"
+c     AstFrame *astGetRegionFrameSet( AstRegion *this )
+f     RESULT = AST_GETREGIONFRAMESET( THIS, STATUS )
+
+*  Class Membership:
+*     Region method.
+
+*  Description:
+*     This function returns a pointer to the FrameSet encapsulated by a
+*     Region. The base Frame is the Frame in which the box was originally
+*     defined, and the current Frame is the Frame into which the Region
+*     is currently mapped (i.e. it will be the same as the Frame returned
+c     by astGetRegionFrame).
+f     by AST_GETREGIONFRAME).
+
+*  Parameters:
+c     this
+f     THIS = INTEGER (Given)
+*        Pointer to the Region.
+f     STATUS = INTEGER (Given and Returned)
+f        The global status.
+
+*  Returned Value:
+c     astGetRegionFrameSet()
+f     AST_GETREGIONFRAMESET = INTEGER
+*        A pointer to a deep copy of the FrameSet represented by the Region.
+*        Using this pointer to modify the FrameSet will have no effect on
+*        the Region.
+
+*  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.
+*--
+*/
+
+/* Check the global error status. */
+   if ( !astOK ) return NULL;
+
+/* Return a deep copy of the encapsulated FrameSet. */
+   return astCopy( this->frameset );
+}
+
 void astInitRegionVtab_(  AstRegionVtab *vtab, const char *name, int *status ) {
 /*
 *+
@@ -4328,6 +4391,7 @@ void astInitRegionVtab_(  AstRegionVtab *vtab, const char *name, int *status ) {
    vtab->TestUnc = TestUnc;
    vtab->ClearUnc = ClearUnc;
    vtab->GetRegionFrame = GetRegionFrame;
+   vtab->GetRegionFrameSet = GetRegionFrameSet;
    vtab->MapRegion = MapRegion;
    vtab->Overlap = Overlap;
    vtab->OverlapX = OverlapX;
@@ -12753,6 +12817,10 @@ AstFrame *astGetRegionFrame_( AstRegion *this, int *status ){
    if ( !astOK ) return NULL;
    return (**astMEMBER(this,Region,GetRegionFrame))( this, status );
 }
+AstFrameSet *astGetRegionFrameSet_( AstRegion *this, int *status ){
+   if ( !astOK ) return NULL;
+   return (**astMEMBER(this,Region,GetRegionFrameSet))( this, status );
+}
 AstRegion *astMapRegion_( AstRegion *this, AstMapping *map, AstFrame *frame, int *status ){
    if ( !astOK ) return NULL;
    return (**astMEMBER(this,Region,MapRegion))( this, map, frame, status );
diff --git a/region.h b/region.h
index 6fdea96..8c68ce8 100644
--- a/region.h
+++ b/region.h
@@ -122,6 +122,7 @@ typedef struct AstRegionVtab {
    int (* OverlapX)( AstRegion *, AstRegion *, int * );
    AstRegion *(* MapRegion)( AstRegion *, AstMapping *, AstFrame *, int * );
    AstFrame *(* GetRegionFrame)( AstRegion *, int * );
+   AstFrameSet *(* GetRegionFrameSet)( AstRegion *, int * );
    AstFrame *(* RegFrame)( AstRegion *, int * );
    AstFrameSet *(* GetRegFS)( AstRegion *, int * );
    AstPointSet *(* RegTransform)( AstRegion *, AstPointSet *, int, AstPointSet *, AstFrame **, int * );
@@ -250,6 +251,7 @@ void astInitRegionGlobals_( AstRegionGlobals * );
 /* -------------------------------- */
 
 AstFrame *astGetRegionFrame_( AstRegion *, int * );
+AstFrameSet *astGetRegionFrameSet_( AstRegion *, int * );
 int astOverlap_( AstRegion *, AstRegion *, int * );
 void astNegate_( AstRegion *, int * );
 
@@ -383,6 +385,8 @@ astINVOKE(O,astLoadRegion_(mem,size,vtab,name,astCheckChannel(channel),STATUS_PT
    of object is supplied. */
 #define astGetRegionFrame(this) \
 astINVOKE(O,astGetRegionFrame_(astCheckRegion(this),STATUS_PTR))
+#define astGetRegionFrameSet(this) \
+astINVOKE(O,astGetRegionFrameSet_(astCheckRegion(this),STATUS_PTR))
 #define astNegate(this) \
 astINVOKE(V,astNegate_(astCheckRegion(this),STATUS_PTR))
 #define astOverlap(this,that) \
diff --git a/skyframe.c b/skyframe.c
index e8b3da2..e0432c1 100644
--- a/skyframe.c
+++ b/skyframe.c
@@ -325,6 +325,11 @@ f     - AST_SKYOFFSETMAP: Obtain a Mapping from absolute to offset coordinates
 *        poorer accuracy, and small variations in interpolated LAST value
 *        depending on the way the cached values are distributed amongst the
 *        N threads.
+*     6-AST-2013 (DSB):
+*        Fix the use of the read-write lock that is used to serialise
+*        access to the table of cached LAST values. This bug could
+*        cause occasional problems where an AST pointer would became
+*        invalid for no apparent reason.
 *class--
 */
 
@@ -8680,6 +8685,10 @@ static void SetCachedLAST( AstSkyFrame *this, double last, double epoch,
 /* Check the global error status. */
    if ( !astOK ) return;
 
+/* Ensure no threads are allowed to read the table whilst we are writing
+   to it. */
+   LOCK_WLOCK1
+
 /* Loop round every LAST table held in the vtab. Each table refers to a
    different observatory position and/or DUT1 value. */
    for( itable = 0; itable < nlast_tables; itable++ ) {
@@ -8696,10 +8705,6 @@ static void SetCachedLAST( AstSkyFrame *this, double last, double epoch,
       table = NULL;
    }
 
-/* Ensure no threads are allowed to read the table whilst we are writing
-   to it. */
-   LOCK_RLOCK1
-
 /* If no table was found, create one now, and add it into the vtab cache. */
    if( !table ) {
 
diff --git a/slamap.c b/slamap.c
index ce1288a..b8eeb1f 100644
--- a/slamap.c
+++ b/slamap.c
@@ -49,6 +49,8 @@ f     - AST_SLAADD: Add a celestial coordinate conversion to an SlaMap
 *  Copyright:
 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
 *     Research Councils
+*     Copyright (C) 2013 Science & Technology Facilities Council.
+*     All Rights Reserved.
 
 *  Licence:
 *     This program is free software; you can redistribute it and/or
@@ -109,6 +111,10 @@ f     - AST_SLAADD: Add a celestial coordinate conversion to an SlaMap
 *        aberration vector.
 *        - Correct bug in the simplification of adjacent AMP and MAP
 *        conversions.
+*     15-NOV-2013 (DSB):
+*        Fix bug in merging of adjacent AMP and MAP conversions (MapMerge
+*        did not take account of the fact that the arguments for these
+*        two conversions are stored in swapped order).
 
 *class--
 */
@@ -2963,9 +2969,9 @@ static int MapMerge( AstMapping *this, int where, int series, int *nmap,
                } else if ( ( PAIR_CVT( AST__SLA_AMP, AST__SLA_MAP ) ||
                              PAIR_CVT( AST__SLA_MAP, AST__SLA_AMP ) ) &&
                            EQUAL( cvtargs[ istep ][ 0 ],
-                                  cvtargs[ istep + 1 ][ 0 ] ) &&
+                                  cvtargs[ istep + 1 ][ 1 ] ) &&
                            EQUAL( cvtargs[ istep ][ 1 ],
-                                  cvtargs[ istep + 1 ][ 1 ] ) ) {
+                                  cvtargs[ istep + 1 ][ 0 ] ) ) {
                   istep++;
                   keep = 0;
 
diff --git a/sphmap.c b/sphmap.c
index 915d278..6c7415c 100644
--- a/sphmap.c
+++ b/sphmap.c
@@ -75,6 +75,10 @@ f     The SphMap class does not define any new routines beyond those
 *        Added PolarLong attribute.
 *     10-MAY-2006 (DSB):
 *        Override astEqual.
+*     5-NOV-2013 (DSB):
+*        Modify MapMerge so that it can spot and simplify an
+*        (inverted SphMap,MatrixMap,SphMap) sequence in which the
+*        MatrixMap just magnifies or reflects the radius vector.
 *class--
 */
 
@@ -330,7 +334,7 @@ static int Equal( AstObject *this_object, AstObject *that_object, int *status )
          if( astGetInvert( this ) == astGetInvert( that ) ) {
 
             if( astEQUAL( this->polarlong, that->polarlong ) &&
-                this->unitradius == that->unitradius ){
+                          this->unitradius == that->unitradius ){
                result = 1;
             }
 
@@ -695,7 +699,12 @@ static int MapMerge( AstMapping *this, int where, int series, int *nmap,
 
 /* Local Variables: */
    AstMapping *new;              /* Pointer to replacement Mapping */
+   AstMatrixMap *mm;             /* Pointer to MatrixMap */
+   AstWinMap *wm;                /* The new WinMap */
    const char *class;            /* Pointer to Mapping class string */
+   double absval;                /* Absolute value fo each diagonal element */
+   double diag[ 3 ];             /* The diagonal matrix elements */
+   double polarlong;             /* Value of PolarLong attribute */
    int imap1;                    /* Index of first SphMap */
    int imap2;                    /* Index of second SphMap */
    int imap;                     /* Loop counter for Mappings */
@@ -730,8 +739,8 @@ static int MapMerge( AstMapping *this, int where, int series, int *nmap,
    the second in the forward direction. This combination can be
    simplified if the PolarLongitude attributes are equal.. */
          if( ( *invert_list )[ imap1 ] && !( *invert_list )[ imap2 ] ) {
-            simpler = ( astGetPolarLong( ( *map_list )[ imap1 ] ) ==
-                        astGetPolarLong( ( *map_list )[ imap2 ] ) );
+            simpler = astEQUAL( astGetPolarLong( ( *map_list )[ imap1 ] ),
+                                astGetPolarLong( ( *map_list )[ imap2 ] ) );
 
 /* If the first SphMap is applied in the forward direction and the second in
    the inverse direction, the combination can only be simplified if the
@@ -776,6 +785,156 @@ static int MapMerge( AstMapping *this, int where, int series, int *nmap,
       }
    }
 
+/* Another possible simplification is if the nominated Mapping is an inverted
+   SphMap followed in series by a ZoomMap or diagonal MatrixMap that has
+   diagonal elements of equal magnitude, which is then followed by a
+   non-inverted SphMap. This is equivalent to a 3D rotation of a pair of
+   (longitude,latitude) angles. The MatrixMap/ZoomMap may magnify the
+   radius vector, but this will not alter the angles. Any difference in
+   signs amongst the diagonal elements will cause a reflection or reversal
+   of the corresponbding angles, which can be represented by a WinMap. We
+   do not need to consider the other possibility (that the nominated
+   SphMap is the *last* Mapping in such a sequence of three), since we
+   will already have discovered such a sequence on an earlier invocation
+   of this function. */
+   if( series && !simpler && ( *invert_list )[ where ] &&
+       where + 2 < *nmap  ) {
+
+/* Check the third Mapping is a non-inverted SphMap. */
+      class = astGetClass( ( *map_list )[ where + 2 ] );
+      if( astOK && !strcmp( class, "SphMap" ) &&
+          !( *invert_list )[ where + 2 ] ) {
+
+/* Check the second Mapping is a ZoomMap, or a diagonal MatrixMap that
+   has diagonal elements of equal magnitude. Since the Mapping is
+   sandwiched between the two SphMaps, we know it must have 3 inputs and
+   3 outputs. Record the corresponding diagonal values. The state of the
+   Invert flag does not matter since it will only affect the degree to
+   which the radius vector is magnified - it will not change the signs of
+   any diagonal elements. */
+         class = astGetClass( ( *map_list )[ where + 1 ] );
+         if( astOK && !strcmp( class, "ZoomMap" ) ) {
+            diag[ 0 ] = astGetZoom( ( *map_list )[ where + 1 ] );
+            if( diag[ 0 ] != 0.0 ) {
+               diag[ 1 ] = diag[ 0 ];
+               diag[ 2 ] = diag[ 0 ];
+            } else {
+               class = NULL;
+            }
+
+         } else if( astOK && !strcmp( class, "MatrixMap" ) ) {
+            mm = (AstMatrixMap *)  ( *map_list )[ where + 1 ];
+            if( mm->form == 1 && mm->f_matrix ) {
+               diag[ 0 ] = mm->f_matrix[ 0 ];
+               if( diag[ 0 ] != 0.0 ) {
+                  diag[ 1 ] = mm->f_matrix[ 1 ];
+                  diag[ 2 ] = mm->f_matrix[ 2 ];
+
+                  absval = fabs( diag[ 0 ] );
+                  if( !astEQUAL( fabs( diag[ 1 ] ), absval ) ||
+                      !astEQUAL( fabs( diag[ 2 ] ), absval ) ) {
+                     class = NULL;
+                  }
+
+               } else {
+                  class = NULL;
+               }
+
+            } else {
+               class = NULL;
+            }
+
+         } else {
+            class = NULL;
+         }
+
+      } else {
+         class = NULL;
+      }
+
+/* We can only make changes if above conditions were met. */
+      if( class ) {
+
+/* Create a WinMap that modifies the (longitude,latitude) values, initially
+   with undefined corners. */
+         wm = astWinMap( 2, NULL, NULL, NULL, NULL, "", status );
+
+/* Store appropriate scales and offsets in the WinMap. These just depend on
+   the signs of the matrix diagonal elements since we know the magnitudes of
+   these elements are all equal. */
+         if( diag[ 0 ] < 0.0 ) {
+            if( diag[ 1 ] < 0.0 ) {
+               wm->a[ 0 ] = AST__DPI;
+               wm->b[ 0 ] = -1.0;
+            } else {
+               wm->a[ 0 ] = AST__DPI;
+               wm->b[ 0 ] = 1.0;
+            }
+
+         } else {
+            if( diag[ 1 ] < 0.0 ) {
+               wm->a[ 0 ] = 0.0;
+               wm->b[ 0 ] = -1.0;
+            } else {
+               wm->a[ 0 ] = 0.0;
+               wm->b[ 0 ] = 1.0;
+            }
+         }
+
+         if( diag[ 2 ] < 0.0 ) {
+            wm->a[ 1 ] = 0.0;
+            wm->b[ 1 ] = -1.0;
+         } else {
+            wm->a[ 1 ] = 0.0;
+            wm->b[ 1 ] = 1.0;
+         }
+
+/* We are aiming to replace the supplied (SphMap,MatrixMap,SphMap)
+   combination with (WinMap,SphMap,SphMap), leaving us with an inverted
+   and non-inverted SphMap side by side. This is on the understanding
+   that a subsequent call to this function will combine these two
+   adjacent SphMaps into a UnitMap. But this will only happen if the
+   adjacent SphMaps have equal values for their PolarLong attributes. The
+   change of (SphMap,MatrixMap) to (WinMap,SphMap) will change the value
+   of the PolarLong attribute in the first SphMap, so we need to work out
+   this changed value and check that it is the same as the PolarLong
+   value of the second SphMap. If they are different, there is no point
+   making any changes since the two SphMaps cannot be merged into a
+   UnitMap. So get the PolarLong value from the supplied first SphMap. */
+         polarlong = astGetPolarLong( ( *map_list )[ where ] );
+
+/* Modified the PolarLong value to take account of the change from
+   (SphMap,MatrixMap) to (WinMap,SphMap). */
+         polarlong =  wm->a[ 0 ] + wm->b[ 0 ]*polarlong;
+
+/* Check this is the same as the PolarLong value in the second SphMap. */
+         if( astEQUAL( polarlong, astGetPolarLong( ( *map_list )[ where + 2 ] ) ) ) {
+
+/* All is good, so we can now change the supplied Mappings list. First
+   change the PolarLong value in the first SphMap. */
+            astSetPolarLong( ( *map_list )[ where ], polarlong );
+
+/* Annul The MatrixMap or ZoomMap. */
+            (void) astAnnul( ( *map_list )[ where + 1 ] );
+
+/* Move the first SphMap to the slot left vacant by the annulled
+   MatrixMap or ZoomMap. */
+            ( *map_list )[ where + 1 ] = ( *map_list )[ where ];
+            ( *invert_list )[ where + 1 ] = ( *invert_list )[ where ];
+
+/* Store the new WinMap in the place of the SphMap. */
+            ( *map_list )[ where ] = astClone( wm );
+            ( *invert_list )[ where ] = 0;
+
+/* Return the index of the first modified element. */
+            result = where;
+         }
+
+/* Free resources. */
+         wm = astAnnul( wm );
+      }
+   }
+
 /* If an error occurred, clear the returned result. */
    if ( !astOK ) result = -1;
 
diff --git a/sun210.tex b/sun210.tex
index cb9ee66..ca6b9f9 100644
--- a/sun210.tex
+++ b/sun210.tex
@@ -16072,6 +16072,9 @@ Object             - Base class for all AST Objects
          list of attribute assignments to be used for initialising the
          new FitsChan. The syntax used is identical to that for the
          \htmlref{AST\_SET}{AST_SET} routine.
+
+         Note, the FITSCHAN\_OPTIONS environment variable may be used
+         to specify default options for all newly created FitsChans.
       }
       \sstsubsection{
          STATUS = INTEGER (Given and Returned)
@@ -17367,6 +17370,52 @@ Object             - Base class for all AST Objects
    }
 }
 \sstroutine{
+   AST\_GETREGIONFRAMESET\sstlabel{AST_GETREGIONFRAMESET}
+}{
+   Obtain a pointer to the encapsulated FrameSet within a Region
+}{
+   \sstdescription{
+      This function returns a pointer to the \htmlref{FrameSet}{FrameSet} encapsulated by a
+      \htmlref{Region}{Region}. The base \htmlref{Frame}{Frame} is the Frame in which the box was originally
+      defined, and the current Frame is the Frame into which the Region
+      is currently mapped (i.e. it will be the same as the Frame returned
+      by \htmlref{AST\_GETREGIONFRAME}{AST_GETREGIONFRAME}).
+   }
+   \sstinvocation{
+      RESULT = AST\_GETREGIONFRAMESET( THIS, STATUS )
+   }
+   \sstarguments{
+      \sstsubsection{
+         THIS = INTEGER (Given)
+      }{
+         Pointer to the Region.
+      }
+      \sstsubsection{
+         STATUS = INTEGER (Given and Returned)
+      }{
+         The global status.
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         AST\_GETREGIONFRAMESET = INTEGER
+      }{
+         A pointer to a deep copy of the FrameSet represented by the Region.
+         Using this pointer to modify the FrameSet will have no effect on
+         the Region.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         A null \htmlref{Object}{Object} pointer (AST\_\_NULL) will be returned if this
+         function is invoked with STATUS set to an error value, or if it
+         should fail for any reason.
+      }
+   }
+}
+\sstroutine{
    AST\_GETREGIONMESH\sstlabel{AST_GETREGIONMESH}
 }{
    Return a mesh of points covering the surface or volume of a Region
@@ -28855,6 +28904,31 @@ Object             - Base class for all AST Objects
    }
 }
 \sstroutine{
+   AST\_SHOWFITS\sstlabel{AST_SHOWFITS}
+}{
+   Display the contents of a FitsChan on standard output
+}{
+   \sstdescription{
+      This routine
+      formats and displays all the cards in a \htmlref{FitsChan}{FitsChan} on standard output.
+   }
+   \sstinvocation{
+      CALL AST\_SHOWFITS( THIS, STATUS )
+   }
+   \sstarguments{
+      \sstsubsection{
+         THIS = INTEGER (Given)
+      }{
+         Pointer to the FitsChan.
+      }
+      \sstsubsection{
+         STATUS = INTEGER (Given and Returned)
+      }{
+         The global status.
+      }
+   }
+}
+\sstroutine{
    AST\_SHOWMESH\sstlabel{AST_SHOWMESH}
 }{
    Display a mesh of points covering the surface of a Region
@@ -34394,10 +34468,7 @@ Object             - Base class for all AST Objects
       coordinates to celestial coordinates is a simple linear transformation
       (hence the attribute name {\tt{"}}CarLin{\tt{"}}). This is appropriate for some older
       FITS data which claims to have a {\tt{"}}CAR{\tt{"}} projection, but which in fact do
-      not conform to the conventions of the FITS-WCS paper. Furthermore, if
-      CarLin is non-zero, it is assumed that CDELT and CD keywords are
-      in units of degrees rather than radians (as required by the
-      FITS-WCS papers).
+      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 {\tt{"}}native spherical
@@ -34455,6 +34526,46 @@ Object             - Base class for all AST Objects
    }
 }
 \sstroutine{
+   CardComm\sstlabel{CardComm}
+}{
+   The comment for the current card in a FitsChan
+}{
+   \sstdescription{
+      This attribute gives the comment for the current card of the
+      \htmlref{FitsChan}{FitsChan}. A zero-length string is returned if the card has no comment.
+   }
+   \sstattributetype{
+      String, read-only.
+   }
+   \sstapplicability{
+      \sstsubsection{
+         FitsChan
+      }{
+         All FitsChans have this attribute.
+      }
+   }
+}
+\sstroutine{
+   CardName\sstlabel{CardName}
+}{
+   The keyword name of the current card in a FitsChan
+}{
+   \sstdescription{
+      This attribute gives the name of the keyword for the
+      current card of the \htmlref{FitsChan}{FitsChan}.
+   }
+   \sstattributetype{
+      String, read-only.
+   }
+   \sstapplicability{
+      \sstsubsection{
+         FitsChan
+      }{
+         All FitsChans have this attribute.
+      }
+   }
+}
+\sstroutine{
    CardType\sstlabel{CardType}
 }{
    The data type of the current card in a FitsChan
@@ -35695,15 +35806,15 @@ Object             - Base class for all AST Objects
       until such time as an agreed method for describing projection
       distortions within FITS-WCS has been published.
 
-      AST extends the range of celestial coordinate sytstems which may be
-      described using this encoding by inclusion of the allowing the use of
+      AST extends the range of celestial coordinate systems which may be
+      described using this encoding by allowing the inclusion of
       {\tt{"}}AZ--{\tt{"}} and {\tt{"}}EL--{\tt{"}} 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 leter release.
+      These may be added in a later release.
 
       If an AST SkyFrame that represents offset rather than absolute
       coordinates (see attribute \htmlref{SkyRefIs}{SkyRefIs}) is written to a FitsChan using
@@ -35712,7 +35823,7 @@ Object             - Base class for all AST Objects
       {\tt{"}}OFLT{\tt{"}} as the axis codes in the CTYPE keywords. The other will
       describe absolute coordinates as specified by the \htmlref{System}{System} attribute
       of the SkyFrame, using the usual CTYPE codes ({\tt{"}}RA--{\tt{"}}/{\tt{"}}DEC-{\tt{"}}, etc).
-      Inaddition, the absolute coordinates description will contain
+      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.
@@ -43631,6 +43742,12 @@ Object             - Base class for all AST Objects
          \htmlref{Card}{Card}: Index of current FITS card in a FitsChan
 
          \sstitem
+         \htmlref{CardComm}{CardComm}: The comment of the current FITS card in a FitsChan
+
+         \sstitem
+         \htmlref{CardName}{CardName}: The keyword name of the current FITS card in a FitsChan
+
+         \sstitem
          \htmlref{CardType}{CardType}: The data type of the current FITS card in a FitsChan
 
          \sstitem
@@ -45763,6 +45880,12 @@ Object             - Base class for all AST Objects
          \htmlref{AST\_GETREGIONFRAME}{AST_GETREGIONFRAME}: Get a copy of the Frame represent by a Region
 
          \sstitem
+         astGetRegionFrameSet: Get a copy of the Frameset encapsulated by a Region
+
+         \sstitem
+         \htmlref{AST\_GETREGIONFRAMESET}{AST_GETREGIONFRAMESET}: Get a copy of the Frameset encapsulated by a Region
+
+         \sstitem
          \htmlref{AST\_GETREGIONMESH}{AST_GETREGIONMESH}: Get a mesh of points covering a Region
 
          \sstitem
@@ -50642,12 +50765,10 @@ certain FITS headers that use a TNX projection.
 
 \end{enumerate}
 
-\subsection{\xlabel{changes}\xlabel{list_of_most_recent_changes}Changes
-Introduced in V7.3.2}
+\subsection{Changes Introduced in V7.3.2}
 
-The following describes the most significant changes which have
-occurred in the AST library between versions V7.3.1 and V7.3.2 (the
-current version):
+The following describes the most significant changes which
+occurred in the AST library between versions V7.3.1 and V7.3.2:
 
 \begin{enumerate}
 
@@ -50665,6 +50786,28 @@ FITS header, if the corresponding CTYPE values included no projection code.
 
 \end{enumerate}
 
+\subsection{\xlabel{changes}\xlabel{list_of_most_recent_changes}Changes
+Introduced in V7.3.3}
+
+The following describes the most significant changes which have
+occurred in the AST library between versions V7.3.2 and V7.3.3 (the
+current version):
+
+\begin{enumerate}
+
+\item The \htmlref{FitsChan}{FitsChan} class has new attributes \htmlref{CardName}{CardName} and \htmlref{CardComm}{CardComm}, which hold
+the keyword name and comment of the current card.
+
+\item When using the FitsChan class to read FITS-WCS headers that include
+polynomial distortion in the SIP format, any inverse transformation specified
+in the header is now ignored and a new inverse is created to replace it based
+on the supplied forward transformation. Previously, an inverse was created
+only if the header did not include an inverse. The accuracy of the inverse
+transformation has also been improved, although it may now be slower to
+evaluate in some circumstances.
+
+\end{enumerate}
+
 Programs which are statically linked will need to be re-linked in
 order to take advantage of these new facilities.
 
diff --git a/sun211.tex b/sun211.tex
index 7eebd07..0cf85ae 100644
--- a/sun211.tex
+++ b/sun211.tex
@@ -16608,6 +16608,9 @@ Object             - Base class for all AST Objects
          specifiers. The rules for supplying these are identical to
          those for the astSet function (and for the C {\tt{"}}printf{\tt{"}}
          function).
+
+         Note, the FITSCHAN\_OPTIONS environment variable may be used
+         to specify default options for all newly created FitsChans.
       }
    }
    \sstreturnedvalue{
@@ -17857,6 +17860,47 @@ Object             - Base class for all AST Objects
    }
 }
 \sstroutine{
+   astGetRegionFrameSet\sstlabel{astGetRegionFrameSet}
+}{
+   Obtain a pointer to the encapsulated FrameSet within a Region
+}{
+   \sstdescription{
+      This function returns a pointer to the \htmlref{FrameSet}{FrameSet} encapsulated by a
+      \htmlref{Region}{Region}. The base \htmlref{Frame}{Frame} is the Frame in which the box was originally
+      defined, and the current Frame is the Frame into which the Region
+      is currently mapped (i.e. it will be the same as the Frame returned
+      by \htmlref{astGetRegionFrame}{astGetRegionFrame}).
+   }
+   \sstsynopsis{
+      AstFrame $*$astGetRegionFrameSet( AstRegion $*$this )
+   }
+   \sstparameters{
+      \sstsubsection{
+         this
+      }{
+         Pointer to the Region.
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         astGetRegionFrameSet()
+      }{
+         A pointer to a deep copy of the FrameSet represented by the Region.
+         Using this pointer to modify the FrameSet will have no effect on
+         the Region.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         A null \htmlref{Object}{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.
+      }
+   }
+}
+\sstroutine{
    astGetRegionMesh\sstlabel{astGetRegionMesh}
 }{
    Return a mesh of points covering the surface or volume of a Region
@@ -29392,6 +29436,26 @@ Object             - Base class for all AST Objects
    }
 }
 \sstroutine{
+   astShowFits\sstlabel{astShowFits}
+}{
+   Display the contents of a FitsChan on standard output
+}{
+   \sstdescription{
+      This function
+      formats and displays all the cards in a \htmlref{FitsChan}{FitsChan} on standard output.
+   }
+   \sstsynopsis{
+      void astShowFits( AstFitsChan $*$this )
+   }
+   \sstparameters{
+      \sstsubsection{
+         this
+      }{
+         Pointer to the FitsChan.
+      }
+   }
+}
+\sstroutine{
    astShowMesh\sstlabel{astShowMesh}
 }{
    Display a mesh of points covering the surface of a Region
@@ -35328,10 +35392,7 @@ Object             - Base class for all AST Objects
       coordinates to celestial coordinates is a simple linear transformation
       (hence the attribute name {\tt{"}}CarLin{\tt{"}}). This is appropriate for some older
       FITS data which claims to have a {\tt{"}}CAR{\tt{"}} projection, but which in fact do
-      not conform to the conventions of the FITS-WCS paper. Furthermore, if
-      CarLin is non-zero, it is assumed that CDELT and CD keywords are
-      in units of degrees rather than radians (as required by the
-      FITS-WCS papers).
+      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 {\tt{"}}native spherical
@@ -35389,6 +35450,46 @@ Object             - Base class for all AST Objects
    }
 }
 \sstroutine{
+   CardComm\sstlabel{CardComm}
+}{
+   The comment for the current card in a FitsChan
+}{
+   \sstdescription{
+      This attribute gives the comment for the current card of the
+      \htmlref{FitsChan}{FitsChan}. A zero-length string is returned if the card has no comment.
+   }
+   \sstattributetype{
+      String, read-only.
+   }
+   \sstapplicability{
+      \sstsubsection{
+         FitsChan
+      }{
+         All FitsChans have this attribute.
+      }
+   }
+}
+\sstroutine{
+   CardName\sstlabel{CardName}
+}{
+   The keyword name of the current card in a FitsChan
+}{
+   \sstdescription{
+      This attribute gives the name of the keyword for the
+      current card of the \htmlref{FitsChan}{FitsChan}.
+   }
+   \sstattributetype{
+      String, read-only.
+   }
+   \sstapplicability{
+      \sstsubsection{
+         FitsChan
+      }{
+         All FitsChans have this attribute.
+      }
+   }
+}
+\sstroutine{
    CardType\sstlabel{CardType}
 }{
    The data type of the current card in a FitsChan
@@ -36630,15 +36731,15 @@ Object             - Base class for all AST Objects
       until such time as an agreed method for describing projection
       distortions within FITS-WCS has been published.
 
-      AST extends the range of celestial coordinate sytstems which may be
-      described using this encoding by inclusion of the allowing the use of
+      AST extends the range of celestial coordinate systems which may be
+      described using this encoding by allowing the inclusion of
       {\tt{"}}AZ--{\tt{"}} and {\tt{"}}EL--{\tt{"}} 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 leter release.
+      These may be added in a later release.
 
       If an AST SkyFrame that represents offset rather than absolute
       coordinates (see attribute \htmlref{SkyRefIs}{SkyRefIs}) is written to a FitsChan using
@@ -36647,7 +36748,7 @@ Object             - Base class for all AST Objects
       {\tt{"}}OFLT{\tt{"}} as the axis codes in the CTYPE keywords. The other will
       describe absolute coordinates as specified by the \htmlref{System}{System} attribute
       of the SkyFrame, using the usual CTYPE codes ({\tt{"}}RA--{\tt{"}}/{\tt{"}}DEC-{\tt{"}}, etc).
-      Inaddition, the absolute coordinates description will contain
+      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.
@@ -44572,6 +44673,12 @@ Object             - Base class for all AST Objects
          \htmlref{Card}{Card}: Index of current FITS card in a FitsChan
 
          \sstitem
+         \htmlref{CardComm}{CardComm}: The comment of the current FITS card in a FitsChan
+
+         \sstitem
+         \htmlref{CardName}{CardName}: The keyword name of the current FITS card in a FitsChan
+
+         \sstitem
          \htmlref{CardType}{CardType}: The data type of the current FITS card in a FitsChan
 
          \sstitem
@@ -44662,6 +44769,9 @@ Object             - Base class for all AST Objects
          \htmlref{astSetFits$<$X$>$}{astSetFitsX}: Store a new keyword value in a FitsChan
 
          \sstitem
+         \htmlref{astShowFits}{astShowFits}: Display the contents of a FitsChan on standard output
+
+         \sstitem
          \htmlref{astTableSource}{astTableSource}: Register a source function for FITS table access
 
          \sstitem
@@ -44669,6 +44779,9 @@ Object             - Base class for all AST Objects
 
          \sstitem
          \htmlref{astWriteFits}{astWriteFits}: Write all cards out to the sink function
+
+         \sstitem
+         AST\_SHOWFITS: Display the contents of a FitsChan on standard output
       }
    }
 }
@@ -52880,12 +52993,10 @@ certain FITS headers that use a TNX projection.
 
 \end{enumerate}
 
-\subsection{\xlabel{changes}\xlabel{list_of_most_recent_changes}Changes
-Introduced in V7.3.2}
+\subsection{Changes Introduced in V7.3.2}
 
-The following describes the most significant changes which have
-occurred in the AST library between versions V7.3.1 and V7.3.2 (the
-current version):
+The following describes the most significant changes which
+occurred in the AST library between versions V7.3.1 and V7.3.2:
 
 \begin{enumerate}
 
@@ -52903,6 +53014,28 @@ FITS header, if the corresponding CTYPE values included no projection code.
 
 \end{enumerate}
 
+\subsection{\xlabel{changes}\xlabel{list_of_most_recent_changes}Changes
+Introduced in V7.3.3}
+
+The following describes the most significant changes which have
+occurred in the AST library between versions V7.3.2 and V7.3.3 (the
+current version):
+
+\begin{enumerate}
+
+\item The \htmlref{FitsChan}{FitsChan} class has new attributes \htmlref{CardName}{CardName} and \htmlref{CardComm}{CardComm}, which hold
+the keyword name and comment of the current card.
+
+\item When using the FitsChan class to read FITS-WCS headers that include
+polynomial distortion in the SIP format, any inverse transformation specified
+in the header is now ignored and a new inverse is created to replace it based
+on the supplied forward transformation. Previously, an inverse was created
+only if the header did not include an inverse. The accuracy of the inverse
+transformation has also been improved, although it may now be slower to
+evaluate in some circumstances.
+
+\end{enumerate}
+
 Programs which are statically linked will need to be re-linked in
 order to take advantage of these new facilities.
 
diff --git a/table.c b/table.c
index 96e0ca6..ece3b14 100644
--- a/table.c
+++ b/table.c
@@ -120,6 +120,8 @@ f     - AST_REMOVEROW: Remove a row from a Table
 *        Original version.
 *     13-MAY-2011 (DSB):
 *        Added support for table parameters.
+*     16-NOV-2013 (DSB):
+*        Fix bug in forming keys in GetColumnLenC.
 *class--
 */
 
@@ -1360,7 +1362,7 @@ static int GetColumnLenC( AstTable *this, const char *column, int *status ) {
       for( irow = 1; irow <= nrow; irow++ ) {
 
 /* Format the cell name. */
-         sprintf( key, "%s(%d)", column, irow );
+         sprintf( key, "%.*s(%d)", (int) astChrLen(column), column, irow );
 
 /* Get the maximum length needed to format a string in the current
    row/column. */
@@ -4177,7 +4179,6 @@ static int TestAttrib( AstObject *this_object, const char *attrib, int *status )
 */
 
 /* Local Variables: */
-   AstTable *this;               /* Pointer to the Table structure */
    int len;                      /* Length of attribute string */
    int nc;                       /* Number of characters read by astSscanf */
    int result;                   /* Result value to return */
@@ -4188,9 +4189,6 @@ static int TestAttrib( AstObject *this_object, const char *attrib, int *status )
 /* Check the global error status. */
    if ( !astOK ) return result;
 
-/* Obtain a pointer to the Table structure. */
-   this = (AstTable *) this_object;
-
 /* Get the length of the attribute string. */
    len = strlen( attrib );
 
diff --git a/version.h b/version.h
index be08a14..1573e47 100644
--- a/version.h
+++ b/version.h
@@ -60,14 +60,14 @@
 *-
 */
 
-/* The current version of AST is 7.3.2 */
+/* The current version of AST is 7.3.3 */
 #define AST__VMAJOR    7
 #define AST__VMINOR    3
-#define AST__RELEASE   2
+#define AST__RELEASE   3
 
 /* Deprecated macros */
 #define AST_MAJOR_VERS 7
 #define AST_MINOR_VERS 3
-#define AST_RELEASE    2
+#define AST_RELEASE    3
 
 #endif /* #if ! defined(VERSION_INCLUDED) */

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/starlink-ast.git



More information about the debian-science-commits mailing list