Slicer.h

Go to the documentation of this file.
00001 //# Slicer.h:  specify which elements to extract from an n-dimensional array
00002 //# Copyright (C) 1994,1995,1997,1999
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 //# $Id$
00027 
00028 #ifndef CASA_SLICER_H
00029 #define CASA_SLICER_H
00030 
00031 
00032 //# Includes
00033 #include <casacore/casa/aips.h>
00034 #include <casacore/casa/Arrays/IPosition.h>
00035 
00036 namespace casacore { //# NAMESPACE CASACORE - BEGIN
00037 
00038 //# Forward Declarations
00039 class Slice;
00040 
00041 
00042 // <summary>
00043 // Specify which elements to extract from an n-dimensional array
00044 // </summary>
00045 
00046 // <reviewed reviewer="Paul Shannon" date="1994/07/07" tests="tSlicer">
00047 //  The review and modification of this class were undertaken, in part,
00048 //  with the aim of making this class header an example -- this is what
00049 //  the Casacore project thinks a class header should look like.
00050 // </reviewed>
00051 
00052 // <prerequisite>
00053 // You should have at least a preliminary understanding of these classes:
00054 //   <li> <linkto class=IPosition>IPosition</linkto>
00055 //   <li> <linkto class=Array>Array</linkto>
00056 //   <li> <linkto class=Slice>Slice</linkto>
00057 // </prerequisite>
00058 
00059 // <etymology>
00060 // The class name "Slicer" may be thought of as a short form 
00061 // of "n-Dimensional Slice Specifier."  Some confusion is possible
00062 // between class "Slice" and this class.
00063 // </etymology>
00064 //
00065 // <synopsis>
00066 // If you need to extract or operate upon a portion of an array,
00067 // the Slicer class is the best way to specify the subarray you are
00068 // interested in.
00069 //
00070 // Slicer has many constructors.  Of these, some require that the
00071 // programmer supply a full specification of the array elements he
00072 // wants to extract;  other constructors make do with partial information.
00073 // In the latter case, the constructor will assume sensible default values or, 
00074 // when directed, infer missing information from the array that's getting 
00075 // sliced (hereafter, the "source" array).
00076 //
00077 // <h4> Constructing With Full Information </h4>
00078 //
00079 // To fully specify a subarray, you must supply three pieces of information
00080 // for each axis of the subarray: 
00081 // 
00082 // <ol>
00083 //    <li> where to start
00084 //    <li> how many elements to extract
00085 //    <li> what stride (or "increment" or "interval") to use:  a stride of
00086 //         "n" means pick extract only every "nth" element along an axis
00087 // </ol>
00088 //
00089 // The most basic constructor for Slicer illustrates this.  To create
00090 // an Slicer for getting selected elements from a 3D array:
00091 //
00092 // <srcblock> 
00093 //   IPosition start (3,0,0,0), length (3,10,10,10), stride (3,3,3,3);
00094 //   Slicer slicer (start, length, stride);
00095 //   // assume proper declarations, and meaningful values in the source array
00096 //   subArray = sourceArray (slicer);
00097 // </srcblock>
00098 // It gets elements 0,3,6,9,12,15,18,21,24,27 for each dimension.
00099 //
00100 // <note role=caution> If you wish to extract elements from the array 
00101 // at intervals, these intervals must be regular.   The interval is one 
00102 // constant integer for each dimension of the array:  it cannot be a function.
00103 // </note>
00104 // 
00105 // <note role=caution> "length", the second parameter to the Slicer 
00106 // constructor above, may actually be used in two ways.  In normal 
00107 // (and default) use, it specifies how many elements to select from the 
00108 // source.  In the alternative use, it specifies the index of the last element
00109 // to extract from the source array.  This ambiguity (does "end" mean 
00110 // "length" or does it mean "last index"?) is handled by a default 
00111 // fourth parameter to the constructor.  This code fragment will
00112 // extract the same subarray as the example above:
00113 // <srcblock>
00114 //   IPosition start (3,0,0,0), end (3,27,27,27), stride (3,3,3,3);
00115 //   Slicer slicer (start, end, stride, Slicer::endIsLast);
00116 //   subArray = sourceArray (slicer);
00117 // </srcblock>
00118 // Note that in this example end(3,28,29,28) gives the same result.
00119 // (We use "end" as the name of the formal parameter because it supports 
00120 // both meanings -- "last index" or "length."  You may wish to use a 
00121 // clarifying name for the actual parameter in your code, as we have 
00122 // above when we used "length".)
00123 // </note>
00124 // Similar to Python it is possible to address the start and/or end value
00125 // from the end by giving a negative value (-1 means the last value).
00126 // However, a length and stride cannot be negative.
00127 // Unlike Python the end value is inclusive (as discussed above).
00128 // For example,
00129 // <srcblock>
00130 //    Slicer slicer (IPosition(1,-4), IPosition(1,-2), Slicer::endIsLast)
00131 //    Slicer slicer (IPosition(1,6),  IPosition(1,8),  Slicer::endIsLast)
00132 // </srcblock>
00133 // Both Slicers give the same result when used on a Vector with length 10.
00134 //
00135 // <h4> Constructing with Partial Information </h4>
00136 // 
00137 // Some of the constructors don't require complete information:  Slicer
00138 // either calculates sensible default values or deduces them from the
00139 // source array.  If you do not specify a "stride" argument, for example,
00140 // a value of 1 will be used for all dimensions.  If you specify a "start" 
00141 // but nothing else, a stride of 1, and (perhaps against expectation)
00142 // a length of 1 will be used. 
00143 //
00144 // Note that using a negative start or end is also partial information.
00145 // The actual array shape is needed to derive the exact start or end value.
00146 //
00147 // To instruct the Slicer to get otherwise unspecified information 
00148 // from the source array, you can create an IPosition like  "end"
00149 // as shown here:
00150 //
00151 // <srcblock>
00152 //   IPosition start (3,0,0,0), stride (3,3,3,3);
00153 //   IPosition end   (3,Slicer::MimicSource, Slicer::MimicSource, 
00154 //                    Slicer::MimicSource);
00155 //   Slicer smartSlicer (start, end, stride);
00156 //   // assume proper declarations...
00157 //   subArray = sourceArray (smartSlicer)
00158 // </srcblock>
00159 //
00160 // If you are a library programmer, and write a class that can be sliced
00161 // by the Slicer class, you need to understand the mechanism for
00162 // completing the information which the application programmer, in using
00163 // your class, specified incompletely. (If you are an application
00164 // programmer, who wants to slice a library class, this explanation will
00165 // be only of academic interest.) 
00166 // 
00167 // When the source array (the library class you provide) gets the Slicer --
00168 // which typically comes when the source array is asked to return a
00169 // reference to a subarray -- the source does a callback to the Slicer
00170 // object.  The source array passes its own shape as one of the arguments
00171 // to the Slicer callback and asks the Slicer to fill in the missing
00172 // values from that shape.
00173 // 
00174 // In use, and with an imagined class "MyVector", code would look
00175 // like this:
00176 // <srcblock>
00177 //   // first, a fragment from the application program:
00178 //   IPosition start (1,10), end (1, Slicer::MimicSource);
00179 //   Slicer slicer (start, end);
00180 //   MyVector <Int> v0 (100);
00181 //   MyVector <Int> v1 = v0 (slicer);
00182 //   //....
00183 //   // second, a fragment from a constructor of the library class "MyVector":
00184 //   // the MyVector class will construct v1 as a reference to
00185 //   // selected elements of v0, using (among other things) a
00186 //   // callback to the slicer it was passed (above, in the
00187 //   // construction of v1.
00188 //   // 
00189 //   IPosition start, end, stride;
00190 //   fullSliceInformation = 
00191 //      slicer.inferShapeFromSource (MyVector::shape(), start, end, stride);
00192 //   // now the MyVector instance knows everything it needs to
00193 //   // construct the instance.
00194 // </srcblock>
00195 // Please note that v1 will have a length of 90, and refer to elements
00196 // 10-99 of v0.
00197 //
00198 // <note role=warning> An exception will be thrown if the positions
00199 //  defined in the Slicer exceed the source array's shape.
00200 // </note>
00201 // </synopsis>
00202 //
00203 // <example>
00204 // Given a large image, 4k on a side, extract (by sampling) an image
00205 // 1k on a side, but covering the same region as the original.
00206 //
00207 // <srcblock>
00208 //   Image <Float>  image ("N5364.fits");   // a 4-d VLA map, 4096 x 4096 x 3 x 1
00209 //   IPosition start (4,0,0,0,0), stride (4,4,4,1,1);
00210 //   IPosition end   (4, Slicer::MimicSource, Slicer::MimicSource, 
00211 //                    Slicer::MimicSource, Slicer::MimicSource);
00212 //   Slicer smartSlicer (start, end, stride);
00213 //   // assume proper declarations...
00214 //   Image <Float> subImage = image (smartSlicer);
00215 // </srcblock>
00216 //  
00217 // </example>
00218 
00219 // <motivation>
00220 // Slicer is particularly convenient for designers of other library
00221 // classes: Array and Image, for example. (In fact, this convenience 
00222 // was the original motivation for the class.)  The benefit
00223 // is this:  the application programmer, who needs a slice of an Array,
00224 // may provide slicing specifications in many different ways, but the 
00225 // Array class author needs to provide only one member function to 
00226 // return the slice.  The Slicer class, in effect, and with its
00227 // many constructors, provides a way to funnel all of the variety
00228 // into a single member function call to the array or image class.
00229 //
00230 // For example, imagine a 100 x 100 x 100 array from which you want to 
00231 // extract various subarrays.  Here are some of the ways you might
00232 // specify the the subarray in the -absence- of Slicer.  
00233 //
00234 // <srcblock>
00235 //   // preliminaries: create a cube and assign values to all elements --
00236 //   //  this will be "source" array
00237 //   Cube <Int> bigCube (IPosition (3, 100, 100, 100));
00238 //   assignValues (bigCube);
00239 //   // declare a smaller cube, the destination array.
00240 //   Cube <Int> smallCube (IPosition (3, 10, 10, 10));
00241 //
00242 //   //  example 1: use Slice objects to extract a subcube -- the first
00243 //   //   ten elements along each axis
00244 //   Slice xIndices (0,10,1), yIndices (0,10,1), zIndices (0,10,1);
00245 //   smallCube = bigCube (xIndices, yIndices, zIndices);
00246 //
00247 //   // example 2: get the same subcube using three IPosition arguments
00248 //   IPosition start (3,0,0,0), end (3,10,10,10), stride (3,1,1,1);
00249 //   smallCube = bigCube (start, end, stride);
00250 //
00251 //   // example 3: use 2 IPositions, letting the 3rd (stride) default to
00252 //   //            IPosition (3,1,1,1)
00253 //   smallCube = bigCube (start, end);
00254 // </srcblock>
00255 //
00256 // So the Cube class (together with its base class) must define three separate
00257 // member functions for the essentially identical operation of
00258 // extracting a subcube.  The same replication is also required of
00259 // Image, Array, and the other Array subclasses (Matrix and Vector).
00260 //
00261 // The Slicer class collapses all of this into a single member
00262 // function per class:
00263 //   
00264 // <srcblock>
00265 //   Slicer slicer = (call the constructor that best suits your problem)
00266 //   smallCube = bigCube (slicer);
00267 // </srcblock>
00268 // 
00269 // Since there are many constructors available for Slicer, you
00270 // can still specify the subarray that you may want in a number of 
00271 // different ways, by constructing the Slicer in the way most natural
00272 // to your circumstances.  You then pass the Slicer to the array, and 
00273 // you will get back the slice you want.  
00274 //
00275 // This class also offers the application programmer considerable
00276 // flexibility by allowing the shape of the source array to determine
00277 // some of the slice specification.  This benefit is explained and
00278 // demonstrated above.
00279 // </motivation>
00280 
00281 // <todo asof="1994/07/01">
00282 //   <li> This class, and the TableArray, Array and Image classes, 
00283 //   could allow for the extraction of a subarray with fewer axes than the
00284 //   source array.  At present, for example, you cannot, directly slice
00285 //   a matrix from a cube.
00286 // </todo>
00287 
00288 
00289 class Slicer
00290 {
00291 public:
00292 
00293     // Define the "MimicSource" value which defines the open start or end.
00294     // This value should be different from MIN_INT in IPosition.h.
00295     // It should also not be the lowest possible value, since that
00296     // will probably be used as an undefined value.
00297     // It must be a negative number.
00298     enum {MimicSource= -2147483646};
00299 
00300     // Define the possible interpretations of the end-value.
00301     enum LengthOrLast {
00302         // The end-values given in the constructor define the lengths.
00303         endIsLength,
00304         // The end-values given in the constructor define the trc.
00305         endIsLast
00306     };
00307 
00308     // Construct a 1-dimensional Slicer.
00309     // Start and end are inferred from the source; stride=1.
00310     // "endIsLength" and "endIsLast" are identical here, so there's
00311     // no need to discriminate between them by using a default parameter.
00312     Slicer();
00313 
00314     // The member function <src>inferShapeFromSource</src>
00315     // (invoked as a callback by the
00316     // source array) will use the shape of the source array for the 
00317     // unspecified values:  IPosition elements with the value
00318     //  Slicer::MimicSource
00319     // <thrown>
00320     //    <li> ArraySlicerError
00321     // </thrown>
00322     // Create a Slicer with a given start, end (or length), and stride.
00323     // An exception will be thrown if a negative length or non-positive
00324     // stride is given or if the IPositions start, end, and stride
00325     // do not have the same dimensionality.
00326     // If length or stride is not given, they default to 1.
00327     // <br> It is possible to leave values in start and end undefined
00328     // by giving the value <src>MimicSource</src>. They can be filled
00329     // in later with the actual array shape using function
00330     // <src>inferShapeFromSource</src>.
00331     // <group>
00332     Slicer (const IPosition& start, const IPosition& end, 
00333             const IPosition& stride, 
00334             LengthOrLast endInterpretation = endIsLength);
00335     Slicer (const IPosition& start, const IPosition& end,
00336             LengthOrLast endInterpretation = endIsLength);
00337     explicit Slicer (const IPosition& start);
00338     // </group>
00339 
00340     // Create a Slicer object from Slice objects.
00341     // In a Slice object one defines the start, length, and stride for 
00342     // one axis.
00343     // The default Slice constructor (called with no arguments) creates
00344     // a Slice with start and length equal to zero, and an undefined stride.
00345     // <group>
00346     // Create a Slicer for a 1-dimensional array.
00347     Slicer (const Slice& x, LengthOrLast endInterpretation = endIsLength);
00348 
00349     // Create a Slicer for a 2-dim array.
00350     Slicer (const Slice& x, const Slice& y, 
00351             LengthOrLast endInterpretation = endIsLength);
00352 
00353     // Create a Slicer for a 3-dim array.
00354     Slicer (const Slice& x, const Slice& y, const Slice& z,
00355             LengthOrLast endInterpretation = endIsLength);
00356     // </group>
00357 
00358     // Copy constructor (copy semantics).
00359     Slicer (const Slicer&);
00360 
00361     // Assignment (copy semantics).
00362     Slicer& operator= (const Slicer&);
00363 
00364     // Equality
00365     Bool operator==(const Slicer&) const;
00366 
00367     // Return the number of dimensions of the Slicer.
00368     uInt ndim() const;
00369 
00370     // This function checks all of the start, length (or end),
00371     // and stride IPositions, and fills in missing values by
00372     // getting the corresponding values from the shape of the
00373     // source array.
00374     // These will first be resized, if necessary.
00375     // If, for a given axis, (end < start) , it means that a 
00376     // length of zero was specified.
00377     // An exception is thrown if the
00378     // start, end, or length exceeds the array shape or if the
00379     // dimensionality of the array and Slicer do not conform.
00380     // <thrown>
00381     //   <li> ArraySlicerError
00382     // </thrown>
00383     IPosition inferShapeFromSource 
00384            (const IPosition& shape, IPosition& startResult,
00385             IPosition& endResult, IPosition& strideResult) const;
00386 
00387     // Report the defined starting position.
00388     const IPosition& start() const;
00389 
00390     // Report the defined ending position. 
00391     const IPosition& end() const;
00392 
00393     // Report the defined stride.
00394     const IPosition& stride() const;
00395 
00396     // Report the length of the resulting axes.
00397     const IPosition& length() const;
00398 
00399     // Are all values fixed (i.e., no MimicSource given)?
00400     Bool isFixed() const;
00401 
00402     // Set the start and end positions. No explicit checking is done that
00403     // the input parameters make sense, so you must be certain if you
00404     // call these. These are useful if you have a loop with many iterations
00405     // and you do not wish the overhead of creating a new Slicer object
00406     // for each iteration if the only thing you are doing is adjusting
00407     // the start and end positions. Other than for performance reasons,
00408     // these methods should not be called and you should prefer the
00409     // error checking provided by constructing a new Slicer object.
00410     // Note that the length is not updated, so in principle care should
00411     // be taken that the length does not change.
00412     // <group>
00413     void setStart (const IPosition& start)
00414       { start_p = start; }
00415     void setEnd (const IPosition& end)
00416       { end_p = end; }
00417     // </group>
00418 
00419 
00420 private:
00421     LengthOrLast asEnd_p;
00422     IPosition    start_p;
00423     IPosition    end_p;
00424     IPosition    stride_p;
00425     IPosition    len_p;         // Length of input
00426     Bool         fixed_p;       // no MimicSource used
00427 
00428     // Define a private constructor taking an ssize_t.
00429     // This is to prevent the user from the unexpected and meaningless
00430     // Slicer that would result when the ssize_t argument is promoted to
00431     // an IPosition.
00432     Slicer (ssize_t);
00433 
00434     // Check the given start, end/length and stride.
00435     // Fill in the length or end.
00436     // It also calls <src>fillFixed</src> to fill the fixed flag.
00437     void fillEndLen();
00438 
00439     // Fill in start, len and stride from a Slice.
00440     void fillSlice (const Slice&, ssize_t& start, ssize_t& length,
00441                     ssize_t& stride);
00442 
00443     // Fill the fixed flag.
00444     void fillFixed();
00445 };
00446 
00447 
00448 // <summary>IO functions for Slicer's</summary>
00449 // <group name="Slicer IO">
00450 // Print the contents of the specified Slicer to the specified stream.
00451 std::ostream& operator << (std::ostream& stream, const Slicer& slicer);
00452 // </group>
00453 
00454 
00455 
00456 inline uInt Slicer::ndim() const
00457     { return start_p.nelements(); }
00458 
00459 inline const IPosition& Slicer::start() const
00460     { return start_p; }
00461 
00462 inline const IPosition& Slicer::end() const
00463     { return end_p; }
00464 
00465 inline const IPosition& Slicer::stride() const
00466     { return stride_p; }
00467 
00468 inline const IPosition& Slicer::length() const
00469     { return len_p; }
00470 
00471 inline Bool Slicer::isFixed() const
00472     { return fixed_p; }
00473 
00474 
00475 
00476 } //# NAMESPACE CASACORE - END
00477 
00478 #endif
00479 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 31 Aug 2016 for casa by  doxygen 1.6.1