• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

/home/pascal/depot/filedata/src/pixel.h

00001 /* Pixel.h */
00002 
00003 /*
00004    Copyright (C) 2006 Fabrice Ducos <fabrice.ducos@icare.univ-lille1.fr>
00005    This file is part of the Pixel Library.
00006 
00007    The Pixel Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The Pixel Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the Pixel Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.
00021 
00022 */
00023 
00024 #ifndef PIXEL_H
00025 #define PIXEL_H
00026 
00027 #include <cassert>
00028 #include <set>
00029 #include <algorithm>
00030 #include <utility> // pair
00031 #include <functional> // binary_function
00032 #include <cmath>
00033 #include <vector>
00034 #include <iostream>
00035 
00036 #include "tools.h"
00037 
00038 template<typename T, typename V>
00039 class Pixel_base;
00040 
00041 template<typename Pixel_type>
00042 class Nearer_from : public std::binary_function<Pixel_type, Pixel_type, bool> {
00043  public:
00044   Nearer_from(const Pixel_type &this_pixel) : this_pixel(this_pixel) { }
00045 
00046   bool operator()(const Pixel_type &pixel1, const Pixel_type &pixel2) const {
00047     return this_pixel.distance(pixel1) < this_pixel.distance(pixel2);
00048   }
00049 
00050  private:
00051   const Pixel_type this_pixel;
00052 };
00053 
00054 template<typename T, typename V>
00055 class Pixel_base {
00056 public:
00057   typedef Pixel_base<T, V> Pixel_type;
00058   typedef T coord_type;
00059   typedef T distance_type;
00060   typedef V value_type;
00061 
00062   static const coord_type DEFAULT_RESOLUTION; // km
00063   static const coord_type R_EARTH; // Earth's authalic radius ("equal aera"), from http://en.wikipedia.org/wiki/Earth_radius
00064   static const coord_type R_EARTH_EQUATORIAL; // Earth's equatorial radius, from http://en.wikipedia.org/wiki/Earth_radius
00065   static const coord_type R_EARTH_POLAR; // Earth's polar radius, from http://en.wikipedia.org/wiki/Earth_radius
00066   static const distance_type DEG2RAD;
00067   static const distance_type RAD2DEG;
00068 
00069   typedef enum {
00070     RADIANS,
00071     DEGREES
00072   } unit_type;
00073 
00074   static coord_type get_resolution() { return resolution; }
00075   static void set_resolution(distance_type new_resolution) {
00076     assert(new_resolution > 0);
00077     resolution = new_resolution;
00078   }
00079 
00080   Pixel_base() { /* do nothing */ }
00081 
00082   Pixel_base(const coord_type lat, const coord_type lon, const value_type &val, const unit_type unit = DEGREES) :
00083     lat_(lat),
00084     lon_(lon),
00085     val_(val)
00086   {
00087     if (unit == DEGREES) {
00088       lat_ *= DEG2RAD;
00089       lon_ *= DEG2RAD;
00090     }
00091     else {
00092       assert(unit == RADIANS);
00093     }
00094 
00095     assert(lat_ >= -M_PI_2 && lat_ <= M_PI_2);
00096     assert(lon_ >= -M_PI && lon_ <= M_PI);
00097 
00098    ilat = lround((lat_ + M_PI_2)*R_EARTH/(resolution));
00099    ilon = lround((lon_ + M_PI)*R_EARTH/(resolution));
00100 
00101   }
00102 
00103   bool operator< (const Pixel_type &other) const
00104   {
00105 
00106     // this is a strict weak ordering
00107 
00108     if (*this == other) return false;
00109     if (ilat < other.ilat) return true;
00110     if (ilat > other.ilat) return false;
00111     return (ilon < other.ilon);
00112 
00113   }
00114 
00115   bool operator== (const Pixel_type &other) const
00116   {
00117     return (ilat == other.ilat && ilon == other.ilon);
00118   }
00119 
00120   coord_type get_lat() const { return lat_; }
00121   coord_type get_lon() const { return lon_; }
00122   value_type get_val() const { return val_; }
00123 
00124   distance_type distance(const Pixel_type &other) const
00125   {
00126     // Haversine formulation of distances (better than law of cosines formulation which is ill-conditioned for small distances)
00127     // http://www.movable-type.co.uk/scripts/GIS-FAQ-5.1.html
00128     distance_type dlat;
00129     distance_type dlon;
00130     distance_type a;
00131     distance_type c;
00132     distance_type sin_dlat_2;
00133     distance_type sin_dlon_2;
00134 
00135     dlat = other.lat_ - lat_;
00136     dlon = other.lon_ - lon_;
00137 
00138     sin_dlat_2 = sin(dlat/2.);
00139     sin_dlon_2 = sin(dlon/2.);
00140     a = sin_dlat_2*sin_dlat_2 + cos(lat_)*cos(other.lat_)*sin_dlon_2*sin_dlon_2;
00141     c = 2 * asin(std::min(static_cast<T>(1.), static_cast<T>(sqrt(a)) ));
00142 
00143     return R_EARTH*c;
00144 
00145   }
00146 
00147   void get_neighbours(std::vector<Pixel_type> &neighbours, std::multiset<Pixel_type> &pixels, distance_type resolution, bool sorted = false) const  {
00148 
00149     using std::multiset;
00150     using std::pair;
00151     using std::vector;
00152 
00153     typedef multiset<Pixel_type> multiset_type;
00154     typedef typename multiset_type::iterator pixel_iterator;
00155     const coord_type dlat = resolution/R_EARTH;
00156     const coord_type dlon = resolution/R_EARTH;
00157 
00158     pair<pixel_iterator, pixel_iterator> range;
00159 
00160     for (coord_type xlat = lat_ - 2*dlat ; xlat <= lat_ + 2*dlat ; xlat += dlat ) {
00161       for (coord_type xlon = lon_ - 2*dlon ; xlon <= lon_ + 2*dlon ; xlon += dlon) {
00162         Pixel_type pixel(xlat, xlon, val_);
00163         range = pixels.equal_range(pixel);
00164         for (pixel_iterator ppixel = range.first ; ppixel != range.second ; ppixel++) {
00165           if (distance(*ppixel) < resolution) { neighbours.push_back(*ppixel); }
00166         }
00167       } // xlon
00168     } // xlat
00169 
00170     if (sorted) {
00171       sort(neighbours.begin(), neighbours.end(), Nearer_from<Pixel_type>(*this));
00172     }
00173 
00174   }
00175 
00176 
00177   friend std::ostream &operator<< (std::ostream &os, const Pixel_type& pixel)
00178   {
00179     os << "{" << pixel.lat_*RAD2DEG << " deg," << pixel.lon_*RAD2DEG << " deg}";
00180     return os;
00181   }
00182 
00183 private:
00184   static distance_type resolution; /* km */
00185 
00186   coord_type lat_; /* radians */
00187   coord_type lon_; /* radians */
00188   value_type val_;
00189 
00190 
00191   /* Earth globe is split into small square elements of resolution km along parallels and meridians.
00192    * Each element is indexed by (ilat, ilon).
00193    * All the (lat, lon) pairs that fall into the same (ilat, ilon) are considered equivalent.
00194    * (see operator==)
00195    */
00196   int ilat;
00197   int ilon;
00198 };
00199 
00203 template<typename T, class V>
00204 class P_Pixel_base {
00205 public:
00206   typedef P_Pixel_base<T, V> Pixel_type;
00207   typedef T coord_type;
00208   typedef T distance_type;
00209   typedef V value_type;
00210 private:
00211   coord_type* lat; /* degrees */
00212   coord_type* lon; /* degrees */
00213   value_type val;
00214 public:
00215   static const coord_type DEFAULT_RESOLUTION; // km
00216   static const coord_type R_EARTH; // Earth's authalic radius ("equal aera"), from http://en.wikipedia.org/wiki/Earth_radius
00217   static const coord_type R_EARTH_EQUATORIAL; // Earth's equatorial radius, from http://en.wikipedia.org/wiki/Earth_radius
00218   static const coord_type R_EARTH_POLAR; // Earth's polar radius, from http://en.wikipedia.org/wiki/Earth_radius
00219   static const distance_type DEG2RAD;
00220   static const distance_type RAD2DEG;
00221 
00222   typedef enum {
00223     RADIANS,
00224     DEGREES
00225   } unit_type;
00226 
00227   P_Pixel_base() : lat((coord_type*)(0)),lon((coord_type*)(0)),val(value_type(0)) { /* do nothing */ }
00228 
00229   P_Pixel_base(const coord_type* lat, const coord_type* lon, const value_type &val=value_type(0)) :
00230     lat(const_cast<coord_type*>(lat)),lon(const_cast<coord_type*>(lon)),val(val){}
00231 
00232   P_Pixel_base(const P_Pixel_base &other):lat(const_cast<coord_type*>(other.lat)),lon(const_cast<coord_type*>(other.lon)),val(other.val){}
00233 
00234   P_Pixel_base & operator= (const P_Pixel_base &other) {
00235     if (&other == this) return *this; // protect against self assignation
00236     lat=const_cast<coord_type*>(other.lat);
00237     lon=const_cast<coord_type*>(other.lon);
00238     val=other.val;
00239     return *this;
00240   }
00241 
00242   bool operator< (const Pixel_type &other) const
00243   {
00244     // this is a strict weak ordering
00245     if (*this == other) return false;
00246     if ((*lat) < other.get_lat()) return true;
00247     if ((*lat) > other.get_lat()) return false;
00248     return ((*lon) < other.get_lon());
00249 
00250   }
00251   bool operator== (const Pixel_type &other) const
00252   {
00253     return (get_lat() == other.get_lat() && get_lon() == other.get_lon());
00254   }
00255 
00256   coord_type get_lat() const { return coord_type(*lat); }
00257   coord_type get_lon() const { return coord_type(*lon); }
00258   value_type get_val() const { return val; }
00259 
00260   distance_type distance(const Pixel_type &other) const
00261   {
00262     // use a plane approximation
00263     return static_cast<distance_type>(sqrt (pow(other.get_lat()-get_lat(),2) + pow(other.get_lon()-get_lon(),2)) );
00264   }
00265 
00266 //   void get_neighbours(std::vector<Pixel_type> &neighbours, std::multiset<Pixel_type> &pixels, distance_type resolution, bool sorted = false) const  {
00267 //
00268 //     using std::multiset;
00269 //     using std::pair;
00270 //     using std::vector;
00271 //
00272 //     typedef multiset<Pixel_type> multiset_type;
00273 //     typedef typename multiset_type::iterator pixel_iterator;
00274 //     const coord_type dlat = resolution/R_EARTH;
00275 //     const coord_type dlon = resolution/R_EARTH;
00276 //
00277 //     pair<pixel_iterator, pixel_iterator> range;
00278 //
00279 //     for (coord_type xlat = *lat - 2*dlat ; xlat <= *lat + 2*dlat ; xlat += dlat ) {
00280 //       for (coord_type xlon = *lon - 2*dlon ; xlon <= *lon + 2*dlon ; xlon += dlon) {
00281 //         Pixel_type pixel(xlat, xlon, val);
00282 //         range = pixels.equal_range(pixel);
00283 //         for (pixel_iterator ppixel = range.first ; ppixel != range.second ; ppixel++) {
00284 //           if (distance(*ppixel) < resolution) { neighbours.push_back(*ppixel); }
00285 //         }
00286 //       } // xlon
00287 //     } // xlat
00288 //
00289 //     if (sorted) {
00290 //       sort(neighbours.begin(), neighbours.end(), Nearer_from<Pixel_type>(*this));
00291 //     }
00292 //   }
00293 //   template < class PPixelContainer >
00294   void get_neighbours( vector<Pixel_type> &neighbours, const vector<Pixel_type> &pixels,
00295                        distance_type resolution, bool sorted = false) {
00296 
00297     typedef typename vector<Pixel_type>::const_iterator pixel_iterator;
00298 
00299     /*** use a generic search on sorted datas ***/
00300     vector<int> default_value(1);
00301     default_value[0] = -1;
00302 
00303     // bounds of the colocation frame
00304     float lat_min=*lat-resolution; // lower latitude acceptable
00305     float lon_min=*lon-resolution; // lower longitude acceptable
00306     Pixel_type pix_min(&lat_min,&lon_min,default_value);
00307     float lat_max=*lat+resolution; // biggest latitude acceptable
00308     float lon_max=*lon+resolution; // biggest longitude acceptable
00309     Pixel_type pix_max(&lat_max,&lon_max,default_value);
00310 
00311     // set the range of colocated points candidates
00312     pixel_iterator i_pix_min = lower_bound(pixels.begin(), pixels.end(), pix_min);
00313     pixel_iterator i_pix_max = upper_bound(pixels.begin(), pixels.end(), pix_max);
00314 
00315 //     cout<<"Distance "<<distance(i_pix_min,i_pix_max)<<endl;
00316     // cross the candidates to match the ones in the resolution frame
00317     for ( pixel_iterator i_pix = i_pix_min ; i_pix != i_pix_max ; ++i_pix ) {
00318         if ( i_pix != pixels.end() &&
00319              abs(i_pix->get_lon()-*lon) < resolution &&
00320              abs(i_pix->get_lat()-*lat) < resolution )
00321             // the pixel is in the colocalisation frame
00322             neighbours.push_back( (*i_pix) );
00323     }
00324 
00325     if ( sorted ) {
00326       sort( neighbours.begin(), neighbours.end(), Nearer_from<Pixel_type>(*this) );
00327     }
00328   }
00329 
00330   friend std::ostream &operator<< (std::ostream &os, const Pixel_type& pixel)
00331   {
00332     os << "{" << pixel.get_lat() << " deg," << pixel.get_lon() << " deg}";
00333     return os;
00334   }
00335 };
00336 
00337 template<typename T, typename V>
00338 const typename Pixel_base<T, V>::coord_type Pixel_base<T,V>::DEFAULT_RESOLUTION = 1.; // km
00339 template<typename T, typename V>
00340 const typename Pixel_base<T, V>::coord_type Pixel_base<T,V>::R_EARTH = 6371.005076; // Earth's authalic radius ("equal aera"), from http://en.wikipedia.org/wiki/Earth_radius
00341 template<typename T, typename V>
00342 const typename P_Pixel_base<T, V>::coord_type P_Pixel_base<T,V>::R_EARTH=6371.005076;
00343 template<typename T, typename V>
00344 const typename Pixel_base<T, V>::coord_type Pixel_base<T,V>::R_EARTH_EQUATORIAL = 6378.137; // km
00345 template<typename T, typename V>
00346 const typename P_Pixel_base<T, V>::coord_type P_Pixel_base<T,V>::R_EARTH_EQUATORIAL = 6378.137; // km
00347 template<typename T, typename V>
00348 const typename Pixel_base<T, V>::coord_type Pixel_base<T,V>::R_EARTH_POLAR = 6356.7523; // km
00349 template<typename T, typename V>
00350 const typename P_Pixel_base<T, V>::coord_type P_Pixel_base<T,V>::R_EARTH_POLAR = 6356.7523; // km
00351 template<typename T, typename V>
00352 const typename Pixel_base<T, V>::distance_type Pixel_base<T,V>::DEG2RAD = M_PI/180.;
00353 template<typename T, typename V>
00354 const typename Pixel_base<T, V>::distance_type Pixel_base<T,V>::RAD2DEG = 180.*M_1_PI;
00355 
00356 template<typename T, typename V> typename
00357 Pixel_base<T, V>::distance_type Pixel_base<T, V>::resolution = DEFAULT_RESOLUTION;
00358 
00359 #endif // PIXEL_H

Generated on Thu Feb 14 2013 17:59:03 for filedata.kdevelop by  doxygen 1.7.1