regularData2D.h

Go to the documentation of this file.
00001 // -*- Mode: C++; tab-width: 2; -*-
00002 // vi: set ts=2:
00003 //
00004 // $Id: regularData2D.h,v 1.45 2005/05/28 15:52:48 anhi Exp $
00005 //
00006 
00007 #ifndef BALL_DATATYPE_REGULARDATA2D_H
00008 #define BALL_DATATYPE_REGULARDATA2D_H
00009 
00010 #ifndef BALL_MATHS_VECTOR2_H
00011 # include <BALL/MATHS/vector2.h>
00012 #endif
00013 
00014 #ifndef BALL_SYSTEM_FILE_H
00015 # include <BALL/SYSTEM/file.h>
00016 #endif
00017 
00018 #include <iostream>
00019 #include <fstream>
00020 #include <iterator>
00021 #include <algorithm>
00022 
00023 namespace BALL 
00024 {
00034   template <typename ValueType>
00035   class TRegularData2D 
00036   {
00037     public:
00038 
00039     BALL_CREATE(TRegularData2D<ValueType>)
00040 
00041     
00044 
00046     class IndexType
00047     {
00048       public:
00049       inline IndexType() : x(0), y(0) {}
00050       inline IndexType(Position p) : x(p), y(p) {}
00051       inline IndexType(Position p, Position q) : x(p), y(q) {}
00052 
00054       Position x;
00056       Position y;
00057 
00058     };
00059 
00061     typedef std::vector<ValueType> VectorType;
00063     typedef TVector2<float> CoordinateType;
00065     typedef typename std::vector<ValueType>::iterator Iterator;
00067     typedef typename std::vector<ValueType>::const_iterator ConstIterator;
00069 
00070     //  STL compatibility types
00071     //
00072     typedef ValueType value_type;
00073     typedef typename std::vector<ValueType>::iterator iterator;
00074     typedef typename std::vector<ValueType>::const_iterator const_iterator;
00075     typedef typename std::vector<ValueType>::reference reference;
00076     typedef typename std::vector<ValueType>::const_reference const_reference;
00077     typedef typename std::vector<ValueType>::pointer pointer;
00078     typedef typename std::vector<ValueType>::difference_type difference_type;
00079     typedef typename std::vector<ValueType>::size_type size_type;
00080 
00084 
00088     TRegularData2D();
00089 
00091     TRegularData2D(const TRegularData2D<ValueType>& data)
00092       throw(Exception::OutOfMemory);  
00093 
00100     TRegularData2D(const CoordinateType& origin, const CoordinateType& dimension, const CoordinateType& spacing)
00101        throw(Exception::OutOfMemory);
00102 
00103     /* Constructor.
00104        This constructor takes the size of the grid (as the number of grid points per dimension)
00105        as input and (optionally) the origin and the dimension (in grid <em>coordinates</em>).
00106        @exception OutOfMemory if insufficient memory is available to allocate the grid
00107     */
00108     TRegularData2D(const IndexType& size, 
00109                    const CoordinateType& origin = CoordinateType(0.0), 
00110                    const CoordinateType& dimension = CoordinateType(1.0))
00111       throw(Exception::OutOfMemory);
00112 
00115     virtual ~TRegularData2D();
00116 
00120     virtual void clear();
00122 
00126 
00130     TRegularData2D& operator = (const TRegularData2D<ValueType>& data) 
00131       throw(Exception::OutOfMemory);
00133       
00134 
00138     
00143     bool operator == (const TRegularData2D<ValueType>& data) const;
00144 
00146     BALL_INLINE bool operator != (const TRegularData2D<ValueType>& data) const { return !this->operator == (data); }
00147 
00149     BALL_INLINE bool empty() const { return data_.empty(); }
00150 
00152     bool isInside(const CoordinateType& x) const;
00154 
00158 
00159     BALL_INLINE ConstIterator begin() const { return data_.begin(); }
00161     BALL_INLINE ConstIterator end() const { return data_.end(); }
00163     BALL_INLINE Iterator begin() { return data_.begin(); }
00165     BALL_INLINE Iterator end() { return data_.end(); }
00167 
00171     // STL compatibility
00172     BALL_INLINE size_type size() const { return data_.size(); }
00173     BALL_INLINE size_type max_size() const { return data_.max_size(); }
00174     BALL_INLINE void swap(TRegularData2D<ValueType>& data) { std::swap(*this, data); }
00175     
00176 
00180     const ValueType& getData(const IndexType& index) const
00181       throw(Exception::OutOfGrid);
00182 
00186     ValueType& getData(const IndexType& index)
00187       throw(Exception::OutOfGrid);
00188 
00192     const ValueType& getData(Position index) const
00193       throw(Exception::OutOfGrid);
00194 
00198     ValueType& getData(Position index)
00199       throw(Exception::OutOfGrid);
00200 
00205     const ValueType& operator [] (const IndexType& index) const { return data_[index.x + size_.x * index.y]; }
00206 
00211     ValueType& operator [] (const IndexType& index) { return data_[index.x + size_.x * index.y]; }
00212 
00217     const ValueType& operator [] (Position index) const { return data_[index]; }
00218 
00223     ValueType& operator [] (Position index) { return data_[index]; }
00224 
00233     ValueType operator () (const CoordinateType& x) const;
00234 
00240     ValueType getInterpolatedValue(const CoordinateType& x) const
00241       throw(Exception::OutOfGrid);
00242 
00248     const ValueType& getClosestValue(const CoordinateType& x) const
00249       throw(Exception::OutOfGrid);
00250 
00256     ValueType& getClosestValue(const CoordinateType& x)
00257       throw(Exception::OutOfGrid);
00258 
00262     IndexType getLowerIndex(const CoordinateType& v) const 
00263       throw(Exception::OutOfGrid);
00264 
00270     IndexType getClosestIndex(const CoordinateType& v) const 
00271       throw(Exception::OutOfGrid);
00272 
00278     inline const IndexType& getSize() const { return size_; }
00279         
00284     inline const CoordinateType& getOrigin() const { return origin_; }
00285 
00290     const CoordinateType& getSpacing() const {  return spacing_; }
00291 
00294     void setOrigin(const CoordinateType& origin);
00295 
00301     const CoordinateType& getDimension() const { return dimension_; }
00302 
00308     void setDimension(const CoordinateType& dimension) { dimension_ = dimension; }
00309 
00321     void resize(const IndexType& new_size)
00322       throw(Exception::OutOfMemory);
00323 
00332     void rescale(const IndexType& new_size)
00333       throw(Exception::OutOfMemory);
00334 
00339     CoordinateType getCoordinates(const IndexType& index) const
00340       throw(Exception::OutOfGrid);
00341 
00346     CoordinateType getCoordinates(Position index) const
00347       throw(Exception::OutOfGrid);
00348 
00361     void getEnclosingIndices
00362       (const CoordinateType& r, Position& ll, Position& lr, Position& ul, Position& ur) const
00363       throw(Exception::OutOfGrid);
00364                   
00368     void getEnclosingValues
00369       (const CoordinateType& r, ValueType& ll, ValueType& lr, ValueType& ul, ValueType& ur) const
00370       throw(Exception::OutOfGrid);
00371                   
00375     void binaryWrite(const String& filename) const
00376       throw(Exception::FileNotFound);
00377 
00381     void binaryRead(const String& filename)
00382       throw(Exception::FileNotFound);
00384   
00385     protected:
00386       
00388     VectorType data_;
00389 
00391     CoordinateType  origin_;
00392 
00394     CoordinateType  dimension_;
00395 
00397     CoordinateType  spacing_;
00398 
00400     IndexType size_;
00401 
00403     typedef struct { ValueType bt[1024]; } BlockValueType;
00404   };
00405 
00408   typedef TRegularData2D<float> RegularData2D;
00409 
00410   // default constructor.
00411   template <class ValueType>
00412   TRegularData2D<ValueType>::TRegularData2D()
00413     : data_(),
00414       origin_(0.0),
00415       dimension_(0.0),
00416       spacing_(1.0),
00417       size_(0)
00418   {
00419   }
00420 
00421   // copy constructor
00422   template <class ValueType>
00423   TRegularData2D<ValueType>::TRegularData2D(const TRegularData2D<ValueType>& data)
00424     throw(Exception::OutOfMemory)
00425     : data_(),
00426       origin_(data.origin_),
00427       dimension_(data.dimension_),
00428       spacing_(data.spacing_),
00429       size_(data.size_)
00430   {
00431     try
00432     {
00433       data_ = data.data_;
00434     }
00435     catch (std::bad_alloc&)
00436     {
00437       data_.resize(0);
00438       throw Exception::OutOfMemory(__FILE__, __LINE__, data.data_.size() * sizeof(ValueType));
00439     }
00440   }
00441 
00442   template <class ValueType>
00443   TRegularData2D<ValueType>::TRegularData2D
00444     (const typename TRegularData2D<ValueType>::IndexType& size,
00445      const typename TRegularData2D<ValueType>::CoordinateType& origin,
00446      const typename TRegularData2D<ValueType>::CoordinateType& dimension)
00447     throw(Exception::OutOfMemory)
00448     : data_(),
00449       origin_(origin),
00450       dimension_(dimension),
00451       spacing_(0.0, 0.0),
00452       size_(size)
00453   {
00454     // Compute the grid spacing
00455     spacing_.x = dimension_.x / (double)(size_.x - 1);
00456     spacing_.y = dimension_.y / (double)(size_.y - 1);
00457 
00458     // Compute the number of grid points
00459     size_type number_of_points = size_.x * size_.y;
00460     try
00461     {
00462       data_.resize(number_of_points);
00463     }
00464     catch (std::bad_alloc&)
00465     {
00466       data_.resize(0);
00467       throw Exception::OutOfMemory(__FILE__, __LINE__, number_of_points * sizeof(ValueType));
00468     }
00469   }
00470 
00471   template <class ValueType>
00472   TRegularData2D<ValueType>::TRegularData2D
00473     (const typename TRegularData2D<ValueType>::CoordinateType& origin,
00474      const typename TRegularData2D<ValueType>::CoordinateType& dimension,
00475      const typename TRegularData2D<ValueType>::CoordinateType& spacing)
00476     throw(Exception::OutOfMemory)
00477     : data_(),
00478       origin_(origin),
00479       dimension_(dimension),
00480       spacing_(spacing),
00481       size_(0)
00482   {
00483     // Compute the grid size
00484     size_.x = (Size)(dimension_.x / spacing_.x + 0.5) + 1;
00485     size_.y = (Size)(dimension_.y / spacing_.y + 0.5) + 1;
00486     
00487     // Compute the number of grid points
00488     size_type size = size_.x * size_.y;
00489     try
00490     {
00491       data_ .resize(size);
00492     }
00493     catch (std::bad_alloc&)
00494     {
00495       data_.resize(0);
00496       throw Exception::OutOfMemory(__FILE__, __LINE__, size * sizeof(ValueType));
00497     }
00498     
00499     // Adjust the spacing -- dimension has precedence.
00500     spacing_.x = dimension_.x / (double)(size_.x - 1);
00501     spacing_.y = dimension_.y / (double)(size_.y - 1);
00502   }
00503 
00504   template <class ValueType>
00505   TRegularData2D<ValueType>::~TRegularData2D()
00506   {
00507   }
00508 
00509   // assignment operator
00510   template <typename ValueType>
00511   BALL_INLINE
00512   TRegularData2D<ValueType>& TRegularData2D<ValueType>::operator = 
00513     (const TRegularData2D<ValueType>& rhs)
00514     throw(Exception::OutOfMemory)
00515   {
00516     // Avoid self assignment
00517     if (&rhs != this)
00518     {
00519       // Copy the coordinate-related attributes and
00520       // the size.
00521       origin_ = rhs.origin_;
00522       dimension_ = rhs.dimension_;
00523       spacing_ = rhs.spacing_;
00524       size_ = rhs.size_;
00525 
00526       // Copy the data itself and rethrow allocation exceptions.
00527       try
00528       {
00529         data_ = rhs.data_;
00530       }
00531       catch (std::bad_alloc&)
00532       {
00533         data_.resize(0);
00534         throw Exception::OutOfMemory(__FILE__, __LINE__, rhs.data_.size() * sizeof(ValueType));
00535       }
00536     }
00537 
00538     return *this;
00539   }
00540 
00541   template <typename ValueType>
00542   void TRegularData2D<ValueType>::rescale(const typename TRegularData2D<ValueType>::IndexType& size)
00543     throw(Exception::OutOfMemory)
00544   {
00545     // If the old size equals the new size, we're done.
00546     if ((size.x == size_.x) && (size_.y == size.y))
00547     {
00548       return;
00549     }
00550   
00551     // If the new grid is empty, this whole thing is quite easy.
00552     if ((size.x == 0) || (size.y == 0))
00553     {
00554       data_.resize(0);
00555       dimension_.set(0.0);
00556       return;
00557     }
00558 
00559     // Compute the new array size.
00560     size_type new_size = (size_type)(size.x * size.y);
00561 
00562     // Catch any bad_allocs thrown by vector::resize
00563     try
00564     {
00565       // Create a new temporary array.
00566       TRegularData2D<ValueType> old_data(*this);
00567 
00568       // Resize the data to its new size.
00569       data_.resize(new_size);
00570       spacing_.x = dimension_.x / (double)(size.x - 1);
00571       spacing_.y = dimension_.y / (double)(size.y - 1);
00572       
00573       // Walk over the new grid and copy the (interpolated) old stuff back.
00574       CoordinateType v;
00575       for (size_type i = 0; i < new_size; i++)
00576       { 
00577         Position x = i % size.x;
00578         Position y = i / size.x;
00579         v.x = origin_.x + x * spacing_.x;
00580         v.y = origin_.y + y * spacing_.y;
00581         data_[i] = old_data(v);
00582       }
00583       
00584       // Correct the grid dimension. Origin and spacing remain constant.
00585       size_ = size;
00586     }
00587     catch (std::bad_alloc&)
00588     {
00589       throw Exception::OutOfMemory(__FILE__, __LINE__, new_size * (Size)sizeof(ValueType));
00590     }
00591   }
00592 
00593   template <typename ValueType>
00594   void TRegularData2D<ValueType>::resize(const typename TRegularData2D<ValueType>::IndexType& size)
00595     throw(Exception::OutOfMemory)
00596   {
00597     // If the old size equals the new size, we're done.
00598     if (size.x == size_.x && size_.y == size.y)
00599     {
00600       return;
00601     }
00602   
00603     // If the new grid is empty, this whole thing is quite easy.
00604     if ((size.x == 0) || (size.y == 0))
00605     {
00606       data_.resize(0);
00607       dimension_.set(0.0, 0.0);
00608       return;
00609     }
00610 
00611     // Compute the new array size.
00612     size_type new_size = (size_type)(size.x * size.y);
00613 
00614     // Catch any bad_allocs thrown by vector::resize
00615     try
00616     {
00617       // Create a new temporary array.
00618       std::vector<ValueType> old_data(data_);
00619 
00620       // Resize the data to its new size.
00621       data_.resize(new_size);
00622       
00623       // walk over the new grid and copy the old stuff back.
00624       static ValueType default_value = (ValueType)0;
00625       for (size_type i = 0; i < new_size; i++)
00626       { 
00627         size_type x = i % size.x;
00628         size_type y = i / size.x;
00629         if (x >= size_.x || y >= size_.y)
00630         {
00631           data_[i] = default_value;
00632         }
00633         else
00634         {
00635           data_[i] = old_data[x + y * size_.x];
00636         }
00637       }
00638       
00639       // Correct the grid dimension. Origin and spacing remain constant.
00640       dimension_.x *= (double)size.x / (double)size_.x;
00641       dimension_.y *= (double)size.y / (double)size_.y;
00642       size_ = size;
00643     }
00644     catch (std::bad_alloc&)
00645     {
00646       throw Exception::OutOfMemory(__FILE__, __LINE__, new_size * (Size)sizeof(ValueType));
00647     }
00648   }
00649 
00650   template <class ValueType>
00651   void TRegularData2D<ValueType>::setOrigin(const typename TRegularData2D<ValueType>::CoordinateType& origin)
00652   {
00653     origin_ = origin;
00654   }
00655 
00656   template <class ValueType> 
00657   BALL_INLINE
00658   bool TRegularData2D<ValueType>::isInside(const typename TRegularData2D<ValueType>::CoordinateType& r) const   
00659   {
00660     return ((r.x >= origin_.x) && (r.x <= (origin_.x + dimension_.x))
00661             && (r.y >= origin_.y) && (r.y <= (origin_.y + dimension_.y)));
00662   }
00663 
00664   template <class ValueType>
00665   BALL_INLINE 
00666   const ValueType& TRegularData2D<ValueType>::getData
00667     (const typename TRegularData2D<ValueType>::IndexType& index) const
00668     throw(Exception::OutOfGrid)
00669   { 
00670     size_type pos = index.x + index.y * size_.x;
00671     if (pos >= data_.size())
00672     {
00673       throw Exception::OutOfGrid(__FILE__, __LINE__);
00674     }       
00675     return data_[pos];
00676   }
00677 
00678   template <class ValueType>
00679   BALL_INLINE 
00680   ValueType& TRegularData2D<ValueType>::getData(const typename TRegularData2D<ValueType>::IndexType& index)
00681     throw(Exception::OutOfGrid)
00682   { 
00683     size_type pos = index.x + index.y * size_.x;
00684     if (pos >= data_.size())
00685     {
00686       throw Exception::OutOfGrid(__FILE__, __LINE__);
00687     }       
00688     return data_[pos];
00689   }
00690 
00691   template <class ValueType>
00692   BALL_INLINE 
00693   const ValueType& TRegularData2D<ValueType>::getData(Position index) const
00694     throw(Exception::OutOfGrid)
00695   { 
00696     if (index >= data_.size())
00697     {
00698       throw Exception::OutOfGrid(__FILE__, __LINE__);
00699     }       
00700     return data_[index];
00701   }
00702 
00703   template <class ValueType>
00704   BALL_INLINE 
00705   ValueType& TRegularData2D<ValueType>::getData(Position index)
00706     throw(Exception::OutOfGrid)
00707   { 
00708     if (index >= data_.size())
00709     {
00710       throw Exception::OutOfGrid(__FILE__, __LINE__);
00711     }       
00712     return data_[index];
00713   }
00714 
00715   template <class ValueType>
00716   BALL_INLINE 
00717   typename TRegularData2D<ValueType>::CoordinateType TRegularData2D<ValueType>::getCoordinates
00718     (const typename TRegularData2D<ValueType>::IndexType& index) const 
00719     throw(Exception::OutOfGrid)
00720   {
00721     if ((index.x >= size_.x) || (index.y >= size_.y))
00722     {
00723       throw Exception::OutOfGrid(__FILE__, __LINE__);
00724     }   
00725     
00726     CoordinateType r(origin_.x + index.x * spacing_.x,
00727                      origin_.y + index.y * spacing_.y);
00728 
00729     return r;
00730   }
00731 
00732   template <class ValueType> 
00733   BALL_INLINE 
00734   typename TRegularData2D<ValueType>::CoordinateType
00735   TRegularData2D<ValueType>::getCoordinates(Position position) const 
00736     throw(Exception::OutOfGrid)
00737   {
00738     if (position >= data_.size())
00739     {
00740       throw Exception::OutOfGrid(__FILE__, __LINE__);
00741     } 
00742     
00743     Position x = (Position)(position %  size_.x);
00744     Position y = (Position)(position / size_.x);
00745 
00746     return CoordinateType(origin_.x + (double)x * spacing_.x,
00747                           origin_.y + (double)y * spacing_.y);
00748   }
00749 
00750   template <typename ValueType>
00751   BALL_INLINE
00752   void TRegularData2D<ValueType>::getEnclosingIndices
00753     (const typename TRegularData2D<ValueType>::CoordinateType& r,
00754      Position& ll, Position& lr, Position& ul, Position& ur) const
00755     throw(Exception::OutOfGrid)
00756   {
00757     if (!isInside(r))
00758     {
00759       throw Exception::OutOfGrid(__FILE__, __LINE__);
00760     }   
00761 
00762     // Calculate the grid indices of the lower left front corner
00763     // of the enclosing rectangle
00764     IndexType position;
00765     position.x = (Position)((r.x - origin_.x) / spacing_.x);
00766     position.y = (Position)((r.y - origin_.y) / spacing_.y);
00767     
00768     // Calculate the (linear) indices of the four rectangle corners
00769     ll = position.x + size_.x * position.y;
00770     lr = ll + 1;
00771     ul = ll + size_.x;
00772     ur = ul + 1;
00773   }
00774 
00775   template <typename ValueType>
00776   BALL_INLINE
00777   void TRegularData2D<ValueType>::getEnclosingValues
00778     (const typename TRegularData2D<ValueType>::CoordinateType& r,
00779      ValueType& ll, ValueType& lr, ValueType& ul, ValueType& ur) const
00780     throw(Exception::OutOfGrid)
00781   {
00782     if (!isInside(r))
00783     {
00784       throw Exception::OutOfGrid(__FILE__, __LINE__);
00785     }   
00786     
00787     // compute the four grid indices forming the enclosing rectangle
00788     Position ll_id, lr_id, ul_id, ur_id;
00789     getEnclosingIndices(r, ll_id, lr_id, ul_id, ur_id);
00790         
00791     // Retrieve the grid values
00792     ll = data_[ll_id];
00793     lr = data_[lr_id];
00794     ul = data_[ul_id];
00795     ur = data_[ur_id];
00796   }
00797 
00798   template <typename ValueType>
00799   BALL_INLINE
00800   ValueType TRegularData2D<ValueType>::getInterpolatedValue
00801     (const typename TRegularData2D<ValueType>::CoordinateType& r) const
00802     throw(Exception::OutOfGrid)
00803   {
00804     if (!isInside(r))
00805     {
00806       throw Exception::OutOfGrid(__FILE__, __LINE__);
00807     }   
00808     
00809     return this->operator () (r);
00810   }
00811 
00812   template <typename ValueType>
00813   BALL_INLINE
00814   ValueType TRegularData2D<ValueType>::operator ()
00815     (const typename TRegularData2D<ValueType>::CoordinateType& r) const
00816   {
00817     CoordinateType h(r - origin_);
00818     Position x = (Position)(h.x / spacing_.x);
00819     Position y = (Position)(h.y / spacing_.y);
00820 
00821     // correct for numerical inaccuracies
00822     if (x >= (size_.x - 1))
00823     {
00824       x = size_.x - 2;
00825     }
00826     if (y >= (size_.y - 1))
00827     {
00828       y = size_.y - 2;
00829     }
00830 
00831     Size l = x + size_.x * y;
00832     CoordinateType r_0(origin_.x + (double)x * spacing_.x,
00833                        origin_.y + (double)y * spacing_.y);
00834 
00835     double dx = 1.0 - ((r.x - r_0.x) / spacing_.x);
00836     double dy = 1.0 - ((r.y - r_0.y) / spacing_.y);
00837 
00838     return  data_[l] * dx * dy
00839           + data_[l + 1] * (1.0 - dx) * dy
00840           + data_[l + size_.x] * dx * (1.0 - dy)
00841           + data_[l + size_.x + 1] * (1.0 - dx) * (1.0 - dy);
00842   }
00843 
00844   template <typename ValueType>
00845   BALL_INLINE
00846   typename TRegularData2D<ValueType>::IndexType TRegularData2D<ValueType>::getLowerIndex
00847     (const typename TRegularData2D<ValueType>::CoordinateType& r) const
00848     throw(Exception::OutOfGrid)
00849   {
00850     if (!isInside(r))
00851     {
00852       throw Exception::OutOfGrid(__FILE__, __LINE__);
00853     }   
00854     
00855     static IndexType position;
00856     position.x = (Position)((r.x - origin_.x) / spacing_.x);
00857     position.y = (Position)((r.y - origin_.y) / spacing_.y);
00858     
00859     return position;
00860   }
00861 
00862   template <typename ValueType>
00863   BALL_INLINE
00864   typename TRegularData2D<ValueType>::IndexType TRegularData2D<ValueType>::getClosestIndex
00865     (const typename TRegularData2D<ValueType>::CoordinateType& r) const
00866     throw(Exception::OutOfGrid)
00867   {
00868     if (!isInside(r))
00869     {
00870       throw Exception::OutOfGrid(__FILE__, __LINE__);
00871     }   
00872     
00873     static IndexType position;
00874     position.x = (Position)((r.x - origin_.x) / spacing_.x + 0.5);
00875     position.y = (Position)((r.y - origin_.y) / spacing_.y + 0.5);
00876     
00877     return position;
00878   }
00879 
00880   template <typename ValueType>
00881   BALL_INLINE
00882   const ValueType& TRegularData2D<ValueType>::getClosestValue
00883     (const typename TRegularData2D<ValueType>::CoordinateType& r) const
00884     throw(Exception::OutOfGrid)
00885   {
00886     if (!isInside(r))
00887     {
00888       throw Exception::OutOfGrid(__FILE__, __LINE__);
00889     }   
00890     
00891     static IndexType position;
00892     position.x = (Position)((r.x - origin_.x) / spacing_.x + 0.5);
00893     position.y = (Position)((r.y - origin_.y) / spacing_.y + 0.5);
00894 
00895     return operator [] (position);
00896   }
00897 
00898   template <typename ValueType>
00899   BALL_INLINE
00900   ValueType& TRegularData2D<ValueType>::getClosestValue
00901     (const typename TRegularData2D<ValueType>::CoordinateType& r)
00902     throw(Exception::OutOfGrid)
00903   {
00904     if (!isInside(r))
00905     {
00906       throw Exception::OutOfGrid(__FILE__, __LINE__);
00907     }   
00908     
00909     static IndexType position;
00910     position.x = (Position)((r.x - origin_.x) / spacing_.x + 0.5);
00911     position.y = (Position)((r.y - origin_.y) / spacing_.y + 0.5);
00912 
00913     return operator [] (position);
00914   }
00915 
00916   template <typename ValueType>
00917   void TRegularData2D<ValueType>::clear()
00918   {
00919     data_.resize(0);
00920     
00921     origin_.set(0.0);
00922     dimension_.set(0.0, 0.0);
00923     size_.x = 0;
00924     size_.y = 0;
00925     spacing_.set(1.0, 1.0);
00926   }
00927 
00928   template <typename ValueType> 
00929   bool TRegularData2D<ValueType>::operator == (const TRegularData2D<ValueType>& data) const
00930   {
00931     return ((origin_ == data.origin_)
00932             && (dimension_ == data.dimension_)
00933             && (size_.x == data.size_.x)
00934             && (size_.y == data.size_.y)
00935             && (data_ == data.data_));
00936   } 
00937 
00938 
00941 
00942   template <typename ValueType>
00943   std::ostream& operator << (std::ostream& os, const TRegularData2D<ValueType>& data)
00944   {
00945     // Write the grid origin, dimension, and number of grid points
00946     os << data.getOrigin().x << " " << data.getOrigin().y
00947       << std::endl
00948       << data.getOrigin().x + data.getDimension().x << " "
00949       << data.getOrigin().y + data.getDimension().y
00950       << std::endl
00951       << data.getSize().x - 1 << " " << data.getSize().y - 1
00952       << std::endl;
00953 
00954     // Write the array contents.
00955     std::copy(data.begin(), data.end(), std::ostream_iterator<ValueType>(os, "\n"));
00956     return os;
00957   }
00958 
00960   template <typename ValueType>
00961   std::istream& operator >> (std::istream& is, TRegularData2D<ValueType>& grid)
00962   {
00963     typename TRegularData2D<ValueType>::CoordinateType origin;
00964     typename TRegularData2D<ValueType>::CoordinateType dimension;
00965     typename TRegularData2D<ValueType>::IndexType size;
00966 
00967     is >> origin.x >> origin.y;
00968     is >> dimension.x >> dimension.y;
00969     is >> size.x >> size.y;
00970     
00971     dimension -= origin;
00972     size.x++;
00973     size.y++;
00974 
00975     grid.resize(size);
00976     grid.setOrigin(origin);
00977     grid.setDimension(dimension);
00978 
00979     std::copy(std::istream_iterator<ValueType>(is), 
00980               std::istream_iterator<ValueType>(), 
00981               grid.begin());
00982     //    std::copy_n(std::istream_iterator<ValueType>(is), grid.size(), grid.begin());
00983     
00984     return is;
00985   }
00987 
00988   template <typename ValueType>
00989   void TRegularData2D<ValueType>::binaryWrite(const String& filename) const
00990     throw(Exception::FileNotFound)
00991   {
00992     File outfile(filename.c_str(), std::ios::out|std::ios::binary);
00993     if (!outfile.isValid()) 
00994       throw Exception::FileNotFound(__FILE__, __LINE__, filename);
00995 
00996     // write all information we need to recreate the grid
00997     BinaryFileAdaptor<BlockValueType> adapt_block;
00998     BinaryFileAdaptor<ValueType>      adapt_single;
00999     BinaryFileAdaptor<float>          adapt_float;
01000     
01001     BinaryFileAdaptor<Size>           adapt_size;
01002 
01003     adapt_size.setData(data_.size());
01004     outfile << adapt_size;
01005     
01006     // NOTE: we do not use the binary file adaptor to write out the Vector2-variables here,
01007     //       the reason is a bit stupid: the data layout of Vector2 has a three-byte "hole"
01008     //       that is automatically padded by the compiler to ensure the correct alignment.
01009     //       valgrind is very unhappy when we write these uninitialized values out, even
01010     //       though they are entirely harmless. To prevent false-positives in the error checking,
01011     //       we write out the members of the vectors instead. This even saves some bytes in the
01012     //       output (not that it would matter...)
01013     adapt_float.setData(origin_.x);
01014     outfile << adapt_float;
01015     adapt_float.setData(origin_.y);
01016     outfile << adapt_float;
01017 
01018     adapt_float.setData(dimension_.x);
01019     outfile << adapt_float;
01020     adapt_float.setData(dimension_.y);
01021     outfile << adapt_float;
01022 
01023     adapt_float.setData(spacing_.x);
01024     outfile << adapt_float;
01025     adapt_float.setData(spacing_.y);
01026     outfile << adapt_float;
01027 
01028     BinaryFileAdaptor<IndexType> adapt_index;
01029     adapt_index.setData(size_);
01030     outfile << adapt_index;
01031   
01032     // we slide a window of BLOCK_SIZE over our data.
01033     const int BLOCK_SIZE = 1024;
01034     Index window_pos = 0;
01035     
01036     while (((int)data_.size() - (BLOCK_SIZE + window_pos)) >= 0)
01037     {
01038       adapt_block.setData(* (BlockValueType*)&(data_[window_pos]));
01039       outfile << adapt_block;
01040       window_pos += BLOCK_SIZE;
01041     }
01042 
01043     // Now we have to write the remaining data one by one.
01044     for (Size i = window_pos; i < data_.size(); i++)
01045     {
01046       adapt_single.setData(data_[i]);
01047       outfile << adapt_single;
01048     }
01049 
01050     // That's it. 
01051     outfile.close();
01052   }
01053 
01054   template <typename ValueType>
01055   void TRegularData2D<ValueType>::binaryRead(const String& filename)
01056     throw(Exception::FileNotFound)
01057   {
01058     File infile(filename, std::ios::in|std::ios::binary);
01059     if (!infile.isValid()) 
01060     {
01061       throw Exception::FileNotFound(__FILE__, __LINE__, filename);
01062     }
01063     
01064     BinaryFileAdaptor< BlockValueType > adapt_block;
01065     BinaryFileAdaptor< ValueType >      adapt_single;
01066     
01067     // read all information we need to recreate the grid
01068     BinaryFileAdaptor<Size>           adapt_size;
01069     BinaryFileAdaptor<float>          adapt_float;
01070 
01071     infile >> adapt_size;
01072     Size new_size = adapt_size.getData();
01073   
01074     infile >> adapt_float;
01075     origin_.x = adapt_float.getData();
01076     infile >> adapt_float;
01077     origin_.y = adapt_float.getData();
01078 
01079     infile >> adapt_float;
01080     dimension_.x = adapt_float.getData();
01081     infile >> adapt_float;
01082     dimension_.y = adapt_float.getData();
01083 
01084     infile >> adapt_float;
01085     spacing_.x = adapt_float.getData();
01086     infile >> adapt_float;
01087     spacing_.y = adapt_float.getData();
01088 
01089     BinaryFileAdaptor<IndexType> adapt_index;
01090     infile >> adapt_index;
01091     size_ =  adapt_index.getData();
01092   
01093     data_.resize(new_size);
01094 
01095     // we slide a window of size 1024 over our data
01096     Index window_pos = 0;
01097     
01098     while ( ((int)data_.size() - (1024 + window_pos)) >= 0 )
01099     {
01100       infile >> adapt_block;
01101       *(BlockValueType*)(&(data_[window_pos])) = adapt_block.getData();
01102       /*
01103       for (Size i=0; i<1024; i++)
01104       {
01105         data_[i+window_pos] = adapt_block.getData().bt[i];
01106       }
01107       */
01108       window_pos+=1024;
01109     }
01110 
01111     // now we have to read the remaining data one by one
01112     for (Size i=window_pos; i<data_.size(); i++)
01113     {
01114       infile >> adapt_single;
01115       data_[i] = adapt_single.getData();
01116     }
01117 
01118     // that's it. I hope...
01119     infile.close();
01120   } 
01121  } // namespace BALL
01122 
01123 #endif // BALL_DATATYPE_TREGULARDATA2D_H