regularData3D.h

Go to the documentation of this file.
00001 // -*- Mode: C++; tab-width: 2; -*-
00002 // vi: set ts=2:
00003 //
00004 // $Id: regularData3D.h,v 1.36.12.1 2007/03/25 21:23:40 oliver Exp $ 
00005 //
00006 
00007 #ifndef BALL_DATATYPE_REGULARDATA3D_H
00008 #define BALL_DATATYPE_REGULARDATA3D_H
00009 
00010 #ifndef BALL_MATHS_VECTOR3_H
00011 # include <BALL/MATHS/vector3.h>
00012 #endif
00013 
00014 #ifndef BALL_SYSTEM_FILE_H
00015 # include <BALL/SYSTEM/file.h>
00016 #endif
00017 
00018 #ifndef BALL_MATHS_COMMON_H
00019 # include <BALL/MATHS/common.h>
00020 #endif
00021 
00022 #include <iostream>
00023 #include <fstream>
00024 #include <iterator>
00025 #include <algorithm>
00026 
00027 namespace BALL 
00028 {
00042   template <typename ValueType>
00043   class TRegularData3D 
00044   {
00045     public:
00046 
00047     BALL_CREATE(TRegularData3D<ValueType>)
00048 
00049     
00052 
00054     class IndexType
00055     {
00056       public:
00057       inline IndexType() : x(0), y(0), z(0) {}
00058       inline IndexType(Position p) : x(p), y(p), z(p) {}
00059       inline IndexType(Position p, Position q, Position r) : x(p), y(q), z(r) {}
00060 
00062       Position x;
00064       Position y;
00066       Position z;
00067     };
00068 
00070     typedef std::vector<ValueType> VectorType;
00072     typedef TVector3<float> CoordinateType;
00074     typedef typename std::vector<ValueType>::iterator Iterator;
00076     typedef typename std::vector<ValueType>::const_iterator ConstIterator;
00078 
00079     //  STL compatibility types
00080     //
00081     typedef ValueType value_type;
00082     typedef typename std::vector<ValueType>::iterator iterator;
00083     typedef typename std::vector<ValueType>::const_iterator const_iterator;
00084     typedef typename std::vector<ValueType>::reference reference;
00085     typedef typename std::vector<ValueType>::const_reference const_reference;
00086     typedef typename std::vector<ValueType>::pointer pointer;
00087     typedef typename std::vector<ValueType>::difference_type difference_type;
00088     typedef typename std::vector<ValueType>::size_type size_type;
00089 
00093 
00097     TRegularData3D(); 
00098   
00101     TRegularData3D(const TRegularData3D<ValueType>& grid)
00102       throw(Exception::OutOfMemory);
00103 
00106     TRegularData3D(const CoordinateType& origin, const CoordinateType& dimension, const CoordinateType& spacing)
00107        throw(Exception::OutOfMemory);
00108 
00111     TRegularData3D(const CoordinateType& origin, const CoordinateType& x_axis, 
00112                    const CoordinateType& y_axis, const CoordinateType& z_axis, const IndexType& size)
00113        throw(Exception::OutOfMemory);
00114 
00117     TRegularData3D
00118       (const IndexType& size, 
00119        const CoordinateType& origin = CoordinateType(0.0),
00120        const CoordinateType& dimension = CoordinateType(1.0))
00121        throw(Exception::OutOfMemory);
00122 
00125     virtual ~TRegularData3D();
00126 
00130     virtual void clear();
00132 
00136 
00140     TRegularData3D& operator = (const TRegularData3D<ValueType>& data)
00141       throw(Exception::OutOfMemory);
00143 
00144 
00148 
00154     bool operator == (const TRegularData3D<ValueType>& grid) const;
00155 
00158     BALL_INLINE bool operator != (const TRegularData3D<ValueType>& grid) const {  return !this->operator == (grid); }
00159 
00161     BALL_INLINE bool empty() const { return data_.empty(); }
00162 
00164     bool isInside(const CoordinateType& r) const;
00166 
00170 
00171     BALL_INLINE ConstIterator begin() const { return data_.begin(); }
00173     BALL_INLINE ConstIterator end() const { return data_.end(); }
00175     BALL_INLINE Iterator begin() { return data_.begin(); }
00177     BALL_INLINE Iterator end() { return data_.end(); }
00179 
00183 
00184     // STL compatibility
00185     BALL_INLINE size_type size() const { return data_.size(); }
00186     BALL_INLINE size_type max_size() const { return data_.max_size(); }
00187     BALL_INLINE void swap(TRegularData3D<ValueType>& grid) { std::swap(*this, grid); }
00188 
00189 
00191     const vector<ValueType>& getData() const;
00192 
00196     const ValueType& getData(const IndexType& index) const
00197       throw(Exception::OutOfGrid);
00198 
00202     ValueType& getData(const IndexType& index)
00203       throw(Exception::OutOfGrid);
00204 
00208     const ValueType& getData(Position index) const
00209       throw(Exception::OutOfGrid);
00210 
00214     ValueType& getData(Position index)
00215       throw(Exception::OutOfGrid);
00216 
00221     const ValueType& operator [] (const IndexType& index) const 
00222     {   
00223       return data_[index.x + size_.x * index.y + index.z * size_.x * size_.y]; 
00224     }
00225 
00230     ValueType& operator [] (const IndexType& index)
00231     {   
00232       return data_[index.x + size_.x * index.y + index.z * size_.x * size_.y]; 
00233     }
00234 
00239     const ValueType& operator [] (Position index) const { return data_[index]; }
00240 
00245     ValueType& operator [] (Position index) { return data_[index]; }
00246 
00257     ValueType operator () (const CoordinateType& x) const;
00258     
00264     ValueType getInterpolatedValue(const CoordinateType& x) const
00265       throw(Exception::OutOfGrid);
00266 
00272     const ValueType& getClosestValue(const CoordinateType& x) const
00273       throw(Exception::OutOfGrid);
00274 
00280     ValueType& getClosestValue(const CoordinateType& x)
00281       throw(Exception::OutOfGrid);
00282 
00288     IndexType getClosestIndex(const CoordinateType& v) const
00289       throw(Exception::OutOfGrid);
00290 
00295     IndexType getLowerIndex(const CoordinateType& v) const
00296       throw(Exception::OutOfGrid);
00297 
00303     inline const IndexType& getSize() const { return size_; }
00304     
00309     inline const CoordinateType& getOrigin() const { return origin_; }
00310 
00315     const CoordinateType& getSpacing() const {  return spacing_; }
00318     void setOrigin(const CoordinateType& origin) { origin_ = origin; }
00319 
00325     const CoordinateType& getDimension() const { return dimension_; }
00326 
00335     void setDimension(const CoordinateType& dimension)  
00336     {
00337       dimension_ = dimension;
00338       if (is_orthogonal_)
00339       {
00340         spacing_.x = dimension_.x / (double)(size_.x - 1);
00341         spacing_.y = dimension_.y / (double)(size_.y - 1);
00342         spacing_.z = dimension_.z / (double)(size_.z - 1);
00343       }
00344     }
00345 
00360     void resize(const IndexType& size)
00361       throw(Exception::OutOfMemory);
00362 
00374     void rescale(const IndexType& new_size)
00375       throw(Exception::OutOfMemory);
00376 
00381     CoordinateType getCoordinates(const IndexType& index) const
00382       throw(Exception::OutOfGrid);
00383 
00388     CoordinateType getCoordinates(Position index) const
00389       throw(Exception::OutOfGrid);
00390 
00406     void getEnclosingIndices
00407       (const CoordinateType& r,
00408       Position& llf, Position& rlf, Position& luf, Position& ruf,
00409       Position& llb, Position& rlb, Position& lub, Position& rub) const
00410       throw(Exception::OutOfGrid);
00411 
00415     void getEnclosingValues
00416       (const CoordinateType& r,
00417        ValueType& llf, ValueType& rlf, ValueType& luf, ValueType& ruf,
00418        ValueType& llb, ValueType& rlb, ValueType& lub, ValueType& rub) const
00419       throw(Exception::OutOfGrid);
00420     
00425     void binaryWrite(const String& filename) const
00426       throw(Exception::FileNotFound);   
00427 
00434     void binaryWriteRaw(const String& filename) const
00435       throw(Exception::FileNotFound);
00436 
00441     void binaryRead(const String& filename)
00442       throw(Exception::FileNotFound);
00444   
00445     protected:
00446       
00448     const CoordinateType mapToCartesian_(CoordinateType r) const
00449     {
00450       Vector3 result;
00451       r.x /= (size_.x - 1.);
00452       r.y /= (size_.y - 1.);
00453       r.z /= (size_.z - 1.);
00454 
00455       result.x = mapping_[0] * r.x + mapping_[1] * r.y + mapping_[2] * r.z + origin_.x;
00456       result.y = mapping_[3] * r.x + mapping_[4] * r.y + mapping_[5] * r.z + origin_.y;
00457       result.z = mapping_[6] * r.x + mapping_[7] * r.y + mapping_[8] * r.z + origin_.z;
00458 
00459       return result;
00460     }
00461     
00463     const CoordinateType mapInverse_(CoordinateType r) const
00464     {
00465       r -= origin_;
00466 
00467       Vector3 result;
00468       result.x = inverse_mapping_[0] * r.x + inverse_mapping_[1] * r.y + inverse_mapping_[2] * r.z;
00469       result.y = inverse_mapping_[3] * r.x + inverse_mapping_[4] * r.y + inverse_mapping_[5] * r.z;
00470       result.z = inverse_mapping_[6] * r.x + inverse_mapping_[7] * r.y + inverse_mapping_[8] * r.z;
00471 
00472       result.x *= (size_.x - 1);
00473       result.y *= (size_.y - 1);
00474       result.z *= (size_.z - 1);
00475 
00476       return result;
00477     }
00478     
00480     VectorType data_;
00481 
00483     CoordinateType  origin_;
00484 
00486     CoordinateType  dimension_;
00487 
00489     CoordinateType  spacing_;
00490 
00492     IndexType size_;
00493 
00495     typedef struct { ValueType bt[1024]; } BlockValueType;
00496 
00498     bool is_orthogonal_;
00499 
00501     std::vector<double> mapping_;
00502     std::vector<double> inverse_mapping_;
00503   };
00504 
00507   typedef TRegularData3D<float> RegularData3D;
00508 
00509   // default constructor.
00510   template <class ValueType>
00511   TRegularData3D<ValueType>::TRegularData3D()
00512     : data_(0),
00513       origin_(0.0),
00514       dimension_(0.0),
00515       spacing_(1.0),
00516       size_(0, 0, 0),
00517       is_orthogonal_(true)
00518   {
00519   }
00520 
00521   // copy constructor
00522   template <class ValueType>
00523   TRegularData3D<ValueType>::TRegularData3D
00524     (const TRegularData3D<ValueType>& data)
00525     throw(Exception::OutOfMemory)
00526     : data_(),
00527       origin_(data.origin_),
00528       dimension_(data.dimension_),
00529       spacing_(data.spacing_),
00530       size_(data.size_),
00531       is_orthogonal_(data.is_orthogonal_),
00532       mapping_(data.mapping_),
00533       inverse_mapping_(data.inverse_mapping_)
00534   {
00535     try
00536     {
00537       data_ = data.data_;
00538     }
00539     catch (std::bad_alloc&)
00540     {
00541       data_.resize(0);
00542       throw Exception::OutOfMemory(__FILE__, __LINE__, data.data_.size() * sizeof(ValueType));
00543     }
00544   }
00545 
00546   template <class ValueType>
00547   TRegularData3D<ValueType>::TRegularData3D
00548     (const typename TRegularData3D<ValueType>::IndexType& size,
00549      const typename TRegularData3D<ValueType>::CoordinateType& origin,
00550      const typename TRegularData3D<ValueType>::CoordinateType& dimension)
00551     throw(Exception::OutOfMemory)
00552     : data_(),
00553       origin_(origin),
00554       dimension_(dimension),
00555       spacing_(0.0),
00556       size_(size),
00557       is_orthogonal_(true)
00558   {
00559     // Compute the grid spacing
00560     spacing_.x = dimension_.x / (double)(size_.x - 1);
00561     spacing_.y = dimension_.y / (double)(size_.y - 1);
00562     spacing_.z = dimension_.z / (double)(size_.z - 1);
00563 
00564     // Compute the number of grid points
00565     size_type number_of_points = size_.x * size_.y * size_.z;
00566     try
00567     {
00568       data_.resize(number_of_points);
00569     }
00570     catch (std::bad_alloc&)
00571     {
00572       data_.resize(0);
00573       throw Exception::OutOfMemory(__FILE__, __LINE__, number_of_points * sizeof(ValueType));
00574     }
00575   }
00576 
00577 
00578   template <class ValueType>
00579   TRegularData3D<ValueType>::TRegularData3D
00580     (const typename TRegularData3D<ValueType>::CoordinateType& origin,
00581      const typename TRegularData3D<ValueType>::CoordinateType& dimension,
00582      const typename TRegularData3D<ValueType>::CoordinateType& spacing)
00583     throw(Exception::OutOfMemory)
00584     : data_(),
00585       origin_(origin),
00586       dimension_(dimension),
00587       spacing_(spacing),
00588       size_(0),
00589       is_orthogonal_(true)
00590   {
00591     // Compute the grid size
00592     size_.x = (Size)(dimension_.x / spacing_.x + 0.5) + 1;
00593     size_.y = (Size)(dimension_.y / spacing_.y + 0.5) + 1;
00594     size_.z = (Size)(dimension_.z / spacing_.z + 0.5) + 1;
00595 
00596     // Compute the number of grid points
00597     size_type size = size_.x * size_.y * size_.z;
00598     try
00599     {
00600       data_ .resize(size);
00601     }
00602     catch (std::bad_alloc&)
00603     {
00604       data_.resize(0);
00605       throw Exception::OutOfMemory(__FILE__, __LINE__, size * sizeof(ValueType));
00606     }
00607 
00608     // Adjust the spacing -- dimension has precedence.
00609     spacing_.x = dimension_.x / (double)(size_.x - 1);
00610     spacing_.y = dimension_.y / (double)(size_.y - 1);
00611     spacing_.z = dimension_.z / (double)(size_.z - 1);
00612   }
00613 
00614   template <class ValueType>
00615   TRegularData3D<ValueType>::TRegularData3D
00616     (const typename TRegularData3D<ValueType>::CoordinateType& origin, 
00617      const typename TRegularData3D<ValueType>::CoordinateType& x_axis,
00618      const typename TRegularData3D<ValueType>::CoordinateType& y_axis, 
00619      const typename TRegularData3D<ValueType>::CoordinateType& z_axis, 
00620      const typename TRegularData3D<ValueType>::IndexType& new_size)
00621     throw(Exception::OutOfMemory)
00622     : data_(),
00623       origin_(origin),
00624       dimension_(x_axis+y_axis+z_axis),
00625       spacing_(0.0),
00626       size_(new_size),
00627       is_orthogonal_(false)
00628   {
00629     // compute the spacing
00630     spacing_.x = x_axis.getLength() / (new_size.x - 1.);
00631     spacing_.y = y_axis.getLength() / (new_size.y - 1.);
00632     spacing_.z = z_axis.getLength() / (new_size.z - 1.);  
00633 
00634     size_type size = size_.x * size_.y * size_.z;
00635     try
00636     {
00637       data_.resize(size);
00638     }
00639     catch (std::bad_alloc&)
00640     {
00641       data_.resize(0);
00642       throw Exception::OutOfMemory(__FILE__, __LINE__, size * sizeof(ValueType));
00643     }
00644 
00645     // prepare the mapping matrix and its inverse
00646     mapping_.resize(9);
00647     inverse_mapping_.resize(9);
00648 
00649     mapping_[0] = x_axis.x; mapping_[1] = y_axis.x; mapping_[2] = z_axis.x;
00650     mapping_[3] = x_axis.y; mapping_[4] = y_axis.y; mapping_[5] = z_axis.y;
00651     mapping_[6] = x_axis.z; mapping_[7] = y_axis.z; mapping_[8] = z_axis.z;
00652 
00653     // this is numerically instable and only works well for the "simple"
00654     // cases. should be replaced by QR or an SVD
00655 
00656     // just for readability
00657     double a = mapping_[0]; double b = mapping_[1]; double c = mapping_[2];
00658     double d = mapping_[3]; double e = mapping_[4]; double f = mapping_[5];
00659     double g = mapping_[6]; double h = mapping_[7]; double i = mapping_[8];
00660 
00661     double determinant = 1. / (a*(e*i - f*h) - b*(d*i - f*g) + c*(d*h - e*g));
00662 
00663     inverse_mapping_[0] = determinant * (e*i - f*h);
00664     inverse_mapping_[1] = determinant * (b*i - c*h);
00665     inverse_mapping_[2] = determinant * (b*f - c*e);
00666 
00667     inverse_mapping_[3] = determinant * (f*g - d*i);
00668     inverse_mapping_[4] = determinant * (a*i - c*g);
00669     inverse_mapping_[5] = determinant * (c*d - a*f);
00670 
00671     inverse_mapping_[6] = determinant * (d*h - e*g);
00672     inverse_mapping_[7] = determinant * (b*g - a*h);
00673     inverse_mapping_[8] = determinant * (a*e - b*d);
00674   }   
00675 
00676   template <class ValueType>
00677   TRegularData3D<ValueType>::~TRegularData3D()
00678   {
00679   }
00680 
00681   template <typename ValueType>
00682   BALL_INLINE
00683   TRegularData3D<ValueType>& TRegularData3D<ValueType>::operator =
00684     (const TRegularData3D<ValueType>& rhs)
00685     throw(Exception::OutOfMemory)
00686   {
00687     // Avoid self-assignment.
00688     if (&rhs != this)
00689     {
00690       // Copy the coordinate-related attributes and
00691       // the size.
00692       origin_ = rhs.origin_;
00693       dimension_ = rhs.dimension_;
00694       spacing_ = rhs.spacing_;
00695       size_ = rhs.size_;
00696       
00697       is_orthogonal_ = rhs.is_orthogonal_;
00698       mapping_ = rhs.mapping_;
00699       inverse_mapping_ = rhs.inverse_mapping_;
00700       // Copy the data itself and rethrow allocation exceptions.
00701       try
00702       {
00703         data_ = rhs.data_;
00704       }
00705       catch (std::bad_alloc&)
00706       {
00707         data_.resize(0);
00708         throw Exception::OutOfMemory(__FILE__, __LINE__, rhs.data_.size() * sizeof(ValueType));
00709       }
00710     }
00711 
00712     return *this;
00713   }
00714 
00715   template <typename ValueType>
00716   void TRegularData3D<ValueType>::resize(const typename TRegularData3D<ValueType>::IndexType& size)
00717     throw(Exception::OutOfMemory)
00718   {
00719     if (is_orthogonal_)
00720     {
00721       // If the old size equals the new size, we're done.
00722       if ((size.x == size_.x) && (size_.y == size.y) && (size_.z == size.z))
00723       {
00724         return;
00725       }
00726 
00727       // If the new grid is empty, this whole thing is quite easy.
00728       if ((size.x == 0) || (size.y == 0) || (size.z == 0))
00729       {
00730         data_.resize(0);
00731         dimension_.set(0.0, 0.0, 0.0);
00732         return;
00733       }
00734       // Compute the new array size.
00735       size_type new_size = (size_type)(size.x * size.y * size.z);
00736 
00737       // Catch any bad_allocs thrown by vector::resize
00738       try
00739       {
00740         // Create a new temporary array.
00741         std::vector<ValueType> old_data(data_);
00742 
00743         // Resize the data to its new size.
00744         data_.resize(new_size);
00745 
00746         // walk over the new grid and copy the old stuff back.
00747         static ValueType default_value = (ValueType)0;
00748         for (size_type i = 0; i < new_size; i++)
00749         {
00750           size_type x = i % size.x;
00751           size_type y = (i % (size.x * size.y)) / size.x;
00752           size_type z = i / (size.x * size.y);
00753           if ((x >= size_.x) || (y >= size_.y) || (z >= size_.z))
00754           {
00755             data_[i] = default_value;
00756           }
00757           else
00758           {
00759             data_[i] = old_data[x + y * size_.x + z * size_.x * size_.y];
00760           }
00761         }
00762 
00763         // Correct the grid dimension. Origin and spacing remain constant.
00764         if ((size_.x != 0) && (size_.y != 0) && (size_.z != 0))
00765         {
00766           dimension_.x *= (double)size.x / (double)size_.x;
00767           dimension_.y *= (double)size.y / (double)size_.y;
00768           dimension_.z *= (double)size.z / (double)size_.z;
00769         }
00770         size_ = size;
00771       }
00772       catch (std::bad_alloc&)
00773       {
00774         throw Exception::OutOfMemory(__FILE__, __LINE__, new_size * (Size)sizeof(ValueType));
00775       }
00776     }
00777   }
00778 
00779   template <typename ValueType>
00780   void TRegularData3D<ValueType>::rescale(const typename TRegularData3D<ValueType>::IndexType& size)
00781     throw(Exception::OutOfMemory)
00782   {
00783     if (is_orthogonal_)
00784     {
00785       // If the old size equals the new size, we're done.
00786       if ((size.x == size_.x) && (size_.y == size.y) && (size_.z == size.z))
00787       {
00788         return;
00789       }
00790 
00791       // If the new grid is empty, this whole thing is quite easy.
00792       if ((size.x == 0) || (size.y == 0) || (size.z == 0))
00793       {
00794         data_.resize(0);
00795         dimension_.set(0.0);
00796         return;
00797       }
00798 
00799       // Compute the new array size.
00800       size_type new_size = (size_type)(size.x * size.y * size.z);
00801 
00802       // Catch any bad_allocs thrown by vector::resize
00803       try
00804       {
00805         // Create a new temporary array.
00806         TRegularData3D<ValueType> old_data(*this);
00807 
00808         // Resize the data array to its new size.
00809         data_.resize(new_size);
00810         spacing_.x = dimension_.x / (double)(size.x - 1);
00811         spacing_.y = dimension_.y / (double)(size.y - 1);
00812         spacing_.z = dimension_.z / (double)(size.z - 1);
00813 
00814         // Correct the grid size. Origin and dimension remain constant.
00815         size_ = size;
00816 
00817         // Walk over the new grid and copy the (interpolated) old stuff back.
00818         for (size_type i = 0; i < data_.size(); i++)
00819         {
00820           try
00821           {
00822             data_[i] = old_data.getInterpolatedValue(getCoordinates(i));
00823           }
00824           catch (Exception::OutOfGrid&)
00825           {
00826             data_[i] = old_data.getClosestValue(getCoordinates(i));
00827           }
00828         }
00829       }
00830       catch (std::bad_alloc&)
00831       {
00832         throw Exception::OutOfMemory(__FILE__, __LINE__, new_size * (Size)sizeof(ValueType));
00833       }
00834     }
00835   }
00836 
00837   template <class ValueType> 
00838   BALL_INLINE
00839   bool TRegularData3D<ValueType>::isInside(const typename TRegularData3D<ValueType>::CoordinateType& r) const   
00840   {
00841     if (is_orthogonal_)
00842     {
00843       return !((r.x > (origin_.x + dimension_.x )) 
00844           || (r.y > (origin_.y + dimension_.y))  
00845           || (r.z > (origin_.z + dimension_.z))
00846           || (r.x < origin_.x) || (r.y < origin_.y) || (r.z < origin_.z));
00847     } 
00848     else 
00849     {
00850       // compute A^-1 * pos and see whether the indices are part of the grid
00851       CoordinateType ri = mapInverse_(r);
00852       ri.x = Maths::round(ri.x);
00853       ri.y = Maths::round(ri.y);
00854       ri.z = Maths::round(ri.z);
00855       
00856       return !(   (ri.x < 0) || (ri.y < 0) || (ri.z < 0)
00857                || (ri.x >= size_.x) || (ri.y >= size_.y) || (ri.z >= size_.z) );
00858     }
00859   }
00860 
00861   template <class ValueType>
00862   BALL_INLINE
00863   const ValueType& TRegularData3D<ValueType>::getData
00864     (const typename TRegularData3D<ValueType>::IndexType& index) const
00865     throw(Exception::OutOfGrid)
00866   {
00867     size_type pos = index.x + index.y * size_.x + index.z * size_.x * size_.y;
00868     if (pos >= data_.size())
00869     {
00870       throw Exception::OutOfGrid(__FILE__, __LINE__);
00871     }
00872     return data_[pos];
00873   }
00874 
00875   template <class ValueType>
00876   BALL_INLINE
00877   const vector<ValueType>& TRegularData3D<ValueType>::getData() const
00878   {
00879     return data_;
00880   }
00881 
00882   template <typename ValueType>
00883   BALL_INLINE
00884   ValueType& TRegularData3D<ValueType>::getData
00885     (const typename TRegularData3D<ValueType>::IndexType& index)
00886     throw(Exception::OutOfGrid)
00887   {
00888     size_type pos = index.x + index.y * size_.x + index.z * size_.x * size_.y;
00889     if (pos >= data_.size())
00890     {
00891       throw Exception::OutOfGrid(__FILE__, __LINE__);
00892     }
00893     return data_[pos];
00894   }
00895 
00896   template <class ValueType>
00897   BALL_INLINE
00898   const ValueType& TRegularData3D<ValueType>::getData(Position index) const
00899     throw(Exception::OutOfGrid)
00900   {
00901     if (index >= data_.size())
00902     {
00903       throw Exception::OutOfGrid(__FILE__, __LINE__);
00904     }
00905     return data_[index];
00906   }
00907 
00908   template <class ValueType>
00909   BALL_INLINE
00910   ValueType& TRegularData3D<ValueType>::getData(Position index)
00911     throw(Exception::OutOfGrid)
00912   {
00913     if (index >= data_.size())
00914     {
00915       throw Exception::OutOfGrid(__FILE__, __LINE__);
00916     }
00917     return data_[index];
00918   }
00919 
00920   template <class ValueType>
00921   BALL_INLINE
00922   typename TRegularData3D<ValueType>::CoordinateType TRegularData3D<ValueType>::getCoordinates
00923     (const typename TRegularData3D<ValueType>::IndexType& index) const
00924     throw(Exception::OutOfGrid)
00925   {
00926     if ((index.x >= size_.x) || (index.y >= size_.y) || (index.z >= size_.z))
00927     {
00928       throw Exception::OutOfGrid(__FILE__, __LINE__);
00929     }
00930 
00931     if (is_orthogonal_)
00932     {
00933       CoordinateType r(origin_.x + index.x * spacing_.x,
00934           origin_.y + index.y * spacing_.y,
00935           origin_.z + index.z * spacing_.z);
00936       return r;
00937     }
00938     else
00939     {
00940       CoordinateType r(index.x, index.y, index.z);
00941       r = mapToCartesian_(r);
00942 
00943       return r;
00944     }
00945   }
00946 
00947   template <class ValueType>
00948   BALL_INLINE
00949   typename TRegularData3D<ValueType>::CoordinateType
00950   TRegularData3D<ValueType>::getCoordinates(Position position) const
00951     throw(Exception::OutOfGrid)
00952   {
00953     if (position >= data_.size())
00954     {
00955       throw Exception::OutOfGrid(__FILE__, __LINE__);
00956     }
00957 
00958     Position x = (Position)(position %  size_.x);
00959     Position y = (Position)((position % (size_.x * size_.y))/ size_.x);
00960     Position z = (Position)(position / (size_.x * size_.y));
00961 
00962     if (is_orthogonal_)
00963     {
00964       return CoordinateType(origin_.x + (double)x * spacing_.x,
00965                             origin_.y + (double)y * spacing_.y,
00966                             origin_.z + (double)z * spacing_.z);
00967     }
00968     else
00969     {
00970       CoordinateType r(x,y,z);
00971       r = mapToCartesian_(r);
00972 
00973       return r;
00974     }
00975   }
00976 
00977   template <typename ValueType>
00978   BALL_INLINE
00979   void TRegularData3D<ValueType>::getEnclosingIndices
00980     (const typename TRegularData3D<ValueType>::CoordinateType& r,
00981     Position& llf, Position& rlf, Position& luf, Position& ruf,
00982     Position& llb, Position& rlb, Position& lub, Position& rub) const
00983     throw(Exception::OutOfGrid)
00984   {
00985     if (!isInside(r))
00986     {
00987       throw Exception::OutOfGrid(__FILE__, __LINE__);
00988     }   
00989 
00990     // calculate the grid indices of the lower left front corner
00991     // of the enclosing box
00992     IndexType position;
00993     if (is_orthogonal_)
00994     {
00995       position.x = (Position)((r.x - origin_.x) / spacing_.x);
00996       position.y = (Position)((r.y - origin_.y) / spacing_.y);
00997       position.z = (Position)((r.z - origin_.z) / spacing_.z);
00998     }
00999     else
01000     {
01001       CoordinateType pos = mapInverse_(r);
01002       position.x = (Position) pos.x;  
01003       position.y = (Position) pos.y;  
01004       position.z = (Position) pos.z;  
01005     } 
01006     
01007     // calculate the (linear) indices of the eight
01008     // box corners
01009     llf = position.x + size_.x * position.y 
01010         + size_.x * size_.y * position.z;
01011     rlf = llf + 1;
01012     luf = llf + size_.x;
01013     ruf = luf + 1;
01014     llb = llf + size_.x * size_.y;
01015     rlb = llb + 1;
01016     lub = llb + size_.x;
01017     rub = lub + 1;
01018   }
01019 
01020   template <typename ValueType>
01021   BALL_INLINE
01022   void TRegularData3D<ValueType>::getEnclosingValues
01023     (const typename TRegularData3D<ValueType>::CoordinateType& r,
01024     ValueType& llf, ValueType& rlf, ValueType& luf, ValueType& ruf,
01025     ValueType& llb, ValueType& rlb, ValueType& lub, ValueType& rub) const
01026     throw(Exception::OutOfGrid)
01027   {
01028     if (!isInside(r))
01029     {
01030       throw Exception::OutOfGrid(__FILE__, __LINE__);
01031     }   
01032     
01033     // compute the eight grid indices forming the enclosing box
01034     Position llf_idx, rlf_idx, luf_idx, ruf_idx, llb_idx, rlb_idx, lub_idx, rub_idx;
01035     getEnclosingIndices(r, llf_idx, rlf_idx, luf_idx, ruf_idx, llb_idx, rlb_idx, lub_idx, rub_idx);
01036         
01037     // retrieve the grid values
01038     llf = data_[llf_idx];
01039     rlf = data_[rlf_idx];
01040     luf = data_[luf_idx];
01041     ruf = data_[ruf_idx];
01042     llb = data_[llb_idx];
01043     rlb = data_[rlb_idx];
01044     lub = data_[lub_idx];
01045     rub = data_[rub_idx];
01046   }
01047 
01048   template <typename ValueType>
01049   BALL_INLINE
01050   ValueType TRegularData3D<ValueType>::getInterpolatedValue
01051     (const typename TRegularData3D<ValueType>::CoordinateType& r) const
01052     throw(Exception::OutOfGrid)
01053   {
01054     if (!isInside(r))
01055     {
01056       throw Exception::OutOfGrid(__FILE__, __LINE__);
01057     }   
01058     return operator () (r);
01059   }
01060 
01061   template <typename ValueType>
01062   BALL_INLINE
01063   ValueType TRegularData3D<ValueType>::operator ()
01064     (const typename TRegularData3D<ValueType>::CoordinateType& r) const
01065   {
01066     Position x;
01067     Position y;   
01068     Position z;   
01069     TVector3<double> r_0;
01070     
01071     if (is_orthogonal_)
01072     { 
01073       Vector3 h(r - origin_);
01074 
01075       x = (Position)(h.x / spacing_.x);
01076       y = (Position)(h.y / spacing_.y);
01077       z = (Position)(h.z / spacing_.z);
01078 
01079       while (x >= (size_.x - 1)) x--;
01080       while (y >= (size_.y - 1)) y--;
01081       while (z >= (size_.z - 1)) z--;
01082 
01083       r_0.x = origin_.x + x*spacing_.x;
01084       r_0.y = origin_.y + y*spacing_.y;
01085       r_0.z = origin_.z + z*spacing_.z;
01086     }
01087     else
01088     {
01089       Vector3 pos = mapInverse_(r);
01090       x = (Position) pos.x;
01091       y = (Position) pos.y;
01092       z = (Position) pos.z;
01093 
01094       while (x >= (size_.x - 1)) x--;
01095       while (y >= (size_.y - 1)) y--;
01096       while (z >= (size_.z - 1)) z--;
01097 
01098       // This can probably be done much faster...
01099       Vector3 lower_pos(x,y,z);
01100       lower_pos = mapToCartesian_(lower_pos);
01101       r_0.x = lower_pos.x;
01102       r_0.y = lower_pos.y;
01103       r_0.z = lower_pos.z;
01104     }
01105     
01106     Position Nx = size_.x;
01107     Position Nxy = size_.y * Nx;
01108     Position l = x + Nx * y + Nxy * z;
01109 
01110     double dx = 1. - ((double)(r.x - r_0.x) / spacing_.x);
01111     double dy = 1. - ((double)(r.y - r_0.y) / spacing_.y);
01112     double dz = 1. - ((double)(r.z - r_0.z) / spacing_.z);
01113 
01114     return  data_[l] * dx * dy * dz
01115           + data_[l + 1] * (1. - dx) * dy * dz
01116           + data_[l + Nx] * dx * (1. - dy) * dz
01117           + data_[l + Nx + 1] * (1. - dx) * (1. - dy) * dz
01118           + data_[l + Nxy] * dx * dy * (1. - dz)
01119           + data_[l + Nxy + 1] * (1. - dx) * dy * (1. - dz)
01120           + data_[l + Nxy + Nx] * dx * (1. - dy) * (1. - dz)
01121           + data_[l + Nxy + Nx + 1] * (1. - dx) * (1. - dy) * (1. - dz);
01122   }
01123 
01124   template <typename ValueType>
01125   BALL_INLINE
01126   typename TRegularData3D<ValueType>::IndexType TRegularData3D<ValueType>::getClosestIndex
01127     (const typename TRegularData3D<ValueType>::CoordinateType& r) const
01128     throw(Exception::OutOfGrid)
01129   {
01130     if (!isInside(r))
01131     {
01132       throw Exception::OutOfGrid(__FILE__, __LINE__);
01133     }
01134 
01135     static IndexType position;
01136 
01137     if (is_orthogonal_)
01138     {
01139       position.x = (Position)((r.x - origin_.x) / spacing_.x + 0.5);
01140       position.y = (Position)((r.y - origin_.y) / spacing_.y + 0.5);
01141       position.z = (Position)((r.z - origin_.z) / spacing_.z + 0.5);
01142     }
01143     else
01144     {
01145       Vector3 pos = mapInverse_(r);
01146       position.x = (Position) Maths::round(pos.x);
01147       position.y = (Position) Maths::round(pos.y);
01148       position.z = (Position) Maths::round(pos.z);
01149     }
01150       
01151     return position;
01152   }
01153 
01154   template <typename ValueType>
01155   BALL_INLINE
01156   typename TRegularData3D<ValueType>::IndexType  TRegularData3D<ValueType>::getLowerIndex
01157     (const typename TRegularData3D<ValueType>::CoordinateType& r) const
01158     throw(Exception::OutOfGrid)
01159   {
01160     if (!isInside(r))
01161     {
01162       throw Exception::OutOfGrid(__FILE__, __LINE__);
01163     }
01164 
01165     static IndexType position;
01166     if (is_orthogonal_)
01167     {
01168       position.x = (Position)((r.x - origin_.x) / spacing_.x);
01169       position.y = (Position)((r.y - origin_.y) / spacing_.y);
01170       position.z = (Position)((r.z - origin_.z) / spacing_.z);
01171     }
01172     else
01173     {
01174       Vector3 pos = mapInverse_(r);
01175       position.x = (Position)pos.x;
01176       position.y = (Position)pos.y;
01177       position.z = (Position)pos.z;
01178     }
01179 
01180     return position;
01181   }
01182 
01183   template <typename ValueType>
01184   BALL_INLINE
01185   const ValueType& TRegularData3D<ValueType>::getClosestValue
01186     (const typename TRegularData3D<ValueType>::CoordinateType& r) const
01187     throw(Exception::OutOfGrid)
01188   {
01189     if (!isInside(r))
01190     {
01191       throw Exception::OutOfGrid(__FILE__, __LINE__);
01192     }
01193 
01194     static IndexType position;
01195 
01196     if (is_orthogonal_)
01197     {
01198       position.x = (Position)((r.x - origin_.x) / spacing_.x + 0.5);
01199       position.y = (Position)((r.y - origin_.y) / spacing_.y + 0.5);
01200       position.z = (Position)((r.z - origin_.z) / spacing_.z + 0.5);
01201     }
01202     else
01203     {
01204       static Vector3 pos = mapInverse_(r);
01205       position.x = (Position) Maths::round(pos.x);
01206       position.y = (Position) Maths::round(pos.y);
01207       position.z = (Position) Maths::round(pos.z);
01208     }
01209 
01210     return operator [] (position);
01211   }
01212 
01213   template <typename ValueType>
01214   BALL_INLINE
01215   ValueType& TRegularData3D<ValueType>::getClosestValue
01216     (const typename TRegularData3D<ValueType>::CoordinateType& r)
01217     throw(Exception::OutOfGrid)
01218   {
01219     if (!isInside(r))
01220     {
01221       throw Exception::OutOfGrid(__FILE__, __LINE__);
01222     }
01223 
01224     static IndexType position;
01225 
01226     if (is_orthogonal_)
01227     {
01228       position.x = (Position)((r.x - origin_.x) / spacing_.x + 0.5);
01229       position.y = (Position)((r.y - origin_.y) / spacing_.y + 0.5);
01230       position.z = (Position)((r.z - origin_.z) / spacing_.z + 0.5);
01231     }
01232     else
01233     {
01234       static Vector3 pos = mapInverse_(r);
01235       position.x = (Position) Maths::round(pos.x);
01236       position.y = (Position) Maths::round(pos.y);
01237       position.z = (Position) Maths::round(pos.z);
01238     }
01239 
01240 
01241     return operator [] (position);
01242   }
01243 
01244 
01245   template <typename ValueType>
01246   void TRegularData3D<ValueType>::clear()
01247   {
01248     data_.resize(0);
01249 
01250     origin_.set(0.0);
01251     dimension_.set(0.0);
01252     size_.x = 0;
01253     size_.y = 0;
01254     size_.z = 0;
01255     spacing_.set(1.0);    
01256     is_orthogonal_ = true;
01257   }
01258 
01259   
01260   template <typename ValueType> 
01261   bool TRegularData3D<ValueType>::operator == (const TRegularData3D<ValueType>& grid) const 
01262   {
01263     return ((origin_ == grid.origin_)
01264             && (dimension_ == grid.dimension_)
01265             && (size_.x == grid.size_.x)
01266             && (size_.y == grid.size_.y)
01267             && (size_.z == grid.size_.z)
01268             && (data_ == grid.data_)
01269             && (is_orthogonal_ == grid.is_orthogonal_));
01270   } 
01271 
01272   template <typename ValueType>
01273   void TRegularData3D<ValueType>::binaryWrite(const String& filename) const
01274     throw(Exception::FileNotFound)
01275   {
01276     File outfile(filename, std::ios::out|std::ios::binary);
01277     if (!outfile.isValid()) throw Exception::FileNotFound(__FILE__, __LINE__, filename);
01278     
01279     BinaryFileAdaptor< BlockValueType > adapt_block;
01280     BinaryFileAdaptor< ValueType >       adapt_single;
01281     
01282     // TODO: check for endiannes and swap bytes accordingly
01283 
01284     // write all information we need to recreate the grid
01285     BinaryFileAdaptor<CoordinateType> adapt_coordinate;
01286     BinaryFileAdaptor<Size>           adapt_size;
01287 
01288     adapt_size.setData(data_.size());
01289     outfile << adapt_size;
01290     
01291     adapt_coordinate.setData(origin_);
01292     outfile << adapt_coordinate;
01293 
01294     adapt_coordinate.setData(dimension_);
01295     outfile << adapt_coordinate;
01296 
01297     adapt_coordinate.setData(spacing_);
01298     outfile << adapt_coordinate;
01299 
01300     BinaryFileAdaptor<IndexType> adapt_index;
01301     adapt_index.setData(size_);
01302     outfile << adapt_index;
01303   
01304     // we slide a window of size 1024 over our data
01305     Index window_pos = 0;
01306     
01307     while ( ((int)data_.size() - (1024 + window_pos)) >= 0 )
01308     {
01309       adapt_block.setData(* (BlockValueType*)&(data_[window_pos]));
01310       outfile << adapt_block;
01311       window_pos+=1024;
01312     }
01313 
01314     // now we have to write the remaining data one by one
01315     for (Size i=window_pos; i<data_.size(); i++)
01316     {
01317       adapt_single.setData(data_[i]);
01318       outfile << adapt_single;
01319     }
01320 
01321     // that's it. I hope...
01322     outfile.close();
01323   }
01324 
01325   template <typename ValueType>
01326   void TRegularData3D<ValueType>::binaryRead(const String& filename)
01327     throw(Exception::FileNotFound)
01328   {
01329     File infile(filename, std::ios::in|std::ios::binary);
01330     if (!infile.isValid()) throw Exception::FileNotFound(__FILE__, __LINE__, filename);
01331     
01332     BinaryFileAdaptor< BlockValueType > adapt_block;
01333     BinaryFileAdaptor< ValueType >      adapt_single;
01334     
01335     // TODO: check for endiannes and swap bytes accordingly
01336 
01337     // read all information we need to recreate the grid
01338     BinaryFileAdaptor<CoordinateType> adapt_coordinate;
01339     BinaryFileAdaptor<Size>           adapt_size;
01340 
01341     infile >> adapt_size;
01342     Size new_size = adapt_size.getData();
01343   
01344     infile >> adapt_coordinate;
01345     origin_ = adapt_coordinate.getData();
01346 
01347     infile >> adapt_coordinate;
01348     dimension_ = adapt_coordinate.getData();
01349 
01350     infile >> adapt_coordinate;
01351     spacing_ = adapt_coordinate.getData();
01352 
01353     BinaryFileAdaptor<IndexType> adapt_index;
01354     infile >> adapt_index;
01355     size_ =  adapt_index.getData();
01356   
01357     data_.resize(new_size);
01358 
01359     // we slide a window of size 1024 over our data
01360     Index window_pos = 0;
01361     
01362     while ( ((int)data_.size() - (1024 + window_pos)) >= 0 )
01363     {
01364       infile >> adapt_block;
01365       *(BlockValueType*)(&(data_[window_pos])) = adapt_block.getData();
01366       /*
01367       for (Size i=0; i<1024; i++)
01368       {
01369         data_[i+window_pos] = adapt_block.getData().bt[i];
01370       }
01371       */
01372       window_pos+=1024;
01373     }
01374 
01375     // now we have to read the remaining data one by one
01376     for (Size i=window_pos; i<data_.size(); i++)
01377     {
01378       infile >> adapt_single;
01379       data_[i] = adapt_single.getData();
01380     }
01381 
01382     // that's it. I hope...
01383     infile.close();
01384   }
01385 
01388 
01389   template <typename ValueType>
01390   std::ostream& operator << (std::ostream& os, const TRegularData3D<ValueType>& grid)
01391   {
01392     // Write the grid origin, dimension, and number of grid points
01393     os << grid.getOrigin().x << " " << grid.getOrigin().y << " " << grid.getOrigin().z
01394        << std::endl
01395        << grid.getOrigin().x + grid.getDimension().x << " " 
01396        << grid.getOrigin().y + grid.getDimension().y << " " 
01397        << grid.getOrigin().z + grid.getDimension().z
01398        << std::endl
01399        << grid.getSize().x - 1 << " " << grid.getSize().y - 1 << " " << grid.getSize().z - 1 
01400        << std::endl;
01401 
01402     // Write the array contents.
01403     std::copy(grid.begin(), grid.end(), std::ostream_iterator<ValueType>(os, "\n"));
01404 
01405     return os;
01406   }
01407 
01409   template <typename ValueType>
01410   std::istream& operator >> (std::istream& is, TRegularData3D<ValueType>& grid)
01411   {
01412     typename TRegularData3D<ValueType>::CoordinateType origin;
01413     typename TRegularData3D<ValueType>::CoordinateType dimension;
01414     typename TRegularData3D<ValueType>::IndexType size;
01415 
01416     is >> origin.x >> origin.y >> origin.z;
01417     is >> dimension.x >> dimension.y >> dimension.z;
01418     is >> size.x >> size.y >> size.z;
01419 
01420     dimension -= origin;
01421     size.x++;
01422     size.y++;
01423     size.z++;
01424 
01425     grid.resize(size);
01426     grid.setOrigin(origin);
01427     grid.setDimension(dimension);
01428     std::copy(std::istream_iterator<ValueType>(is), std::istream_iterator<ValueType>(), grid.begin());
01429 
01430     return is;
01431   }
01433   
01434  } // namespace BALL
01435 
01436 #endif // BALL_DATATYPE_REGULARDATA3D_H