PeriodicBinaryTransform.cxx
Go to the documentation of this file.
1 
11 // for wcslib
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15 
17 
18 #include "axes/AxisModelBase.h"
19 #include "graphics/Rectangle.h"
20 #include "UnaryTransform.h"
21 
22 #ifdef HAVE_WCSLIB
23 #include <string.h>
24 #ifdef _WIN32
25 #include "C/wcs.h"
26 #else
27 #include "wcslib/wcs.h"
28 #endif
29 #endif
30 
31 #include <cmath>
32 #include <cstdio>
33 #include <stdexcept>
34 #include <sstream>
35 #include <cassert>
36 
37 using namespace hippodraw;
38 
39 using std::max;
40 using std::abs;
41 using std::vector;
42 
50  m_x_limits ( -180.0, +180.0 ),
51  m_y_limits ( - 90.0, + 90.0 ),
52  m_x_offset ( 0.0 ),
53  m_y_offset ( 0.0 )
54 {
55 }
56 
58  bool is_periodic,
59  bool needs_grid,
60  bool needs_x_ticks,
61  bool needs_y_ticks,
62  double xlo, double xhi,
63  double ylo, double yhi) :
64  BinaryTransform ( z, is_periodic, needs_grid, needs_x_ticks, needs_y_ticks ),
65  m_x_limits ( xlo, xhi ),
66  m_y_limits ( ylo, yhi ),
67  m_x_offset ( 0.0 ),
68  m_y_offset ( 0.0 )
69 {
70 }
71 
74  BinaryTransform ( t ),
75  m_x_limits( t.limitX() ),
76  m_y_limits( t.limitY() ),
77  m_x_offset( t.xOffset() ),
78  m_y_offset( t.yOffset() )
79 {
80 }
81 
83 {
84  // Does nothing
85 }
86 
88 {
89  return m_x_limits;
90 }
91 
92 
94 {
95  return m_y_limits;
96 }
97 
98 
100 {
101  return m_x_offset;
102 }
103 
104 void PeriodicBinaryTransform::setXOffset( double x_offset )
105 {
106  m_x_offset = x_offset;
107 }
108 
110 {
111  return m_y_offset;
112 }
113 
114 void PeriodicBinaryTransform::setYOffset( double y_offset )
115 {
116 
117  m_y_offset = y_offset;
118 }
119 
120 
121 double
123 moduloAdd( double a1, double a2, hippodraw::Axes::Type axis ) const
124 {
125  if ( axis == Axes::X ) {
126  return moduloAddX ( a1, a2);
127  }
128  else if ( axis == Axes::Y ) {
129  return moduloAddY ( a1, a2);
130  }
131  else return a1 + a2;
132 }
133 
134 double
136 moduloSub( double s1, double s2, hippodraw::Axes::Type axis ) const
137 {
138  if ( axis == Axes::X ) {
139  return moduloSubX ( s1, s2);
140  }
141  else if ( axis == Axes::Y ) {
142  return moduloSubY ( s1, s2);
143  }
144  else return s1 - s2;
145 }
146 
147 double PeriodicBinaryTransform::moduloAddX( double x1, double x2 ) const
148 {
149  if ( x2 < -DBL_EPSILON )
150  return moduloSubX ( x1, -x2 );
151 
152  double overshoot = x1 + x2 - m_x_limits.high();
153 
154  if ( overshoot > DBL_EPSILON ) {
155  return m_x_limits.low() + overshoot;
156  }
157  else {
158  return x1 + x2;
159  }
160 }
161 
162 double PeriodicBinaryTransform::moduloSubX( double x1, double x2 ) const
163 {
164  if ( x2 < -DBL_EPSILON )
165  return moduloAddX ( x1, -x2 );
166 
167  double undershoot = m_x_limits.low() - ( x1 - x2 );
168 
169  if ( undershoot > DBL_EPSILON)
170  return m_x_limits.high() - undershoot;
171  else
172  return x1 - x2;
173 }
174 
175 
176 double PeriodicBinaryTransform::moduloAddY( double y1, double y2 ) const
177 {
178  if ( y2 < -DBL_EPSILON ) return moduloSubY ( y1, -y2 );
179 
180  double overshoot = y1 + y2 - m_y_limits.high();
181 
182  if ( overshoot > DBL_EPSILON ) {
183  return m_y_limits.low() + overshoot;
184  }
185  else {
186  return y1 + y2;
187  }
188 
189 }
190 
191 double PeriodicBinaryTransform::moduloSubY( double y1, double y2 ) const
192 {
193  if ( y2 < -DBL_EPSILON ) return moduloAddY ( y1, -y2 );
194 
195  double undershoot = m_y_limits.low() - ( y1 - y2 );
196 
197  if ( undershoot > DBL_EPSILON ) return m_y_limits.high() - undershoot;
198  else return y1 - y2;
199 }
200 
201 
203  const Range & lon )
204 {
205  double x_lo = lat.low ();
206  double x_hi = lat.high ();
207 
208  double y_lo = lon.low ();
209  double y_hi = lon.high ();
210 
211  double x, y;
212 
213  double x_min = 1000;
214  double x_max = -1000;
215  double y_min = 1000;
216  double y_max = -1000;
217 
218  int n = 50;
219  double dx = ( x_hi - x_lo ) / n;
220  double dy = ( y_hi - y_lo ) / n;
221 
222 
223  // Finding out xmin, xmax, ymin, ymax along line y = y_lo
224  for ( int i = 0; i <= n; i++)
225  {
226  x = x_lo + i * dx;
227  y = y_lo;
228  transform ( x, y );
229  x_min = ( x_min < x ) ? x_min : x;
230  x_max = ( x_max > x ) ? x_max : x;
231  y_min = ( y_min < y ) ? y_min : y;
232  y_max = ( y_max > y ) ? y_max : y;
233  }
234 
235  // Finding out xmin, xmax, ymin, ymax along line y = y_hi
236  for ( int i = 0; i <= n; i++)
237  {
238  x = x_lo + i * dx;
239  y = y_hi;
240  transform ( x, y );
241  x_min = ( x_min < x ) ? x_min : x;
242  x_max = ( x_max > x ) ? x_max : x;
243  y_min = ( y_min < y ) ? y_min : y;
244  y_max = ( y_max > y ) ? y_max : y;
245  }
246 
247  // Finding out xmin, xmax, ymin, ymax along line x = x_lo
248  for ( int i = 0; i <= n; i++)
249  {
250  x = x_lo;
251  y = y_lo + i * dy;
252  transform ( x, y );
253  x_min = ( x_min < x ) ? x_min : x;
254  x_max = ( x_max > x ) ? x_max : x;
255  y_min = ( y_min < y ) ? y_min : y;
256  y_max = ( y_max > y ) ? y_max : y;
257  }
258 
259  // Finding out xmin, xmax, ymin, ymax along line x = x_hi
260  for ( int i = 0; i <= n; i++)
261  {
262  x = x_hi;
263  y = y_lo + i * dy;
264  transform ( x, y );
265  x_min = ( x_min < x ) ? x_min : x;
266  x_max = ( x_max > x ) ? x_max : x;
267  y_min = ( y_min < y ) ? y_min : y;
268  y_max = ( y_max > y ) ? y_max : y;
269  }
270 
271  return Rect ( x_min, y_min, x_max - x_min, y_max - y_min );
272 }
273 
274 
275 void PeriodicBinaryTransform::validate ( Range & lat, Range & lon ) const
276 {
277  if ( lat.low () < m_x_limits.low() ) lat.setLow ( m_x_limits.low() );
278  if ( lat.high () > m_x_limits.high() ) lat.setHigh ( m_x_limits.high() );
279 
280  if ( lon.low () < m_y_limits.low() ) lon.setLow ( m_y_limits.low() );
281  if ( lon.high () > m_y_limits.high() ) lon.setHigh ( m_y_limits.high() );
282 }
283 
287 const vector < AxisTick > &
290 {
291  if ( axis == Axes::Z ) {
292  return m_z -> setTicks ( model );
293  }
294  //else
295  setTickStep ( model );
296  setFirstTick ( model );
297  return genTicks ( model, axis );
298 }
299 
301 void
305  const Range & )
306 {
307  // Does not do anything as of now
308  return;
309 }
310 
311 inline double FLT_EQUAL( double x, double y )
312 {
313  return ( (double)abs( x - y ) <= 2.0 * ( y * FLT_EPSILON + FLT_MIN ) );
314 }
315 
316 
318 {
319  const Range & range = axis.getRange(false);
320  double rangeLength = range.length();
321 
322  double scale_factor = axis.getScaleFactor();
323  rangeLength *= scale_factor;
324 
325  // The following algorithm determines the magnitude of the range...
326  double rmag = floor( log10( rangeLength ) );
327  axis.setRMag( rmag );
328 
329  double scalelow = range.low() * scale_factor;
330  double scalehigh = range.high() * scale_factor;
331 
332  // We will also need the largest magnitude for labels.
333  double pmag = max( floor( log10( abs ( scalehigh ) ) ),
334  floor( log10( abs ( scalelow ) ) ) );
335  axis.setPMag( pmag );
336 
337  axis.setTickStep( rangeLength / 4.0 );
338 }
339 
341 {
342  const Range & range = axis.getRange(false);
343 
344  axis.setFirstTick ( range.low() );
345 }
346 
347 
352 const vector < AxisTick > &
355 {
356  double y = 0.0, ylabel;
357 
358  int num_ticks = 0;
359  m_ticks.clear();
360  double pmag = axis.getPMag();
361  double rmag = axis.getRMag();
362  double first_tick = axis.getFirstTick();
363  double tick_step = axis.getTickStep();
364  double scale_factor = axis.getScaleFactor();
365 
366  // pmag will get set to 0 if it is less than or equal to 3. This
367  // is used later to determine scientific notation. However, m_rmag
368  // is still needed as the original magnitude for calculations such
369  // as decimal place notation, and rounding to nice numbers.
370 
371  bool use_pmag = abs ( pmag ) > 3.0;
372 
373  axis.setUsePMag ( use_pmag );
374 
375  char pstr[10];
376  char labl[10];
377 
378  int decimals = 0;
379 
380  // The following if-else block decides the pstr string, which holds
381  // the number of decimal places in the label.
382 
383  // if( fabs( m_pmag ) > 3.0 ) {
384  if ( use_pmag ) {
385  // If we are greater than mag 3, we are showing scientific
386  // notation. How many decimals we show is determined by the
387  // difference between the range magnitude and the power magnitude.
388 
389  decimals = static_cast<int>( pmag - rmag );
390  // minumum 1 decimal in scientific notation
391 
392  if( !decimals ) decimals++;
393 
394  } else {
395 
396  if( rmag > 0.0 ){
397 
398  // If we are less than mag 3 and positive, then no decimal
399  // accuracy is needed.
400 
401  decimals = 0;
402 
403  } else {
404 
405  // If we are less than mag 3 and negative, then we are suddenly
406  // looking at decimal numbers not in scientific notation.
407  // Therefore we hold as many decimal places as the magnitude.
408 
409  decimals = static_cast<int>( abs( rmag ) );
410 
411  }
412 
413  }
414  // @todo decimals should never be negative here, but it does end up
415  // negative in some cases. See the "dirty fix" in Range.cxx, that
416  // dirty-fixed this problem too. But a better fix is needed.
417  if (decimals < 0)
418  decimals = 0;
419 
420  sprintf( pstr, "%%1.%df", decimals );
421 
422  y = first_tick;
423  const Range & range = axis.getRange(false);
424  double range_high = range.high();
425  range_high *= scale_factor;
426 
427  while( y <= range_high || FLT_EQUAL( range_high, y ) )
428  {
429  double value = 0.0;
430 
431  if ( axistype == Axes::X ) {
432  value = moduloAddX( y, xOffset() );
433  }
434  else if ( axistype == Axes::Y ) {
435  value = moduloAddY( y, yOffset() );
436  }
437 
438  // Now we either keep the original magnitude
439  // or reduce it in order to express it in scientific notation.
440 
441  if ( use_pmag ) ylabel = value / pow( 10.0, pmag );
442  else ylabel = value;
443 
444  value /= scale_factor;
445  sprintf( labl, pstr, ylabel );
446  m_ticks.push_back( AxisTick ( y, labl ) );
447 
448  num_ticks++;
449  if ( tick_step == 0.0 ) break;
450  y += tick_step;
451 
452  }
453 
454  return m_ticks;
455 }
456 
457 
458 bool
460 isLinearInXY () const
461 {
462  return false;
463 }
464 
465 
466 
467 
468 
469 /* Use WCSLIB to do transform. */
470 
471 void
473 initwcs(const std::string &transformName, double* crpix,
474  double* crval, double* cdelt, double crota2, bool galactic)
475 {
476 #ifdef HAVE_WCSLIB
477  // Assert the sizeof wcsprm struct is smaller than the size allocated.
478  assert(sizeof(wcsprm)<=2000);
479  m_wcs = reinterpret_cast<wcsprm*>(m_wcs_struct);
480  m_wcs->flag = -1;
481 
482  // Call wcsini() in WCSLIB.
483  int naxis = 2;
484  wcsini(1, naxis, m_wcs);
485 
486  // Transfer parameters from c++ class to c stuct.
487  std::string
488  lon_type = (galactic? "GLON-" : "RA---") + transformName,
489  lat_type = (galactic? "GLAT-" : "DEC--") + transformName;
490  strcpy(m_wcs->ctype[0], lon_type.c_str() );
491  strcpy(m_wcs->ctype[1], lat_type.c_str() );
492 
493  for( int i=0; i<naxis; ++i){
494  m_wcs->crval[i] = crval[i]; // reference value
495  m_wcs->crpix[i] = crpix[i]; // pixel coordinate
496  m_wcs->cdelt[i] = cdelt[i]; // scale factor
497  }
498 #else
499  throwWCSMissing ();
500 #endif
501 
502 }
503 
504 void
507 {
508  const std::string what
509  ( "HippoDraw has not been compiled with WCSLIB support" );
510  throw std::runtime_error ( what );
511 }
512 
513 
514 
515 /* virtual */
516 void
518 transform ( double & lon, double & lat ) const
519 {
520 
521 #ifdef HAVE_WCSLIB
522  int ncoords = 1;
523  int nelem = 2;
524  double imgcrd[2], pixcrd[2];
525  double phi[1], theta[1];
526  int stat[1];
527 
528  double worldcrd[] ={lon,lat};
529 
530  // int returncode =
531  wcss2p(m_wcs, ncoords, nelem, worldcrd, phi, theta, imgcrd, pixcrd, stat);
532 
533  lon = pixcrd[0];
534  lat = pixcrd[1];
535 #else
536  throwWCSMissing ();
537 #endif
538 
539 
540 }
541 
542 
543 bool
545 inverseTransform ( double & lon, double & lat ) const
546 {
547 
548 #ifdef HAVE_WCSLIB
549  int ncoords = 1;
550  int nelem = 2;
551  double worldcrd[2], imgcrd[2];
552  double phi[1], theta[1];
553  int stat[1];
554 
555  double pixcrd[] = {lon,lat};
556 
557  int returncode =
558  wcsp2s(m_wcs, ncoords, nelem, pixcrd, imgcrd, phi, theta, worldcrd, stat);
559 
560 
561  // If there is invalid coordinate, return false.
562  if ( returncode == 8 ) return false;
563 
564  // Make sure the inverse transform result in (-180,180) or (0,360)
565  //if (worldcrd[0]<0) worldcrd[0]=worldcrd[0]+360;
566  lon = worldcrd [0];
567  lat = worldcrd [1];
568 
569 
570  return true;
571 #else
572  throwWCSMissing ();
573  return false;
574 #endif
575 }
576 
577 void
579 transform ( std::vector< double > & lon,
580  std::vector< double > & lat ) const
581 {
582 
583 #ifdef HAVE_WCSLIB
584  assert ( lat.size() == lon.size() );
585  int size = lat.size();
586 
587  // Form vector to array.
588  vector < double > worldcrd ( 2*size );
589  for ( int i = 0; i < size; i++ ) {
590  worldcrd[2*i]= lon[i];
591  worldcrd[2*i+1]= lat[i];
592  }
593 
594  int ncoords = size;
595  int nelem = 2;
596 
597  vector < double > pixcrd( 2*size );
598  vector < double > imgcrd( 2*size );
599  vector < double > phi( size );
600  vector < double > theta( size );
601  vector < int > stat ( size );
602 
603  //int returncode =
604  wcss2p ( m_wcs, ncoords, nelem, &worldcrd[0], &phi[0], &theta[0],
605  &imgcrd[0], &pixcrd[0], &stat[0] );
606 
607  // From array to vector;
608  for ( int i = 0; i < size; i++ ) {
609  lon[i]=pixcrd[2*i];
610  lat[i]=pixcrd[2*i+1];
611  }
612 
613 #else
614  throwWCSMissing ();
615 #endif
616 }
unsigned int i
std::vector< AxisTick > m_ticks
The ticks last generated by this transform.
virtual void validate(Range &lat, Range &lon) const
Validates the Ranges.
double moduloAdd(double a1, double a2, hippodraw::Axes::Type axis) const
Modulo Addition along either X or Y axis.
Range m_x_limits
The limits on X axis of the transform.
void initwcs(const std::string &transformName, double *crpix, double *crval, double *cdelt, double crota2, bool galactic)
Initialize the WCS transform type.
virtual const Range & limitY() const
Returns the Range limits of the second coordinate.
double high() const
Returns the maximum of the range object.
Definition: Range.cxx:100
A class to maintain tick coordinates and string values.
Definition: AxisTick.h:29
UnaryTransform class interface.
void setFirstTick(const double &first_tick)
Sets the value for first tick step.
double moduloAddX(double x1, double x2) const
Modulo Addition along X axis.
static double a1[3]
Definition: Landau.cxx:52
hippodrw::Rect class interface
double moduloAddY(double y1, double y2) const
Modulo Addition along Y axis.
hippodraw::PeriodicBinaryTransform class interface
double yOffset() const
Returns the yOffset of the (periodic) transform.
virtual void adjustValues(AxisModelBase &model, hippodraw::Axes::Type axes, const Range &limit)
Sets the range of given axis to be a new &quot;nice&quot; within the limits given.
double xOffset() const
Returns the xOffset of the (periodic) transform.
static double a2[2]
Definition: Landau.cxx:54
void setLow(double x)
Sets the minimum of the range object.
Definition: Range.cxx:93
void setXOffset(double x_offset)
Sets the xOffset of the (periodic) transform.
virtual const Range & limitX() const
Returns the Range limits of the first coordinate.
virtual ~PeriodicBinaryTransform()
The virtual destructor.
Range m_y_limits
The limits on Y axis of the transform.
const std::vector< AxisTick > & genTicks(AxisModelBase &axis, hippodraw::Axes::Type axistype)
Generates the ticks in the axis.
void setHigh(double x)
Sets the maximum of the range object.
Definition: Range.cxx:106
A Periodic transform that transforms coordinates from one 2D coordinate system to another...
double moduloSubY(double y1, double y2) const
Modulo Subtraction along Y axis.
virtual void transform(double &lon, double &lat) const
Transform the coordinates on the X and Y axes.
double FLT_EQUAL(double x, double y)
void setPMag(const double &pmag)
Sets the magnitude of the power of ten for the tick labels.
double moduloSub(double s1, double s2, hippodraw::Axes::Type axis) const
Modulo Subtraction along either X or Y axis.
intp size(numeric::array arr)
Definition: num_util.cpp:296
void throwWCSMissing() const
Throws an exception if WCSLIB support is missing.
The AxisModelBase class maintains the Range and scaling of an axis.
Definition: AxisModelBase.h:33
double length() const
Returns the length of the range object.
Definition: Range.h:156
Class representing a rectangle.
Definition: Rectangle.h:34
double getScaleFactor() const
Returns the scale factor.
virtual const std::vector< AxisTick > & setTicks(AxisModelBase &axis_model, hippodraw::Axes::Type axis)
void setYOffset(double y_offset)
Sets the yOffset of the (periodic) transform.
hippodraw::AxisModelBase class interface
double getRMag() const
Sets the magnitude of the range.
double moduloSubX(double x1, double x2) const
Modulo Subtraction along X axis.
double getPMag() const
Returns the magnitude of the power of ten for the tick labels.
A transform that transforms coordinates from one 2D coordinate system to another. ...
const Range & getRange(bool scaled) const
Returns the range represented by this AxisModel.
A transform that transforms coordinates in one dimension from one coordinate system to another...
void setRMag(const double &rmag)
Sets the magnitude of the range.
double low() const
Returns the minimum of the range object.
Definition: Range.cxx:87
virtual Rect calcRectangle(const Range &x, const Range &y)
Returns a rectangle enclosing the transformed data space.
void setTickStep(const double &t_step)
Sets the tick step.
Expresses a range of values.
Definition: Range.h:33
PeriodicBinaryTransform()
The default constructor.
void setFirstTick(AxisModelBase &axis)
Sets the first tick on the axis.
void setTickStep(AxisModelBase &axis)
Helps to decide the tick size for the corresponding axis.
UnaryTransform * m_z
The transform on the Z axis.
virtual void setUsePMag(const bool &use_p_mag)
Use to set the value of the member variable m_use_pmag.
virtual bool inverseTransform(double &lon, double &lat) const
Transform the transformed coordinates on X and Y axis back to the original true data space...
double m_x_offset
The xoffset of this periodic transform.
double m_y_offset
The yoffset of this periodic transform.
double getFirstTick() const
Returns the value for the first tick step.
Type
Axes constants.
Definition: AxesType.h:31
virtual bool isLinearInXY() const
Returns true if the transform would be one to one on both the X and Y axes.
double getTickStep() const
Returns the tick step in the true coordinate system.

Generated for HippoDraw Class Library by doxygen