casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
CoordinateSystem.h
Go to the documentation of this file.
00001 //# CoordinateSystem.h: Interconvert pixel and image coordinates.
00002 //# Copyright (C) 1997,1998,1999,2000,2001,2002,2003,2004
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //#
00027 //# $Id: CoordinateSystem.h 20491 2009-01-16 08:33:56Z gervandiepen $
00028 
00029 
00030 #ifndef COORDINATES_COORDINATESYSTEM_H
00031 #define COORDINATES_COORDINATESYSTEM_H
00032 
00033 #include <casa/aips.h>
00034 #include <coordinates/Coordinates/Coordinate.h>
00035 #include <measures/Measures/MDirection.h>
00036 #include <measures/Measures/MFrequency.h>
00037 #include <coordinates/Coordinates/ObsInfo.h>
00038 #include <casa/Containers/Block.h>
00039 #include <measures/Measures/MDoppler.h>
00040 
00041 namespace casa { //# NAMESPACE CASA - BEGIN
00042 
00043 template<class T> class Matrix;
00044 class DirectionCoordinate;
00045 class LinearCoordinate;
00046 class SpectralCoordinate;
00047 class StokesCoordinate;
00048 class QualityCoordinate;
00049 class TabularCoordinate;
00050 class IPosition;
00051 class LogIO;
00052 
00053 
00054 // <summary>
00055 // Interconvert pixel and world coordinates.
00056 // </summary>
00057 
00058 // <use visibility=export>
00059 
00060 // <reviewed reviewer="Peter Barnes" date="1999/12/24" tests="tCoordinateSystem">
00061 // </reviewed>
00062 //
00063 // <prerequisite>
00064 //   <li> <linkto class=Coordinate>Coordinate</linkto>
00065 // </prerequisite>
00066 
00067 // <synopsis>
00068 // CoordinateSystem is the normal interface to coordinate systems,
00069 // typically attached to an 
00070 // <linkto class=ImageInterface>ImageInterface</linkto>, however the
00071 // coordinate system can be manipulated on its own. CoordinateSystem
00072 // is in turn composed from various classes derived from the base class
00073 // <linkto class=Coordinate>Coordinate</linkto>.
00074 // <p>
00075 // The fundamental operations available to the user of a 
00076 // CoordinateSystem are:
00077 // <ol>
00078 //   <li> Transform a world (physical) coordinate to a pixel coordinate 
00079 //        or vice versa via the methods toWorld and toPixel.
00080 //   <li> Compose a CoordinateSystem from one or more independent groups,
00081 //        typically the sky-plane transformation will be one group, and the
00082 //        spectral axis will be another group. Each group consists of a linear
00083 //        transformation (in FITS terms, apply <src>CRPIX, PC, CDELT</src>)
00084 //        to turn the pixel coordinates into relative world coordinates, 
00085 //        followed by a (possibly) nonlinear projection to world coordinates 
00086 //        (i.e. apply <src>CTYPE and CRVAL</src>), typically a sky projection
00087 //        or a frequency to velocity conversion. Note that an arbitrary rotation
00088 //        or linear transformation can be applied by changing the
00089 //        matrix.
00090 //   <li> Transpose the world and/or pixel axes.
00091 //   <li> One or more pixel or world axes may be removed. You are encouraged to
00092 //        leave all the world axes if you remove a pixel axis.
00093 //        Removing a world axis also removes the corresponding pixel axis.
00094 //   <li> Calculate the CoordinateSystem that results from a subimage
00095 //        operation.
00096 // </ol>
00097 //
00098 // Note that all the knowledge to do with removing and transposing axes is
00099 // maintained by the CoordinateSystem.  The individual Coordinates, of which it
00100 // is made, know nothing about this.
00101 // <p>
00102 // Although the CoordinateSystem exists in the absence of an image, the usual
00103 // place you will find one is attached to an object derived from ImageInterface 
00104 // such as PagedImage. When you do so, the physical (or pixel) axes in the image
00105 // map one to one with the pixel axes contained in the CoordinateSystem.
00106 // It cannot be any other way as when you create a PagedImage, it is checked
00107 // that there are equal numbers of image and CoordinateSystem pixel axes.
00108 // It is up to the creator of the PagedImage to make sure that they are
00109 // in the correct order.
00110 // <p>
00111 // However, the CoordinateSystem may have more world axes than pixel axes
00112 // because it is possible to remove a pixel axis but not its associated
00113 // world axis (for example for a moment image).   Now, if you use
00114 // the CoordinateSystem functions 
00115 // referencePixel and referenceValue, you will find the vector of reference
00116 // values will have more values than the vector of reference pixels,
00117 // if a pixel axis has been removed but not the world axis.  You 
00118 // must use the ancilliary functions provided
00119 // to find out what is where.   
00120 // <p>
00121 // Let's consider an example where a CoordinateSystem consisted of
00122 // a DirectionCoordinate and a SpectralCoordinate.  Let us say that
00123 // the first two pixel axes of the image associate (roughly of course
00124 // because lines of constant RA and DEC are not parallel with
00125 // the pixel coordinates) with the DirectionCoordinate (RA and DEC say) 
00126 // and the third pixel axis is the SpectralCoordinate.
00127 // Now imagine we collapse the image along the second pixel axis (roughly,
00128 // the DEC axis).  For the output image, we remove the second pixel axis
00129 // from the CoordinateSystem, but leave the world axis intact.  This enables
00130 // us to still be able to make coordinate conversions for the first (roughly RA)
00131 // pixel axis.  Thus, CoordinateSystem::referenceValue would return a Vector of
00132 // length 3 (for RA, DEC and spectral), but CoordinateSystem::referencePixel
00133 // would return a vector length 2 (for RA and spectral).  
00134 // <p>
00135 // Now this CoordinateSystem has two Coordinates, a DirectionCoordinate and
00136 // a SpectralCoordinate, and let us state that that is the order in which
00137 // they exist in the CoordinateSystem (you can change them about if you wish);
00138 // they are coordinates number 0 and 1. The DirectionCoordinate has two axes
00139 // (RA and DEC) and the SpectralCoordinate has one axis. Only the
00140 // CoordinateSystem knows about removed axes, the DirectionCoordinate
00141 // itself is ignorant that it has been bisected. If you want to find
00142 // out what axis in the Coordinate system is where, you can use
00143 // the functions findPixelAxis or findWorldAxis.
00144 //
00145 // If we asked the former to find pixel axis 0, it would tell us that the
00146 // Coordinate number was 0 (the DirectionCoordinate) and that the axis in
00147 // that coordinate was 0 (the first axis in a DirectionCoordinate
00148 // is always longitude, the second always latitude).  If we asked it to find
00149 // pixel axis 1, it would tell us that the coordinate number was 1
00150 // (the SpectralCoordinate) and that the axis in that coordinate was 0
00151 // (there is only one axis in a SpectralCoordinate). If we asked for
00152 // pixelAxis 2 that would generate an error because our squashed image
00153 // only has 2 pixel axes. 
00154 //
00155 // Now, if we asked findWorldAxis similar questions,
00156 // it would tell us that worldAxis 0 in the CoordinateSystem can be found in
00157 // coordinate 0 (the DirectionCoordinate) in axis 0 of that DirectionCoordinate.
00158 // Similarly, worldAxis 1 in the CoordinateSystem (which has not been removed)
00159 // is in coordinate 0 (the DirectionCoordinate) in axis 1 of that 
00160 // Finally, worldAxis 2 in the CoordinateSystem is in coordinate 1 
00161 // (the SpectralCoordinate) in axis 0 of that SpectralCoordinate.
00162 // <p>
00163 // Other handy functions are pixelAxes and worldAxes.
00164 // These list the pixel and world axes in
00165 // the CoordinateSystem for the specified coordinate. Thus, if we asked
00166 // pixelAxes to find the pixel axes for coordinate 0 (the  DirectionCoordinate)
00167 // in the CoordinateSystem it would return a vector [0, -1]  indicating
00168 // the second axis of  the DirectionCoordinate has been removed.  However, 
00169 // the worldAxes function would return [0,1] as no world axis has been removed.
00170 // Similarly, if operated on coordinate 1 (the SpectralCoordinate), pixelAxes
00171 // would return [1] and worldAxes would return [2].
00172 //
00173 // Because you can transpose the CoordinateSystem about, you should NEVER ASSUME
00174 // ANYTHING except that the pixel axes of the CoordinateSystem map to the pixel
00175 // axes of the image when you first construct the image.
00176 //
00177 // <p>
00178 // SpectralCoordinate and DirectionCoordinate both have a (non-virtual) function
00179 // called <src>setReferenceConversion</src>.  This enables an extra conversion
00180 // layer so that conversion between pixel and world can go to a reference frame
00181 // other than the construction reference.    When you use the function
00182 // <src>convert</src>, these layers are active, but ONLY if the 
00183 // requested conversion is purely between pixel and world. For 
00184 // a SpectralCoordinate this must always be true (only has one axis)
00185 // but for the DirectionCoordinate  you might request a mixed
00186 // pixel/world conversion. In this case, the extra conversion layer
00187 // is ill-defined and not active (for the DirectionCoordinate part of it).
00188 // </synopsis>
00189 
00190 // <note role=caution>
00191 // All pixels coordinates are zero relative.
00192 // </note>
00193 
00194 // <example>
00195 // See the example in <linkto module=Coordinates>Coordinates.h</linkto>
00196 // and tCoordinateSystem.cc
00197 // </example>
00198 
00199 // <motivation>
00200 // Coordinate systems for images.
00201 // </motivation>
00202 //
00203 // <thrown>
00204 //   <li>  AipsError
00205 // </thrown>
00206 //
00207 // <todo asof="1997/01/13">
00208 //   <li> Undelete individual removed axes.
00209 //   <li> Non-integral pixel shifts/decimations in subimage operations?
00210 //   <li> Copy-on-write for efficiency?
00211 //   <li> Check if the classes are thread safe in general
00212 // </todo>
00213 //
00214 
00215 
00216 class CoordinateSystem : public Coordinate
00217 {
00218 public:
00219     // Default constructor.  This is an empty CoordinateSystem.
00220     CoordinateSystem();
00221 
00222     // Copying constructor (copy semantics)
00223     CoordinateSystem(const CoordinateSystem &other);
00224 
00225     // Assignment (copy semantics).
00226     CoordinateSystem &operator=(const CoordinateSystem &other);
00227 
00228     // Destructor
00229     virtual ~CoordinateSystem();
00230 
00231     // Add another Coordinate to this CoordinateSystem. This addition is done
00232     // by copying, so that if coord changes the change is NOT
00233     // reflected in the CoordinateSystem.
00234     void addCoordinate(const Coordinate &coord);
00235 
00236     // Transpose the CoordinateSystem so that world axis 0 is
00237     // newWorldOrder(0) and so on for all the other axes.
00238     // newPixelOrder works similarly. Normally you will give the
00239     // same transformation vector for both the world and pixel transformations,
00240     // however this is not required.
00241     void transpose(const Vector<Int> &newWorldOrder,
00242                    const Vector<Int> &newPixelOrder);
00243 
00244     // Find the world and pixel axis mappings to the supplied CoordinateSystem
00245     // from the current coordinate system. <src>False</src> is 
00246     // returned if either the supplied or current coordinate system, 
00247     // has no world axes (and a message recoverable with function
00248     // errorMessage indicating why).  Otherwise <src>True</src> is returned.
00249     // worldAxisMap(i) is the location of world axis <src>i</src> (from the
00250     // supplied CoordinateSystem, cSys, in the current CoordinateSystem.
00251     // worldAxisTranspose(i) is the location of world axis 
00252     // <src>i</src> (from the current CoordinateSystem) in the supplied 
00253     // CoordinateSystem, cSys.  The output vectors
00254     // are resized appropriately by this function.  A value of  -1 
00255     // in either vector means that the axis could not be found in the other
00256     // CoordinateSystem.  The vector <src>refChange</src> says
00257     // if the types are the same, is there a reference type change
00258     // (e.g. TOPO versus LSR for the SpectralCoordinate, 
00259     // or J2000 versus GALACTIC for DirectionCoordinate). Thus
00260     // if refChange(i) is True, it means world axis i in the
00261     // current CoordinateSystem was matched, but has a different
00262     // reference type to that of the supplied CoordinateSystem.
00263     // <group>
00264     Bool worldMap (Vector<Int>& worldAxisMap,
00265                    Vector<Int>& worldAxisTranspose,
00266                    Vector<Bool>& refChange,
00267                    const CoordinateSystem& cSys) const;
00268     Bool pixelMap (Vector<Int>& pixelAxisMap,
00269                    Vector<Int>& pixelAxisTranspose,
00270                    const CoordinateSystem& cSys) const;
00271     // </group>
00272 
00273     // Remove a world or pixel axis. When its value is required for forward or
00274     // backwards transformations, use <src>replacement</src>
00275     // <br>
00276     // When a world axis is removed, the corresponding pixel axis is removed
00277     // too, because it makes no sense having a pixel axis without world
00278     // coordinates.
00279     // <br>
00280     // Removing a pixel axis without removing the corresponding world axis
00281     // is, however, possible and meaningful. It can be used when e.g. a
00282     // frequency plane is taken from a cube. The plane has 2 pixel axes, but
00283     // the 3rd world axis can still describe the frequency coordinate.
00284     // See also the functions in  <linkto class=CoordinateUtil>CoordinateUtil</linkto>
00285     // for removing lists of pixel/world axes (tricky because they shift down)
00286     //
00287     // False is returned (an error in <src>errorMessage()</src> will be set)
00288     // if the axis is illegal, else returns True.
00289     // <group>
00290     Bool removeWorldAxis(uInt axis, Double replacement);
00291     Bool removePixelAxis(uInt axis, Double replacement);
00292     // </group>
00293 
00294     // Return a CoordinateSystem appropriate for a shift of origin
00295     // (the shift is subtracted from the reference pixel)
00296     // and change of increment (the increments are multipled
00297     // by the factor). Both vectors should be of length nPixelAxes(). 
00298     //
00299     // The newShape vector is only needed for the StokesCoordinate,
00300     // if any.  If this vector is of length zero, the new StokesCoordinate
00301     // is formed from all of the available input Stokes after application
00302     // of the shift and increment factor.    Otherwise,
00303     // the new Stokes axis length is equal to that specified after
00304     // appliction of the shift and increment and excess values 
00305     // discarded.    In addition, for any StokesCoordinate, the
00306     // shift and factor must be integer.  So <src>Int(value+0.5)</src>
00307     // is taken before they are used.
00308     // <group>
00309     CoordinateSystem subImage(const Vector<Float> &originShift,
00310                               const Vector<Float> &incrFac,
00311                               const Vector<Int>& newShape) const;
00312     void subImageInSitu (const Vector<Float> &originShift,
00313                          const Vector<Float> &incrFac,
00314                          const Vector<Int>& newShape);
00315     // </group>
00316 
00317     // Untranspose and undelete all axes. Does not undo the effects of
00318     // subimaging.
00319     void restoreOriginal();
00320 
00321     // Returns the number of Coordinates that this CoordinateSystem contains.
00322     // The order might be unrelated to the axis order through the results of
00323     // transposing and removing axes.
00324     uInt nCoordinates() const;
00325 
00326     // For a given Coordinate say where its world and pixel axes are in
00327     // this CoordinateSystem. The position in the returned Vector is its
00328     // axis number in the Coordinate, and its value is the axis
00329     // number in the CoordinateSystem. If the value is less than zero the axis
00330     // has been removed from this CoordinateSystem.
00331     //  <group>
00332     Vector<Int> worldAxes(uInt whichCoord) const;
00333     Vector<Int> pixelAxes(uInt whichCoord) const;
00334     // </group> 
00335 
00336     // Return the type of the given Coordinate.
00337     Coordinate::Type type(uInt whichCoordinate) const;
00338 
00339     // Returns the type of the given Coordinate as a string.
00340     String showType(uInt whichCoordinate) const;
00341 
00342     // Return the given Coordinate as a reference to the base
00343     // class object.
00344     const Coordinate& coordinate(uInt which) const;
00345 
00346     // Return the given Coordinate.
00347     // Throws an exception if retrieved as the wrong type.
00348     // The versions which take no parameters will return the
00349     // first (or in most cases only) coordinate of the requested type.
00350     // If no such coordinate exists, an exception is thrown.
00351     // <group>
00352     const LinearCoordinate    &linearCoordinate(uInt which) const;
00353     const DirectionCoordinate &directionCoordinate() const;
00354     const DirectionCoordinate &directionCoordinate(uInt which) const;
00355 
00356     const SpectralCoordinate &spectralCoordinate(uInt which) const;
00357     const SpectralCoordinate &spectralCoordinate() const;
00358     const StokesCoordinate  &stokesCoordinate() const;
00359 
00360     const StokesCoordinate  &stokesCoordinate(uInt which) const;
00361     const QualityCoordinate &qualityCoordinate(uInt which) const;
00362     const TabularCoordinate &tabularCoordinate(uInt which) const;
00363     // </group>
00364 
00365     // Replace one Coordinate with another. The mapping of the coordinate axes
00366     // to the CoordinateSystem axes is unchanged, therefore the number of world
00367     // and pixel axes must not be changed. You can, somewhat dangerously,
00368     // change the type of the coordinate however. For example, replace a 
00369     // SpectralCoordinate with a 1-D Linearcoordinate.  It is dangerous because
00370     // the world replacement values (see removeWorldAxis) have to be scaled.
00371     // The algorithm tries to find a scale factor between the old and new
00372     // units and applies it to the replacement values.  If it can't find
00373     // a scale factor (non-conformant units) then the reference value is
00374     // used for any world replacement values.  If the latter occurs,
00375     // it returns False, else True is returned.
00376     Bool replaceCoordinate(const Coordinate &newCoordinate, uInt whichCoordinate);
00377 
00378     // Find the Coordinate number that corresponds to the given type.
00379     // Since there might be more than one Coordinate of a given type you
00380     // can call this multiple times setting <src>afterCoord</src> to
00381     // the last value found. Returns -1 if a Coordinate of the desired
00382     // type is not found.
00383     Int findCoordinate(Coordinate::Type type, Int afterCoord = -1) const;
00384 
00385     // Given an axis number (pixel or world) in the CoordinateSystem,
00386     // find the corresponding coordinate number and axis in that Coordinate. 
00387     // The returned values are set to -1 if the axis does not exist.
00388     // <group>
00389     void findWorldAxis(Int &coordinate, Int &axisInCoordinate, 
00390                        uInt axisInCoordinateSystem) const;
00391     void findPixelAxis(Int &coordinate, Int &axisInCoordinate, 
00392                        uInt axisInCoordinateSystem) const;
00393     // </group>
00394 
00395     // Find the world axis for the given pixel axis in a CoordinateSystem.
00396     // Returns -1 if the world axis is unavailable (e.g. if it has been
00397     // removed).  
00398     Int pixelAxisToWorldAxis(uInt pixelAxis) const;
00399 
00400     // Find the pixel axis for the given world axis in a CoordinateSystem.
00401     // Returns -1 if the pixel axis is unavailable (e.g. if it has been
00402     // removed). 
00403     Int worldAxisToPixelAxis(uInt worldAxis) const;
00404 
00405     // Returns <src>Coordinate::COORDSYS</src>
00406     virtual Coordinate::Type type() const;
00407 
00408     // Always returns "System"
00409     virtual String showType() const;
00410 
00411     // Sums the number of axes in the Coordinates that the CoordinateSystem
00412     // contains, allowing for removed axes.
00413     // <group>
00414     virtual uInt nPixelAxes() const;
00415     virtual uInt nWorldAxes() const;
00416     // </group>
00417 
00418 
00419     // Convert a pixel position to a world position or vice versa. Returns True
00420     // if the conversion succeeds, otherwise it returns <src>False</src> and
00421     // <src>errorMessage()</src> contains an error message. 
00422     // The input vector must be of length <src>nPixelAxes</src> or
00423     // <src>nWorldAxes</src>.  The output vector  is resized appropriately.
00424     // <group>
00425     virtual Bool toWorld(Vector<Double> &world, 
00426                          const Vector<Double> &pixel) const;
00427     // This one throws an exception rather than returning False. After all, that's
00428     // what exceptions are for.
00429     virtual Vector<Double> toWorld(const Vector<Double> &pixel) const;
00430     virtual Vector<Double> toWorld(const IPosition& pixel) const;
00431     virtual Bool toPixel(Vector<Double> &pixel, 
00432                          const Vector<Double> &world) const;
00433     // This one throws an exception rather than returning False.
00434     virtual Vector<Double> toPixel(const Vector<Double> &world) const;
00435     // </group>
00436 
00437     // convert a pixel "length" to a world "length"
00438     virtual Quantity toWorldLength(
00439         const Double nPixels,
00440         const uInt pixelAxis
00441     ) const;
00442 
00443     // This is provided as a convenience since it is a very commonly desired
00444     // operation through CoordinateSystem.  The output vector is resized.   
00445     Bool toWorld(Vector<Double> &world, const IPosition &pixel) const;
00446 
00447     // Batch up a lot of transformations. The first (most rapidly varying) axis
00448     // of the matrices contain the coordinates. Returns False if any conversion
00449     // failed  and  <src>errorMessage()</src> will hold a message.
00450     // The <src>failures</src> array (True for fail, False for success)
00451     // is the length of the number of conversions and
00452     // holds an error status for each conversion.  
00453     // <group>
00454     virtual Bool toWorldMany(Matrix<Double>& world,
00455                              const Matrix<Double>& pixel,
00456                              Vector<Bool>& failures) const;
00457     virtual Bool toPixelMany(Matrix<Double>& pixel,
00458                              const Matrix<Double>& world,
00459                              Vector<Bool>& failures) const;
00460     // </group>
00461 
00462 
00463     // Mixed pixel/world coordinate conversion.
00464     // <src>worldIn</src> and <src>worldAxes</src> are of length n<src>worldAxes</src>.
00465     // <src>pixelIn</src> and <src>pixelAxes</src> are of length nPixelAxes.
00466     // <src>worldAxes(i)=True</src> specifies you have given a world
00467     // value in <src>worldIn(i)</src> to convert to pixel.
00468     // <src>pixelAxes(i)=True</src> specifies you have given a pixel 
00469     // value in <src>pixelIn(i)</src> to convert to world.
00470     // You cannot specify the same axis via <src>worldAxes</src>
00471     // and pixelAxes.
00472     // Values in <src>pixelIn</src> are converted to world and
00473     // put into <src>worldOut</src> in the appropriate world axis
00474     // location.  Values in <src>worldIn</src> are copied to
00475     // <src>worldOut</src>.   
00476     // Values in <src>worldIn</src> are converted to pixel and
00477     // put into <src>pixelOut</src> in the appropriate pixel axis
00478     // location.  Values in <src>pixelIn</src> are copied to
00479     // <src>pixelOut</src>.  Vectors
00480     // <src>worldMin</src> and <src>worldMax</src> specify the range of the world
00481     // coordinate (in the world axis units of that world axis
00482     // in the coordinate system) being solved for in a mixed calculation 
00483     // for each world axis. They are only actually used for DirectionCoordinates
00484     // and for all other coordinates the relevant elements are ignored.
00485     // Functions <src>setWorldMixRanges, worldMixMin, worldMixMax</src> can be
00486     // used to compute and recover the world ranges.  If you don't know 
00487     // the values, use  functions <src>setDefaultWorldMixRanges, worldMixMin, worldMixMax</src>.
00488     // Removed axes are handled (for example, a removed pixel
00489     // axis with remaining corresponding world axis will
00490     // correctly be converted to world using the replacement
00491     // value).
00492     // Returns True if the conversion succeeds, otherwise it returns <src>False</src> and
00493     // <src>errorMessage()</src> contains an error message. The output vectors
00494     // are resized.
00495     virtual Bool toMix(Vector<Double>& worldOut,
00496                        Vector<Double>& pixelOut,
00497                        const Vector<Double>& worldIn,
00498                        const Vector<Double>& pixelIn,
00499                        const Vector<Bool>& worldAxes,                
00500                        const Vector<Bool>& pixelAxes,
00501                        const Vector<Double>& worldMin,
00502                        const Vector<Double>& worldMax) const; 
00503 
00504     // Compute and recover the world min and max ranges, for use in function <src>toMix</src>,
00505     // for  a lattice of the given shape (must be of length <src>nPixelAxes()</src>). 
00506     // Removed pixel axes (with remaining world axes are handled).  With
00507     // the retrieval functions, the output vectors are resized.  They return 
00508     // False if they fail (and then <src>setDefaultWorldMixRanges</src> generates the ranges)
00509     // with a reason in <src>errorMessage()</src>.
00510     // The <src>setDefaultWorldMixRanges</src> function
00511     // gives you  a useful default range if you don't know the shape.
00512     // The only Coordinate type for which these ranges are actually
00513     // used in <src>toMix</src> is DirectionCoordinate (because its coupled). For
00514     // the rest the functionality is provided but never used
00515     // by toMix.
00516     //<group>
00517     virtual Bool setWorldMixRanges (const IPosition& shape);
00518     virtual void setDefaultWorldMixRanges ();
00519     virtual Vector<Double> worldMixMin () const;
00520     virtual Vector<Double> worldMixMax () const;
00521     //</group>
00522 
00523     // Make absolute coordinates relative and vice-versa (relative
00524     // to the reference pixel/value).  The vectors must be of length
00525     // <src>nPixelAxes()</src> or <src>nWorldAxes()</src>
00526     //<group>
00527     virtual void makePixelRelative (Vector<Double>& pixel) const;
00528     virtual void makePixelAbsolute (Vector<Double>& pixel) const;
00529     virtual void makeWorldRelative (Vector<Double>& world) const;
00530     virtual void makeWorldAbsolute (Vector<Double>& world) const;
00531     //</group>
00532 
00533     // Make absolute coordinates relative and vice versa with respect
00534     // to the given reference value.  Add the other functions in this grouping
00535     // as needed.    The vectors must be of length
00536     // <src>nPixelAxes()</src> or <src>nWorldAxes()</src>
00537     //<group>
00538     virtual void makeWorldAbsoluteRef (Vector<Double>& world,
00539                                        const Vector<Double>& refVal) const;
00540     //</group>
00541 
00542     // Batch up a lot of absolute/relative transformations. 
00543     // Parameters as above  for 
00544     // <src>toWorldMany</src> and <src>toPixelMany</src>
00545     // <group>
00546     virtual void makePixelRelativeMany (Matrix<Double>& pixel) const;
00547     virtual void makePixelAbsoluteMany (Matrix<Double>& pixel) const;
00548     virtual void makeWorldRelativeMany (Matrix<Double>& world) const;
00549     virtual void makeWorldAbsoluteMany (Matrix<Double>& world) const;
00550     // </group>
00551 
00552 
00553     // General coordinate conversion.  Only works if no axes
00554     // have been removed and no axis reordering has occurred.
00555     // That is pixel axes and world axes are the same.
00556     //
00557     // Specify the input coordinate values, input units,
00558     // whether value is absolute (or relative). For output
00559     // specify units and abs/rel.  Units may be 'pix' and velocity consistent
00560     // units (e.g. m/s).  Specify doppler types if velocities
00561     // involved.   The pixel offsets allow for the input
00562     // and output pixel coordinates to be something other than 0-rel.  
00563     // If your pixel coordinates are 1-rel input and output, set the 
00564     // offsets to -1 and 1
00565     //
00566     // The Matrix interface lets you do many conversions efficiently.
00567     // Use <src>Matrix(nAxes, nConversions) </src> and 
00568     // <src>Matrix.column()=coordinate</src> or
00569     // <src>Matrix(axis, iConversion)</src> to get the order right.  
00570     //
00571     // These functions invoke <src>toMix</src>
00572     // so make sure you call <src>setWorldMixRanges</src>
00573     // first to set up the world ranges. 
00574     // <group>
00575     Bool convert (Vector<Double>& coordOut, 
00576                   const Vector<Double>& coordin,
00577                   const Vector<Bool>& absIn,
00578                   const Vector<String>& unitsIn,
00579                   MDoppler::Types dopplerIn,
00580                   const Vector<Bool>& absOut,
00581                   const Vector<String>& unitsOut,
00582                   MDoppler::Types dopplerOut,
00583                   Double pixInOffset = 0.0,
00584                   Double pixOutOffset = 0.0);
00585     Bool convert (Matrix<Double>& coordOut, 
00586                   const Matrix<Double>& coordIn,
00587                   const Vector<Bool>& absIn,
00588                   const Vector<String>& unitsIn,
00589                   MDoppler::Types dopplerIn,
00590                   const Vector<Bool>& absOut,
00591                   const Vector<String>& unitsOut,
00592                   MDoppler::Types dopplerOut,
00593                   Double pixInOffset = 0.0,
00594                   Double pixOutOffset = 0.0);
00595     // </group>
00596 
00597     // Return the requested attribute.
00598     // <group>
00599     virtual Vector<String> worldAxisNames() const;
00600     virtual Vector<Double> referencePixel() const;
00601     virtual Matrix<Double> linearTransform() const;
00602     virtual Vector<Double> increment() const;
00603     virtual Vector<Double> referenceValue() const;
00604     // </group>
00605 
00606     // Set the requested attribute.  Note that these just
00607     // change the internal values, they do not cause any recomputation.
00608     // <group>
00609     virtual Bool setWorldAxisNames(const Vector<String> &names);
00610     virtual Bool setReferencePixel(const Vector<Double> &refPix);
00611     virtual Bool setLinearTransform(const Matrix<Double> &xform);
00612     virtual Bool setIncrement(const Vector<Double> &inc);
00613     virtual Bool setReferenceValue(const Vector<Double> &refval);
00614     // </group>
00615 
00616     // Set/get the units. Adjust the increment and
00617     // reference value by the ratio of the old and new units. This implies that
00618     // the units must be known <linkto class=Unit>Unit</linkto> strings, and
00619     // that they must be compatible, e.g. they can't change from time to
00620     // length.
00621     // <group>
00622     virtual Bool setWorldAxisUnits(const Vector<String> &units);
00623     virtual Vector<String> worldAxisUnits() const;
00624     // </group>
00625 
00626     // Comparison function. Any private Double data members are compared
00627     // with the specified fractional tolerance.  Don't compare on the specified 
00628     // pixel axes in the CoordinateSystem.  If the comparison returns
00629     // <src>False</src>, errorMessage() contains a message about why.
00630     // <group>
00631     virtual Bool near(const Coordinate& other, Double tol=1e-6) const;
00632     virtual Bool near(const Coordinate& other, 
00633                       const Vector<Int>& excludePixelAxes,
00634                       Double tol=1e-6) const;
00635     // </group>
00636 
00637     // This function compares this and the other coordinate system,
00638     // but ONLY for the non-removed pixel axes.   It is less strict
00639     // than near, which, for example, insists the number of coordinates
00640     // is the same in each CS
00641     Bool nearPixel (const CoordinateSystem& other, Double tol=1e-6) const;
00642 
00643 
00644     // Format a world value nicely through the
00645     // common format interface.  See <linkto class=Coordinate>Coordinate</linkto>
00646     // for basics.
00647     //
00648     // You specify a world value and its corresponding world axis in
00649     // the CoordinateSystem.   
00650     //
00651     // For the specified worldAxis, the coordinate
00652     // number in the CoordinateSystem is found and the actual derived Coordinate
00653     // class object for that number is created.  The arguments to the formatting 
00654     // function are then passed on to the formatter for that Coordinate. So
00655     // refer to the other derived Coordinate classes for specifics on the
00656     // formatting.
00657     virtual String format(
00658         String& units,
00659         Coordinate::formatType format,
00660         Double worldValue,
00661         uInt worldAxis,
00662         Bool isAbsolute=True,
00663         Bool showAsAbsolute=True,
00664         Int precision=-1, Bool usePrecForMixed=False
00665     ) const;
00666 
00667     // Miscellaneous information related to an observation, for example the
00668     // observation date.
00669     // <group>
00670     ObsInfo obsInfo() const;
00671     void setObsInfo(const ObsInfo &obsinfo);
00672     // </group>
00673 
00674     // Find the CoordinateSystem (you can safely caste the pointer to a CoordinateSystem)
00675     // for when we Fourier Transform ourselves.  This pointer 
00676     // must be deleted by the caller. Axes specifies which pixel axes of the Coordinate
00677     // System you wish to transform.   Shape specifies the shape of the image
00678     // associated with all the axes of the CoordinateSystem.  Currently you have
00679     // no control over the reference pixel, it is always shape/2.
00680     virtual Coordinate* makeFourierCoordinate (const Vector<Bool>& axes,
00681                                                const Vector<Int>& shape) const;
00682 
00683 
00684     // Save the CoordinateSystem into the supplied record using the supplied field name.
00685     // The field must not exist, otherwise <src>False</src> is returned.
00686     // If the CoordinateSystem is empty  <src>False</src> is also returned.
00687     // If <src>False</src> is returned, errorMessage() contains a message about why.   
00688     virtual Bool save(RecordInterface &container,
00689                     const String &fieldName) const;
00690 
00691     // Restore the CoordinateSystem from a record.  The <src>fieldName</src>
00692     // can be empty, in which case the CoordinateSystem is restored 
00693     // directly from the Record, rather than a subrecord of it.
00694     // A null pointer means that the restoration did not succeed - probably 
00695     // because fieldName doesn't exist or doesn't contain a CoordinateSystem.
00696     static CoordinateSystem *restore(const RecordInterface &container,
00697                                    const String &fieldName);
00698 
00699     // Make a copy of the CoordinateSystem using new. The caller is responsible for calling
00700     // delete.
00701     virtual Coordinate* clone() const;
00702 
00703     // Convert a CoordinateSystem to FITS, i.e. fill in ctype etc. In the record
00704     // the keywords are vectors, it is expected that the actual FITS code will
00705     // split them into scalars and upcase the names. Returns False if one of the
00706     // keywords is already taken.
00707     // 
00708     // If writeWCS is True, attempt to write the WCS convention (Greisen and
00709     // Calabretta "Representation of celestial coordinates in FITS"). 
00710     // Use <src>oneRelative=True</src> to convert zero-relative pixel coordinates to
00711     // one-relative FITS coordinates.
00712     //
00713     // prefix gives the prefix for the FITS keywords. E.g.,
00714     // if prefix="c" then crval, cdelt etc. 
00715     // if prefix="d" then drval, ddelt etc. 
00716     //# Much of the work in to/from fits should be moved to the individual
00717     //# classes.
00718     Bool toFITSHeader(RecordInterface &header, 
00719                       IPosition &shape,
00720                       Bool oneRelative, 
00721                       Char prefix = 'c', Bool writeWCS=True,
00722                       Bool preferVelocity=True, 
00723                       Bool opticalVelocity=True,
00724                       Bool preferWavelength=False,
00725                       Bool airWavelength=False) const;
00726 
00727     // Probably even if we return False we should set up the best linear
00728     // coordinate that we can.
00729     // Use oneRelative=True to convert one-relative FITS pixel coordinates to
00730     // zero-relative aips++ coordinates.  On output, <src>stokesFITSValue</src>
00731     // holds the FITS value of any unofficial Stokes (beam, optical depth,
00732     // spectral index) for the last unofficial value accessed (-1 if none).
00733     // The idea is that if the Stokes axis is of length one and holds an unofficial value,
00734     // you should drop the STokes axis and convert that value to <src>ImageInfo::ImageTypes</src>
00735     // with <src>ImageInfo::imageTypeFromFITSValue</src>. If on input, <src>stokesFITSValue</src>
00736     // is positive, then a warning is issued if any unofficial values are encountered.
00737     // Otherwise no warning is issued.
00738     //# cf comment in toFITS.
00739     static Bool fromFITSHeader(Int& stokesFITSValue, 
00740                                CoordinateSystem &coordsys, 
00741                                RecordInterface& recHeader,
00742                                const Vector<String>& header,
00743                                const IPosition& shape,
00744                                uInt which=0);
00745 
00746 // List all header information.  By default, the reference
00747 // values and pixel increments are converted to a "nice" unit before 
00748 // formatting (e.g. RA is  shown as HH:MM:SS.S).  
00749 // For spectral axes, both frequency and velocity information is listed. You
00750 // can specify what velocity definition you want with <src>velocityType</src>
00751 // If you wish, you can specify two shapes; a lattice and tile shape
00752 // (perhaps an image from which the CoordinateSystem came)
00753 // If you give (both of) these, they are included in the listing.  If you pass
00754 // in zero length <src>IPositions</src> then they are not included in
00755 // the listing.   If <src>postlocally=True</src> the formatted summary lines 
00756 // are written locally only to the sink, and then returned by the return value 
00757 // vector.
00758    Vector<String> list(LogIO& os, MDoppler::Types doppler,
00759                        const IPosition& latticeShape,
00760                        const IPosition& tileShape, Bool postLocally=False) const;
00761 
00762    // Does this coordinate system have a spectral axis?
00763    Bool hasSpectralAxis() const;
00764 
00765    // what number is the spectral axis? Returns -1 if no spectral axis exists.
00766    Int spectralAxisNumber() const;
00767 
00768    // what number is the spectral coordinate? Returns -1 if no spectral coordinate exists.
00769    Int spectralCoordinateNumber() const;
00770 
00771 
00772    // does this coordinate system have a polarizaion/stokes coordinate?
00773    Bool hasPolarizationCoordinate() const;
00774 
00775    // Given a stokes or polarization parameter, find the pixel location.
00776    // Note the client is responsible for any boundedness checks
00777    // (eg finite number of stokes in an image).
00778    Int stokesPixelNumber(const String& stokesString) const;
00779 
00780    // what is the number of the polarization/stokes coordinate?
00781    // Returns -1 if no stokes coordinate exists.
00782    Int polarizationCoordinateNumber() const;
00783 
00784    // what is the number of the polarization/stokes axis?
00785    // Returns -1 if no stokes axis exists.
00786    Int polarizationAxisNumber() const;
00787 
00788    // Does this coordinate system have a quality axis?
00789    Bool hasQualityAxis() const;
00790 
00791    // what number is the quality axis? Returns -1 if no quality axis exists.
00792    Int qualityAxisNumber() const;
00793 
00794    // what is the number of the quality coordinate?
00795    // Returns -1 if no quality coordinate exists.
00796    Int qualityCoordinateNumber() const;
00797 
00798    // Given a quality parameter, find the pixel location.
00799    // Note the client is responsible for any boundedness checks
00800    // (eg finite number of quality in an image).
00801    Int qualityPixelNumber(const String& qualityString) const;
00802 
00803    String qualityAtPixel(const uInt pixel) const;
00804 
00805    Int directionCoordinateNumber() const;
00806 
00807    Bool hasDirectionCoordinate() const;
00808 
00809    Vector<Int> directionAxesNumbers() const;
00810 
00811    String stokesAtPixel(const uInt pixel) const;
00812 
00813    Int linearCoordinateNumber() const;
00814 
00815    Bool hasLinearCoordinate() const;
00816 
00817    Vector<Int> linearAxesNumbers() const;
00818 
00819    // Get the 0 based order of the minimal match strings specified in <src>order</src>.
00820    // If <src>requireAll</src> is True, checks are done to ensure that all axes in
00821    // the coordinate system are uniquely specified in <src>order</src>.
00822    // If <src>allowFriendlyNames</src> is True, the following (fully specified) strings will
00823    // match the specified axes:
00824    // "spectral" matches both "frequency" and "velocity".
00825    // "ra" matches "right ascension"
00826    Vector<Int> getWorldAxesOrder(
00827                    Vector<String>& myNames, Bool requireAll,
00828                    Bool allowFriendlyNames=False
00829    ) const;
00830 
00831 
00832 private:
00833     // Where we store copies of the coordinates we are created with.
00834     PtrBlock<Coordinate *> coordinates_p;
00835     
00836     // For coordinate[i] axis[j], 
00837     //    world_maps_p[i][j], if >=0 gives the location in the
00838     //                        input vector that maps to this coord/axis,
00839     //                        <0 means that the axis has been removed
00840     //    world_tmp_p[i] a temporary vector length coord[i]->nworldAxes()
00841     //    replacement_values_p[i][j] value to use for this axis if removed
00842     PtrBlock<Block<Int> *>     world_maps_p;
00843     PtrBlock<Vector<Double> *> world_tmps_p;
00844     PtrBlock<Vector<Double> *> world_replacement_values_p;
00845 
00846     // Same meanings as for the world*'s above.
00847     PtrBlock<Block<Int> *>     pixel_maps_p;
00848     PtrBlock<Vector<Double> *> pixel_tmps_p;
00849     PtrBlock<Vector<Double> *> pixel_replacement_values_p;
00850 
00851     // These temporaries all needed for the toMix function
00852     PtrBlock<Vector<Bool> *> worldAxes_tmps_p;
00853     PtrBlock<Vector<Bool> *> pixelAxes_tmps_p;
00854     PtrBlock<Vector<Double> *> worldOut_tmps_p;
00855     PtrBlock<Vector<Double> *> pixelOut_tmps_p;
00856     PtrBlock<Vector<Double> *> worldMin_tmps_p;
00857     PtrBlock<Vector<Double> *> worldMax_tmps_p;
00858 
00859     // Miscellaneous information about the observation associated with this
00860     // Coordinate System.
00861     ObsInfo obsinfo_p;
00862 
00863     const static String _class;
00864     static map<String, String> _friendlyAxisMap;
00865 
00866     static void _initFriendlyAxisMap();
00867 
00868     // Helper functions to group common code.
00869     Bool mapOne(Vector<Int>& worldAxisMap, 
00870                 Vector<Int>& worldAxisTranspose, 
00871                 Vector<Bool>& refChange,
00872                 const CoordinateSystem& cSys,
00873                 const CoordinateSystem& cSys2,
00874                 const uInt coord, const uInt coord2) const;
00875 
00876     void copy(const CoordinateSystem &other);
00877     void clear();
00878     Bool checkAxesInThisCoordinate(const Vector<Bool>& axes, uInt which) const;
00879 
00880    // Delete some pointer blocks
00881    void cleanUpSpecCoord (PtrBlock<SpectralCoordinate*>&  in,
00882                           PtrBlock<SpectralCoordinate*>&  out);
00883 
00884    // Delete temporary maps
00885    void deleteTemps (const uInt which);
00886 
00887     // Many abs/rel conversions
00888     // <group>
00889     void makeWorldAbsRelMany (Matrix<Double>& value, Bool toAbs) const;
00890     void makePixelAbsRelMany (Matrix<Double>& value, Bool toAbs) const;
00891     // </group>
00892 
00893     // Do subImage for Stokes
00894     StokesCoordinate stokesSubImage(const StokesCoordinate& sc, Int originShift, Int pixincFac,
00895                                     Int newShape) const;
00896 
00897     // Do subImage for Quality
00898     QualityCoordinate qualitySubImage(const QualityCoordinate& qc, Int originShift, Int pixincFac,
00899                                         Int newShape) const;
00900 
00901     // Strip out coordinates with all world and pixel axes removed
00902     CoordinateSystem stripRemovedAxes (const CoordinateSystem& cSys) const;
00903 
00904     //  All these functions are in support of the <src>list</src> function
00905     // <group>
00906     void listDirectionSystem(LogIO& os) const; 
00907     void listFrequencySystem(LogIO& os, MDoppler::Types velocityType) const;
00908     void listPointingCenter (LogIO& os) const;
00909     void getFieldWidths (LogIO& os, uInt& widthAxis, uInt& widthCoordType, 
00910                          uInt& widthCoordNumber, uInt& widthName,
00911                          uInt& widthProj, uInt& widthShape,
00912                          uInt& widthTile, uInt& widthRefValue,
00913                          uInt& widthRefPixel, uInt& widthInc,
00914                          uInt& widthUnits, Int& precRefValSci,
00915                          Int& precRefValFloat,  Int& precRefValRADEC,
00916                          Int& precRefPixFloat, Int& precIncSci, String& nameAxis,
00917                          String& nameCoordType, String& nameCoordNumber, String& nameName, String& nameProj,
00918                          String& nameShape, String& nameTile,
00919                          String& nameRefValue, String& nameRefPixel,
00920                          String& nameInc, String& nameUnits,
00921                          MDoppler::Types velocityType,
00922                          const IPosition& latticeShape, const IPosition& tileShape) const;
00923 
00924     void listHeader (LogIO& os, Coordinate* pc, uInt& widthAxis, uInt& widthCoordType,  uInt& widthCoordNumber,
00925                      uInt& widthName, uInt& widthProj,
00926                      uInt& widthShape, uInt& widthTile, uInt& widthRefValue,
00927                      uInt& widthRefPixel, uInt& widthInc, uInt& widthUnits,     
00928                      Bool findWidths, Int coordinate, Int axisInCoordinate, Int pixelAxis, 
00929                      Int precRefValSci, Int precRefValFloat, Int precRefValRADEC, Int precRefPixFloat,
00930                      Int precIncSci, const IPosition& latticeShape, const IPosition& tileShape) const;
00931     void listVelocity (LogIO& os,  Coordinate* pc, uInt widthAxis, 
00932                        uInt widthCoordType, uInt widthCoordNumber,
00933                        uInt& widthName, uInt widthProj,
00934                        uInt widthShape, uInt widthTile, uInt& widthRefValue,
00935                        uInt widthRefPixel, uInt& widthInc,  uInt& widthUnits,
00936                        Bool findWidths, Int axisInCoordinate, Int pixelAxis, 
00937                        MDoppler::Types velocityType, Int precRefValSci, Int precRefValFloat,
00938                        Int precRefValRADEC, Int precRefPixFloat, Int precIncSci) const;
00939     void clearFlags (LogIO& os) const;
00940     Bool velocityIncrement(Double& velocityInc,  SpectralCoordinate& sc,
00941                            MDoppler::Types velocityType, const String& velUnits) const;
00942     // </group>
00943 
00944     void _downcase(Vector<String>& vec) const;
00945 
00946 };
00947 
00948 } //# NAMESPACE CASA - END
00949 
00950 #endif
00951