//# Cube.h: A 3-D Specialization of the Array Class //# Copyright (C) 1993,1994,1995,1996,1999,2000,2001,2003 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id$ #ifndef CASA_CUBE_2_H #define CASA_CUBE_2_H #include "Array.h" namespace casacore { //#Begin casa namespace // A 3-D Specialization of the Array class // // // // Cube objects are three-dimensional specializations (e.g., more convenient // and efficient indexing) of the general Array class. You might also want // to look at the Array documentation to see inherited functionality. // // Generally the member functions of Array are also available in // Cube versions which take a pair of integers where the array // needs an IPosition. Since the Cube // is three-dimensional, the IPositions are overkill, although you may // use those versions if you want to. // // Cube ci(100,100,100); // Shape is 100x100 // ci.resize(50,50,50); // Shape now 50x50 // // // Slices may be taken with the Slice class. To take a slice, one "indexes" // with one Slice(start, length, inc) for each axis, where end and inc // are optional. Additionally, there is an xyPlane() // member function which return a Matrix which corresponds to some plane: // // Cube cube(10,20,30); // for(size_t i=0; i < 30; i++) { // cube.xyPlane(i) = i; // Set every 10x20 plane to its "height" // } // // // Element-by-element arithmetic and logical operations are available (in // aips/ArrayMath.h and aips/ArrayLogical.h). // // As with the Arrays, if the preprocessor symbol AIPS_DEBUG is // defined at compile time invariants will be checked on entry to most // member functions. Additionally, if AIPS_ARRAY_INDEX_CHECK is defined // index operations will be bounds-checked. Neither of these should // be defined for production code. template class Cube : public Array { public: // A Cube of length zero in each dimension; zero origin. Cube(const Alloc& allocator=Alloc()); // A l1xl2xl3 sized cube. // Fill it with the initial value. Cube(size_t l1, size_t l2, size_t l3, const T &initialValue=T(), const Alloc& allocator=Alloc()); // An uninitialized l1xl2xl3 sized cube. Cube(size_t l1, size_t l2, size_t l3, typename Array::uninitializedType, const Alloc& allocator=Alloc()); // A Cube where the shape ("len") is defined with IPositions. // Fill it with the initial value. Cube(const IPosition &length, const T &initialValue = T(), const Alloc& allocator=Alloc()); // An uninitialized Cube where the shape ("len") is defined with IPositions. Cube(const IPosition& length, typename Array::uninitializedType, const Alloc& allocator=Alloc()); // The copy constructor uses reference semantics. Cube(const Cube &); Cube(Cube &&); // Construct a cube by reference from "other". "other must have // ndim() of 3 or less. The warning which applies to the copy constructor // is also valid here. Cube(const Array &); Cube(Array &&); // Create an Cube of a given shape from a pointer. Cube(const IPosition &shape, T *storage, StorageInitPolicy policy = COPY); // Create an Cube of a given shape from a pointer. Cube(const IPosition &shape, T *storage, StorageInitPolicy policy, const Alloc& allocator); // Create an Cube of a given shape from a pointer. Because the pointer // is const, a copy is always made. Cube(const IPosition &shape, const T *storage); // Resize to the given shape. // Resize without argument is equal to resize(0,0,0). // using Array::resize; void resize(size_t nx, size_t ny, size_t nz, bool copyValues=false); // // Copy the values from other to this cube. If this cube has zero // elements then it will resize to be the same shape as other; otherwise // other must conform to this. // Note that the assign function can be used to assign a // non-conforming cube. // Cube &operator=(const Cube& source) { Array::operator=(source); return *this; } Cube &operator=(Cube&& source) { Array::operator=(std::move(source)); return *this; } Cube& operator=(const Array& source) { // TODO is it highly confusing that operator= is specialized for Cube, e.g. // this is allowed: // Cube cube(5,1,1); // Vector v(5,0); // cube = v; // But this is not: // Array arr(IPosition{5,1,1}); // Vector v(5,0); // arr = v; // If it should be allowed to assign from dim(5,1,1) to dim(5), this should // be supported already by the Array class so that the semantics are the // same! if (source.ndim() == 3) { Array::operator=(source); } else { // This might work if a.ndim == 1 or 2 (*this) = Cube(source); } return *this; } Cube& operator=(Array&& source) { if (source.ndim() == 3) { Array::operator=(std::move(source)); } else { (*this) = Cube(std::move(source)); } return *this; } // // Copy val into every element of this cube; i.e. behaves as if // val were a constant conformant cube. Array &operator=(const T &val) { return Array::operator=(val); } // Copy to this those values in marray whose corresponding elements // in marray's mask are true. // TODO //Cube &operator= (const MaskedArray &marray) // { Array (*this) = marray; return *this; } // Single-pixel addressing. If AIPS_ARRAY_INDEX_CHECK is defined, // bounds checking is performed. // T &operator()(const IPosition &i) { return Array::operator()(i); } const T &operator()(const IPosition &i) const { return Array::operator()(i); } T &operator()(size_t i1, size_t i2, size_t i3) { return this->begin_p[index(i1, i2, i3)]; } const T &operator()(size_t i1, size_t i2, size_t i3) const { return this->begin_p[index(i1, i2, i3)]; } // // Take a slice of this cube. Slices are always indexed starting // at zero. This uses reference semantics, i.e. changing a value // in the slice changes the original. // // Cube vd(100,100,100); // //... // vd(Slice(0,10),Slice(10,10,Slice(0,10))) = -1.0; // sub-cube set to -1.0 // // Cube operator()(const Slice &sliceX, const Slice &sliceY, const Slice &sliceZ); const Cube operator()(const Slice &sliceX, const Slice &sliceY, const Slice &sliceZ) const; // // Slice using IPositions. Required to be defined, otherwise the base // class versions are hidden. // Array operator()(const IPosition &blc, const IPosition &trc, const IPosition &incr) { return Array::operator()(blc,trc,incr); } const Array operator()(const IPosition &blc, const IPosition &trc, const IPosition &incr) const { return Array::operator()(blc,trc,incr); } Array operator()(const IPosition &blc, const IPosition &trc) { return Array::operator()(blc,trc); } const Array operator()(const IPosition &blc, const IPosition &trc) const { return Array::operator()(blc,trc); } Array operator()(const Slicer& slicer) { return Array::operator()(slicer); } const Array operator()(const Slicer& slicer) const { return Array::operator()(slicer); } // // The array is masked by the input LogicalArray. // This mask must conform to the array. // // Return a MaskedArray. const MaskedArray operator() (const LogicalArray &mask) const { return Array::operator() (mask); } // Return a MaskedArray. MaskedArray operator() (const LogicalArray &mask) { return Array::operator() (mask); } // // The array is masked by the input MaskedLogicalArray. // The mask is effectively the AND of the internal LogicalArray // and the internal mask of the MaskedLogicalArray. // The MaskedLogicalArray must conform to the array. // // Return a MaskedArray. const MaskedArray operator() (const MaskedLogicalArray &mask) const { return Array::operator() (mask); } // Return a MaskedArray. MaskedArray operator() (const MaskedLogicalArray &mask) { return Array::operator() (mask); } // // Extract a plane as a matrix referencing the original data. // Of course you could also use a Matrix // iterator on the cube. // Matrix xyPlane(size_t zplane); const Matrix xyPlane(size_t zplane) const; Matrix xzPlane(size_t yplane); const Matrix xzPlane(size_t yplane) const; Matrix yzPlane(size_t xplane); const Matrix yzPlane(size_t xplane) const; // // The length of each axis of the cube. const IPosition &shape() const { return this->length_p; } void shape(int &s1, int &s2, int &s3) const { s1 = this->length_p(0); s2=this->length_p(1); s3=this->length_p(2); } // The number of rows in the Cube, i.e. the length of the first axis. size_t nrow() const { return this->length_p(0); } // The number of columns in the Cube, i.e. the length of the 2nd axis. size_t ncolumn() const { return this->length_p(1); } // The number of planes in the Cube, i.e. the length of the 3rd axis. size_t nplane() const { return this->length_p(2); } // Checks that the cube is consistent (invariants check out). virtual bool ok() const override; protected: virtual void preTakeStorage(const IPosition &shape) override; // Remove the degenerate axes from other and store result in this cube. // An exception is thrown if removing degenerate axes does not result // in a cube. virtual void doNonDegenerate(const Array &other, const IPosition &ignoreAxes) override; size_t fixedDimensionality() const override { return 3; } private: // Cached constants to improve indexing. //size_t xinc_p, yinc_p, zinc_p; // Helper fn to calculate the indexing constants. //void makeIndexingConstants(); size_t xinc() const { return this->inc_p(0); } size_t yinc() const { return this->inc_p(1)*this->originalLength_p(0); } size_t zinc() const { return this->inc_p(2)*this->originalLength_p(0)*this->originalLength_p(1); } size_t index(size_t i1, size_t i2, size_t i3) const { return xinc()*i1 + this->originalLength_p(0)*(this->inc_p(1)*i2 + this->inc_p(2)*this->originalLength_p(1)*i3); } size_t index_continuous(size_t i1, size_t i2, size_t i3) const { return i1 + this->originalLength_p(0)*(this->inc_p(1)*i2 + this->inc_p(2)*this->originalLength_p(1)*i3); } }; } //#End casa namespace #include "Cube.tcc" #endif