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

HammerAito.cxx

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

Generated for HippoDraw-1.14.8.5 by doxygen 1.4.3