Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

Lambert.cxx

Go to the documentation of this file.
00001 
00012 #include "Lambert.h"
00013 
00014 #include "UnaryTransform.h"
00015 
00016 #include "axes/AxisModelBase.h"
00017 #include "axes/AxisTick.h"
00018 
00019 #include "graphics/Rectangle.h"
00020 
00021 #include <cmath>
00022 #include <cstdio>
00023 
00024 #include <cassert>
00025 
00026 using namespace hippodraw;
00027 
00028 using std::max;
00029 using std::abs;
00030 using std::vector;
00031 
00032 Lambert::Lambert ( UnaryTransform * z )
00033   : PeriodicBinaryTransform ( z, true, true, false, true,
00034                               -180.0, +180.0,
00035                               - 90.0, + 90.0 )
00036 {
00037   m_name = "Lambert";
00038 }
00039 
00040 Lambert::Lambert ( const Lambert & t )
00041   :  PeriodicBinaryTransform ( t )
00042 {
00043 }
00044 
00045 Lambert::~Lambert ()
00046 {
00047 }
00048 
00049 #ifdef CLONE_DEFECT
00050 TransformBase * Lambert::clone () const
00051 #else
00052 Lambert    * Lambert::clone () const
00053 #endif
00054 {
00055   return new Lambert ( *this );
00056 }
00057 
00058 bool
00059 Lambert::
00060 isLinearInXY () const
00061 {
00062   return false;
00063 }
00064 
00065 /* virtual */
00066 void
00067 Lambert::
00068 transform ( double & lon, double & lat ) const
00069 {
00070   double lon_r = M_PI * lon / 180.0; // convert to radians from degrees
00071   double lat_r = M_PI * lat / 180.0; // convert to radians from degrees
00072 
00073   double q = 2 * sin ( ( M_PI / 2 - lat_r ) / 2 );
00074   
00075   lon = ( 180.0 / M_PI ) * q * sin ( lon_r );// Tranform and convert to degrees
00076   lat = ( 180.0 / M_PI ) * q * cos ( lon_r );// Tranform and convert to degrees
00077 }
00078 
00079 void
00080 Lambert::
00081 inverseTransform ( double & lon, double & lat ) const
00082 {
00083   double x  = lon * M_PI / 180.0; // Convert to radians
00084   double y  = lat * M_PI / 180.0; // Convert to radians
00085   double lon_r = atan2(x ,  y);   // Gets longitude in radians
00086                                   // (atan2 ensure value is in -M_PI to M_PI)  
00087 
00088   double lat_r =  M_PI / 2 - 2 * asin( 0.5 * sqrt ( x * x + y * y ) );
00089 
00090   lon = ( 180.0 / M_PI ) * lon_r;
00091   lat = ( 180.0 / M_PI ) * lat_r;
00092 }
00093 
00094 /* virtual */
00095 void
00096 Lambert::
00097 transform ( std::vector< double > & lon,
00098             std::vector< double > & lat ) const
00099 {
00100   assert ( lat.size() == lon.size() );
00101 
00102   std::vector < double >:: iterator it_lat = lat.begin ();
00103   std::vector < double >:: iterator it_lon = lon.begin ();
00104 
00105   for ( ; it_lat != lat.end(); ++it_lat, ++it_lon ) {
00106     transform ( *it_lon, *it_lat );
00107   }
00108 }
00109 
00110 /* virtual */
00111 double Lambert::aspectRatio () const
00112 {
00113   return 1.0;
00114 }
00115 
00116 HippoRectangle Lambert::calcRectangle ( const Range & lat,
00117                                         const Range & lon )
00118 {
00119   double x_lo = lat.low ();
00120   double x_hi = lat.high ();
00121   
00122   double y_lo = lon.low ();
00123   double y_hi = lon.high ();
00124 
00125   double x, y;
00126   
00127   double x_min =  1000;
00128   double x_max = -1000;
00129   double y_min =  1000;
00130   double y_max = -1000;
00131 
00132   int n = 50;
00133   double dx = ( x_hi - x_lo ) / n;
00134   double dy = ( y_hi - y_lo ) / n;
00135 
00136   // Finding out xmin, xmax, ymin, ymax along line y =  y_lo
00137   for ( int i = 0; i <= n; i++)
00138     {
00139       x = x_lo + i * dx; 
00140       y = y_lo;
00141       transform ( x, y );
00142       x_min = ( x_min < x ) ? x_min : x;
00143       x_max = ( x_max > x ) ? x_max : x;
00144       y_min = ( y_min < y ) ? y_min : y;
00145       y_max = ( y_max > y ) ? y_max : y;
00146     }
00147 
00148   // Finding out xmin, xmax, ymin, ymax along line y =  y_hi
00149   for ( int i = 0; i <= n; i++)
00150     {
00151       x = x_lo + i * dx; 
00152       y = y_hi;
00153       transform ( x, y );
00154       x_min = ( x_min < x ) ? x_min : x;
00155       x_max = ( x_max > x ) ? x_max : x;
00156       y_min = ( y_min < y ) ? y_min : y;
00157       y_max = ( y_max > y ) ? y_max : y;
00158     }
00159 
00160   // Finding out xmin, xmax, ymin, ymax along line x =  x_lo
00161   for ( int i = 0; i <= n; i++)
00162     {
00163       x = x_lo; 
00164       y = y_lo + i * dy;
00165       transform ( x, y );
00166       x_min = ( x_min < x ) ? x_min : x;
00167       x_max = ( x_max > x ) ? x_max : x;
00168       y_min = ( y_min < y ) ? y_min : y;
00169       y_max = ( y_max > y ) ? y_max : y;
00170     }
00171 
00172   // Finding out xmin, xmax, ymin, ymax along line x =  x_hi
00173   for ( int i = 0; i <= n; i++)
00174     {
00175       x = x_hi; 
00176       y = y_lo + i * dy;
00177       transform ( x, y );
00178       x_min = ( x_min < x ) ? x_min : x;
00179       x_max = ( x_max > x ) ? x_max : x;
00180       y_min = ( y_min < y ) ? y_min : y;
00181       y_max = ( y_max > y ) ? y_max : y;
00182     }
00183     
00184   return HippoRectangle ( x_min, y_min, x_max - x_min, y_max - y_min );
00185 }
00186 
00187 /* virtual */
00188 void Lambert::validate ( Range & lat, Range & lon ) const
00189 {
00190   if ( lat.low () < -180.0 ) lat.setLow ( -180.0 );
00191   if ( lat.high () > 180.0 ) lat.setHigh ( 180.0 );
00192 
00193   if ( lon.low () < -90.0 ) lon.setLow ( -90.0 );
00194   if ( lon.high () > 90.0 ) lon.setHigh ( 90.0 );
00195 }
00196 
00197 
00201 const vector < AxisTick > &
00202 Lambert::
00203 setTicks ( AxisModelBase & model, hippodraw::Axes::Type axis )
00204 { 
00205   if ( axis != Axes:: Z ) {
00206     setTickStep ( model );
00207     setFirstTick ( model );
00208     return genTicks ( model, axis );
00209   }
00210   else {
00211     return m_z -> setTicks ( model );
00212   }
00213 }
00214 
00216 void
00217 Lambert::
00218 adjustValues ( AxisModelBase & model,
00219                hippodraw::Axes::Type,
00220                const Range & limit )
00221 {
00222   // Does not do anything as of now 
00223   return;
00224 }
00225 
00226 inline double FLT_EQUAL( double x, double y )
00227 {
00228   return ( (double)abs( x - y ) <= 2.0 * ( y * FLT_EPSILON + FLT_MIN ) );
00229 }
00230 
00231 
00232 void Lambert::setTickStep( AxisModelBase & axis )
00233 {
00234   const Range & range = axis.getRange(false);
00235   double rangeLength = range.length();
00236 
00237   double scale_factor = axis.getScaleFactor();
00238   rangeLength *= scale_factor;
00239   
00240   // The following algorithm determines the magnitude of the range...
00241   double rmag = floor( log10( rangeLength ) );
00242   axis.setRMag( rmag );
00243   
00244   double scalelow = range.low() * scale_factor;
00245   double scalehigh = range.high() * scale_factor;
00246 
00247   // We will also need the largest magnitude for labels.
00248   double pmag = max( floor( log10( abs ( scalehigh ) ) ), 
00249                      floor( log10( abs ( scalelow ) ) ) );
00250   axis.setPMag( pmag );
00251   
00252   axis.setTickStep( rangeLength / 4.0 );
00253 }
00254 
00255 void Lambert::setFirstTick( AxisModelBase & axis )
00256 {
00257   const Range & range = axis.getRange(false);
00258   
00259   axis.setFirstTick ( range.low() );
00260 }
00261 
00262 
00265 const vector < AxisTick > &
00266 Lambert::
00267 genTicks( AxisModelBase & axis, hippodraw::Axes::Type axistype )
00268 { 
00269   double y = 0.0, ylabel;
00270   
00271   int num_ticks = 0;
00272   m_ticks.clear();
00273   double pmag = axis.getPMag();
00274   double rmag = axis.getRMag();
00275   double first_tick = axis.getFirstTick();
00276   double tick_step  = axis.getTickStep();
00277   double scale_factor = axis.getScaleFactor();
00278   
00279   // pmag will get set to 0 if it is less than or equal to 3.  This
00280   // is used later to determine scientific notation.  However, m_rmag
00281   // is still needed as the original magnitude for calculations such
00282   // as decimal place notation, and rounding to nice numbers.
00283   
00284   bool use_pmag = abs ( pmag ) > 3.0;
00285 
00286   axis.setUsePMag ( use_pmag );
00287   
00288   char pstr[10];
00289   char labl[10];
00290 
00291   int decimals = 0;
00292 
00293   // The following if-else block decides the pstr string, which holds
00294   // the number of decimal places in the label.
00295 
00296   //   if( fabs( m_pmag ) > 3.0 ) {
00297   if ( use_pmag ) {  
00298     // If we are greater than mag 3, we are showing scientific
00299     // notation.  How many decimals we show is determined by the
00300     // difference between the range magnitude and the power magnitude.
00301   
00302     decimals = static_cast<int>( pmag - rmag );
00303     // minumum 1 decimal in scientific notation
00304     
00305     if( !decimals ) decimals++;
00306   
00307   } else {
00308     
00309     if( rmag > 0.0 ){
00310     
00311       // If we are less than mag 3 and positive, then no decimal
00312       // accuracy is needed.
00313       
00314       decimals = 0;
00315       
00316     } else {
00317     
00318       // If we are less than mag 3 and negative, then we are suddenly
00319       // looking at decimal numbers not in scientific notation.
00320       // Therefore we hold as many decimal places as the magnitude.
00321       
00322       decimals = static_cast<int>( abs( rmag ) );
00323       
00324     }
00325   
00326   }
00327   // @todo decimals should never be negative here, but it does end up
00328   //    negative in some cases. See the "dirty fix" in Range.cxx, that
00329   //    dirty-fixed this problem too. But a better fix is needed. 
00330   if (decimals < 0) 
00331     decimals = 0;
00332    
00333   sprintf( pstr, "%%1.%df", decimals );
00334 
00335   y = first_tick;
00336   const Range & range = axis.getRange(false);
00337   double range_high = range.high();
00338   range_high *= scale_factor;
00339   
00340   while( y <= range_high || FLT_EQUAL( range_high, y ) )
00341     {
00342       double value = 0.0;
00343       
00344       if ( axistype == Axes::X ) {
00345         value = moduloAddX( y, xOffset() );
00346       }
00347       else if ( axistype == Axes::Y ) {
00348         value = moduloAddY( y, yOffset() );
00349       }
00350       
00351       // Now we either keep the original magnitude
00352       // or reduce it in order to express it in scientific notation.
00353       
00354       if ( use_pmag ) ylabel = value / pow( 10.0, pmag );
00355       else ylabel = value;
00356       
00357       value /= scale_factor;
00358       sprintf( labl, pstr, ylabel );
00359       m_ticks.push_back( AxisTick ( y, labl ) );
00360       
00361       num_ticks++;
00362       y += tick_step;
00363       
00364     }
00365   
00366   return m_ticks;
00367 }

Generated for HippoDraw-1.14.8.5 by doxygen 1.4.3