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
00066 void
00067 Lambert::
00068 transform ( double & lon, double & lat ) const
00069 {
00070 double lon_r = M_PI * lon / 180.0;
00071 double lat_r = M_PI * lat / 180.0;
00072
00073 double q = 2 * sin ( ( M_PI / 2 - lat_r ) / 2 );
00074
00075 lon = ( 180.0 / M_PI ) * q * sin ( lon_r );
00076 lat = ( 180.0 / M_PI ) * q * cos ( lon_r );
00077 }
00078
00079 void
00080 Lambert::
00081 inverseTransform ( double & lon, double & lat ) const
00082 {
00083 double x = lon * M_PI / 180.0;
00084 double y = lat * M_PI / 180.0;
00085 double lon_r = atan2(x , y);
00086
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
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
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
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
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
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
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
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
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
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
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
00280
00281
00282
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
00294
00295
00296
00297 if ( use_pmag ) {
00298
00299
00300
00301
00302 decimals = static_cast<int>( pmag - rmag );
00303
00304
00305 if( !decimals ) decimals++;
00306
00307 } else {
00308
00309 if( rmag > 0.0 ){
00310
00311
00312
00313
00314 decimals = 0;
00315
00316 } else {
00317
00318
00319
00320
00321
00322 decimals = static_cast<int>( abs( rmag ) );
00323
00324 }
00325
00326 }
00327
00328
00329
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
00352
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 }