QGpCoreTools/Grid2D.h
Go to the documentation of this file.
00001 /***************************************************************************
00002 **
00003 **  This file is part of QGpCoreTools.
00004 **
00005 **  This library is free software; you can redistribute it and/or
00006 **  modify it under the terms of the GNU Lesser General Public
00007 **  License as published by the Free Software Foundation; either
00008 **  version 2.1 of the License, or (at your option) any later version.
00009 **
00010 **  This file 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 Lesser General Public
00013 **  License for more details.
00014 **
00015 **  You should have received a copy of the GNU Lesser General Public
00016 **  License along with this library; if not, write to the Free Software
00017 **  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00018 **
00019 **  See http://www.geopsy.org for more information.
00020 **
00021 **  Created : 2002-04-15
00022 **  Authors :
00023 **    Marc Wathelet
00024 **    Marc Wathelet (ULg, Liège, Belgium)
00025 **    Marc Wathelet (LGIT, Grenoble, France)
00026 **
00027 ***************************************************************************/
00028 
00029 #ifndef GRID_H
00030 #define GRID_H
00031 
00032 #include <math.h>
00033 
00034 #include "QGpCoreToolsDLLExport.h"
00035 #include "Point2D.h"
00036 #include "Translations.h"
00037 #include "CoreApplication.h"
00038 #include "XMLClass.h"
00039 
00040 namespace QGpCoreTools {
00041 
00042 template <class ValueType>
00043 class QGPCORETOOLS_EXPORT Grid2D : public XMLClass
00044 {
00045   TRANSLATIONS( "Grid2D" )
00046 public:
00047   Grid2D();
00048   Grid2D(int nx, int ny);
00049   Grid2D(const Grid2D& m);
00050   virtual ~Grid2D();
00051 
00052   virtual const QString& xml_tagName() const {return xmlGrid2DTag;}
00053   static const QString xmlGrid2DTag;
00054   
00055   int nx() const {return _nx;}
00056   int ny() const {return _ny;}
00057   void clear();
00058   void init(int nx, int ny);
00059   void init(ValueType value);
00060   inline void init(int nx, int ny, ValueType value);
00061 
00062   ValueType value(int ix, int iy) const {return _values[ix+_nx*iy];}
00063   void setValue(int ix, int iy, double val) {_values[ix+_nx*iy]=val;}
00064   ValueType * valuePointer(int ix, int iy) {return _values+ix+_nx*iy;}
00065   const ValueType * valuePointer(int ix, int iy) const {return _values+ix+_nx*iy;}
00066 
00067   void setOrigin(const Point2D& p) {_origin=p;}
00068   const Point2D& origin() const {return _origin;}
00069   void setDeltaX(double dx) {_delta.setX(dx); _invDelta.setX(1.0/dx);}
00070   void setDeltaY(double dy) {_delta.setY(dy); _invDelta.setY(1.0/dy);}
00071   double deltaX() const {return _delta.x();}
00072   double deltaY() const {return _delta.y();}
00073   double x(int ix) const {return _origin.x()+ix*_delta.x();}
00074   double y(int iy) const {return _origin.y()+iy*_delta.y();}
00075   double west(int ix) const {return x(ix)-_delta.x()*0.5;}
00076   double east(int ix) const {return x(ix)+_delta.x()*0.5;}
00077   double south(int iy) const {return y(iy)-_delta.y()*0.5;}
00078   double north(int iy) const {return y(iy)+_delta.y()*0.5;}
00079   Point2D coordinates(int ix, int iy) const;
00080   int indexOfX(double x) const {return (int) round((x - _origin.x()) * _invDelta.x());}
00081   int indexOfY(double y) const {return (int) round((y - _origin.y()) * _invDelta.y());}
00082 
00083   ValueType minimumValue() const;
00084   ValueType maximumValue() const;
00085 protected:
00086   virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
00087   virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
00088   virtual XMLMember xml_member(XML_MEMBER_ARGS);
00089   virtual void xml_writeBinaryData(XML_WRITEBINARYDATA_ARGS) const;
00090   virtual bool xml_setBinaryData(XML_SETBINARYDATA_ARGS);
00091 private:
00092   int _nx, _ny;
00093   Point2D _origin, _delta, _invDelta;
00094   ValueType *_values;
00095 };
00096 
00097 // Restore from a QTextStream
00098 template <class ValueType>
00099 QGPCORETOOLS_EXPORT QTextStream& operator<<(QTextStream& s, Grid2D<ValueType>& grd);
00100 template <class ValueType>
00101 QGPCORETOOLS_EXPORT QTextStream& operator>>(QTextStream& s, Grid2D<ValueType>& grd);
00102 
00103 template <class ValueType>
00104 const QString Grid2D<ValueType>::xmlGrid2DTag="Grid2D";
00105 
00106 template <class ValueType>
00107 Grid2D<ValueType>::Grid2D()
00108 {
00109   TRACE;
00110   _nx=_ny=0;
00111   _delta=Point2D(1., 1. );
00112   _invDelta=Point2D(1., 1. );
00113   _origin=Point2D(0., 0. );
00114   _values=0;
00115 }
00116 
00117 template <class ValueType>
00118 Grid2D<ValueType>::Grid2D(int nx, int ny)
00119 {
00120   TRACE;
00121   _values=0;
00122   _delta=Point2D(1., 1. );
00123   _invDelta=Point2D(1., 1. );
00124   _origin=Point2D(0., 0. );
00125   init(nx, ny);
00126 }
00127 
00128 template <class ValueType>
00129 Grid2D<ValueType>::Grid2D(const Grid2D& m) : XMLClass()
00130 {
00131   TRACE;
00132   _values=0;
00133   _delta=m._delta;
00134   _invDelta=m._invDelta;
00135   _origin=m._origin;
00136   init(m._nx, m._ny);
00137   int n=_ny * _nx;
00138   for(int i=0; i < n; i++ )
00139     _values[ i ]=m._values[ i ];
00140 }
00141 
00142 template <class ValueType>
00143 Grid2D<ValueType>::~Grid2D()
00144 {
00145   TRACE;
00146   if(_values) delete [] _values;
00147 }
00148 
00149 template <class ValueType>
00150 void Grid2D<ValueType>::init(int nx, int ny)
00151 {
00152   TRACE;
00153   if(_values) delete [] _values;
00154   _nx=nx;
00155   _ny=ny;
00156   _values=new ValueType[ _ny * _nx ];
00157 }
00158 
00159 template <class ValueType>
00160 void Grid2D<ValueType>::init(ValueType value)
00161 {
00162   TRACE;
00163   int n=_ny * _nx;
00164   for(int i=0; i < n; i++ ) _values[ i ]=value;
00165 }
00166 
00167 template <class ValueType>
00168 inline void Grid2D<ValueType>::init(int nx, int ny, ValueType value)
00169 {
00170   init(nx, ny);
00171   init(value);
00172 }
00173 
00174 template <class ValueType>
00175 ValueType Grid2D<ValueType>::minimumValue() const
00176 {
00177   TRACE;
00178   int n=_nx*_ny;
00179   if(n<1) return 0;
00180   ValueType val=_values[0];
00181   for(int i=1; i<n; i++) {
00182     if(_values[i]<val) val=_values[i];
00183   }
00184   return val;
00185 }
00186 
00187 template <class ValueType>
00188 ValueType Grid2D<ValueType>::maximumValue() const
00189 {
00190   TRACE;
00191   int n=_nx*_ny;
00192   if(n<1) return 0;
00193   ValueType val=_values[0];
00194   for(int i=1; i<n; i++) {
00195     if(_values[i]>val) val=_values[i];
00196   }
00197   return val;
00198 }
00199 
00200 template <class ValueType>
00201 Point2D Grid2D<ValueType>::coordinates(int ix, int iy) const
00202 {
00203   TRACE;
00204   double x=_origin.x() + (double) ix * _delta.x();
00205   double y=_origin.y() + (double) iy * _delta.y();
00206   return (Point2D(x, y));
00207 }
00208 
00209 template <class ValueType>
00210 void Grid2D<ValueType>::xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const
00211 {
00212   TRACE;
00213   writeProperty(s, "nx", _nx);
00214   writeProperty(s, "ny", _ny);
00215   writeProperty(s, "origin", _origin.toString());
00216   writeProperty(s, "delta", _delta.toString());
00217   writeBinaryData(s, context);
00218 }
00219 
00220 template <class ValueType>
00221 void Grid2D<ValueType>::xml_writeBinaryData(XML_WRITEBINARYDATA_ARGS) const
00222 {
00223   TRACE;
00224   Q_UNUSED(context);
00225   s << _nx;
00226   s << _ny;
00227   s.writeRawData((const char *)_values, sizeof(double)*_nx * _ny);
00228 }
00229 
00230 template <class ValueType>
00231 bool Grid2D<ValueType>::xml_setBinaryData(XML_SETBINARYDATA_ARGS)
00232 {
00233   TRACE;
00234   Q_UNUSED(context);
00235   int nx, ny;
00236   s >> nx;
00237   s >> ny;
00238   if(nx!=_nx || ny!=ny) {
00239     App::stream() << tr( "Grid2D size in binary file: %1x%2\n"
00240                   "            in XML data   : %3x%4" )
00241     .arg(nx).arg(ny).arg(_nx).arg(_ny) << endl;
00242     _nx=nx;
00243     _ny=ny;
00244   }
00245   init(_nx, _ny);
00246   s.readRawData((char *)_values, sizeof(double)*_nx * _ny);
00247   return true;
00248 }
00249 
00250 template <class ValueType>
00251 XMLMember Grid2D<ValueType>::xml_member(XML_MEMBER_ARGS)
00252 {
00253   TRACE;
00254   Q_UNUSED(attributes);
00255   Q_UNUSED(context);
00256   if(tag=="origin" ) return XMLMember(0);
00257   else if(tag=="delta" ) return XMLMember(1);
00258   else if(tag=="nx" ) return XMLMember(2);
00259   else if(tag=="ny" ) return XMLMember(3);
00260   return XMLMember(XMLMember::Unknown);
00261 }
00262 
00263 template <class ValueType>
00264 bool Grid2D<ValueType>::xml_setProperty(XML_SETPROPERTY_ARGS)
00265 {
00266   TRACE;
00267   Q_UNUSED(tag);
00268   Q_UNUSED(attributes);
00269   Q_UNUSED(context);
00270   switch (memberID) {
00271   case 0: _origin.fromString(content); return true;
00272   case 1:
00273     _delta.fromString(content);
00274     _invDelta.setX(1.0/_delta.x());
00275     _invDelta.setY(1.0/_delta.y());
00276     return true;
00277   case 2: _nx=content.toInt(); return true;
00278   case 3: _ny=content.toInt(); return true;
00279   }
00280   return false;
00281 }
00282 
00283 template <class ValueType>
00284 QTextStream& operator<<(QTextStream& s, const Grid2D<double>& grd)
00285 {
00286   TRACE;
00287   s << "x y val" << ::endl;
00288   const double * ptr=grd.valuePointer(0, 0);
00289   for(int iy=0;iy < grd.ny();iy++ ) {
00290     for(int ix=0;ix < grd.nx();ix++ )
00291       s << grd.x(ix) << " " << grd.y(iy) << " " << *(ptr++ ) << ::endl;
00292   }
00293   return s;
00294 }
00295 
00296 template <class ValueType>
00297 QTextStream& operator>>(QTextStream& s, Grid2D<ValueType>& grd)
00298 {
00299   TRACE;
00300   QString str;
00301   bool ok;
00302   int i;
00303   int line=0;
00304   str=s.readLine().trimmed(); line++;
00305   while(str.isEmpty() || str[0]=='#') {  // Accept blank lines and comments only before grid definition
00306     str=s.readLine().trimmed(); line++;
00307   }
00308   if(str=="x y val" ) {
00309     QVector<Point2D> points;
00310     QVector<ValueType> values;
00311     Point2D p;
00312     ValueType val;
00313     const QChar * ptr;
00314     StringSection f;
00315     bool ok=true;
00316     while( !s.atEnd()) {
00317       str=s.readLine().trimmed(); line++;
00318       if(str.isEmpty() || str[0]=='#') break;
00319       StringSection pStr(str);
00320       ptr=0;
00321       f=pStr.nextField(ptr);
00322       if(f.isValid()) p.setX(f.toDouble()); else ok=false;
00323       f=pStr.nextField(ptr);
00324       if(f.isValid()) p.setY(f.toDouble()); else ok=false;
00325       f=pStr.nextField(ptr);
00326       if(f.isValid()) val=f.toDouble(); else ok=false;
00327       if( !ok) {
00328         App::stream() << QCoreApplication::translate( "Grid2D", "Wrong format at line %1, expected: float value" ).arg(line) << endl;
00329         return s;
00330       }
00331       points.append(p);
00332       values.append(val);
00333     }
00334     // Deduce nx, ny, delta and origin from x and y vectors
00335     QMap<double,int> xMap, yMap;
00336     QMap<double,int>::iterator itMap;
00337     for(QVector<Point2D>::iterator it=values.begin();it!=values.end(); it++) {
00338       itMap=xMap.find(it->x());
00339       if(itMap==xMap.end()) {
00340         xMap.insert(it->x(),0);
00341       }
00342       itMap=yMap.find(it->y());
00343       if(itMap==yMap.end()) {
00344         yMap.insert(it->y(),0);
00345       }
00346     }
00347     if(xMap.isEmpty() || yMap.isEmpty()) {
00348       return s;
00349     }
00350     grd.setOrigin(Point2D(xMap.begin().value(), yMap.begin().value()));
00351     grd.setDeltaX(((--xMap.end()).value() - xMap.begin().value())/xMap.count());
00352     grd.setDeltaY(((--yMap.end()).value() - yMap.begin().value())/yMap.count());
00353     grd.init(xMap.count(), yMap.count(), 0.0);
00354     // Set index in x and y maps
00355     int i;
00356     i=0;
00357     for(QMap<double,int>::iterator it=xMap.begin();it!=xMap.end(); it++, i++) {
00358       grd.setX(i, it.key());
00359       it.value()=i;
00360       //printf("x[%i]=%lf\n",i,it.key());
00361     }
00362     i=0;
00363     for(QMap<double,int>::iterator it=yMap.begin();it!=yMap.end(); it++, i++) {
00364       grd.setY(i, it.key());
00365       it.value()=i;
00366       //printf("y[%i]=%lf\n",i,it.key());
00367     }
00368     // Set values
00369     for(int i=points.count()-1; i>=0; i--) {
00370       Point2D& p=points.at(i);
00371       grd.setValue(xMap[p.x()], yMap[p.y()], values.at(i));
00372     }
00373   } else {
00374     App::stream() << QCoreApplication::translate( "Grid2D", "Wrong format at line %1, expected: values" ).arg(line) << endl;
00375   }
00376   return s;
00377 }
00378 
00379 } // namespace QGpCoreTools
00380 
00381 #endif // GRID2D.H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines