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 }
const std::vector< AxisTick > & genTicks(AxisModelBase &axis, hippodraw::Axes::Type axistype)
Generates the ticks in the axis.
double m_x_offset
The xoffset of this periodic transform.
Class representing a rectangle.
Definition: Rectangle.h:34
void setTickStep(const double &t_step)
Sets the tick step.
double getTickStep() const
Returns the tick step in the true coordinate system.
virtual ~PeriodicBinaryTransform()
The virtual destructor.
static double a1[3]
Definition: Landau.cxx:52
double moduloAdd(double a1, double a2, hippodraw::Axes::Type axis) const
Modulo Addition along either X or Y axis.
virtual bool inverseTransform(double &lon, double &lat) const
Transform the transformed coordinates on X and Y axis back to the original true data space...
hippodraw::AxisModelBase class interface
double moduloSub(double s1, double s2, hippodraw::Axes::Type axis) const
Modulo Subtraction along either X or Y axis.
double getPMag() const
Returns the magnitude of the power of ten for the tick labels.
virtual void setUsePMag(const bool &use_p_mag)
Use to set the value of the member variable m_use_pmag.
void setFirstTick(const double &first_tick)
Sets the value for first tick step.
Range m_y_limits
The limits on Y axis of the transform.
void setPMag(const double &pmag)
Sets the magnitude of the power of ten for the tick labels.
void setRMag(const double &rmag)
Sets the magnitude of the range.
Type
Axes constants.
Definition: AxesType.h:31
void setYOffset(double y_offset)
Sets the yOffset of the (periodic) transform.
virtual Rect calcRectangle(const Range &x, const Range &y)
Returns a rectangle enclosing the transformed data space.
A transform that transforms coordinates from one 2D coordinate system to another. ...
void initwcs(const std::string &transformName, double *crpix, double *crval, double *cdelt, double crota2, bool galactic)
Initialize the WCS transform type.
double high() const
Returns the maximum of the range object.
Definition: Range.cxx:100
void setHigh(double x)
Sets the maximum of the range object.
Definition: Range.cxx:106
double moduloAddY(double y1, double y2) const
Modulo Addition along Y axis.
double FLT_EQUAL(double x, double y)
UnaryTransform class interface.
virtual void transform(double &lon, double &lat) const
Transform the coordinates on the X and Y axes.
Namespace for HippoDraw.
Definition: AxesType.cxx:21
static double a2[2]
Definition: Landau.cxx:54
double length() const
Returns the length of the range object.
Definition: Range.h:156
virtual void validate(Range &lat, Range &lon) const
Validates the Ranges.
double moduloSubY(double y1, double y2) const
Modulo Subtraction along Y axis.
A Periodic transform that transforms coordinates from one 2D coordinate system to another...
intp size(numeric::array arr)
Definition: num_util.cpp:296
UnaryTransform * m_z
The transform on the Z axis.
void throwWCSMissing() const
Throws an exception if WCSLIB support is missing.
void setLow(double x)
Sets the minimum of the range object.
Definition: Range.cxx:93
double low() const
Returns the minimum of the range object.
Definition: Range.cxx:87
virtual void adjustValues(AxisModelBase &model, hippodraw::Axes::Type axes, const Range &limit)
Sets the range of given axis to be a new "nice" within the limits given.
void setFirstTick(AxisModelBase &axis)
Sets the first tick on the axis.
hippodraw::PeriodicBinaryTransform class interface
virtual const Range & limitX() const
Returns the Range limits of the first coordinate.
Expresses a range of values.
Definition: Range.h:33
Range m_x_limits
The limits on X axis of the transform.
virtual bool isLinearInXY() const
Returns true if the transform would be one to one on both the X and Y axes.
double m_y_offset
The yoffset of this periodic transform.
PeriodicBinaryTransform()
The default constructor.
void setXOffset(double x_offset)
Sets the xOffset of the (periodic) transform.
double getScaleFactor() const
Returns the scale factor.
void setTickStep(AxisModelBase &axis)
Helps to decide the tick size for the corresponding axis.
hippodrw::Rect class interface
virtual const Range & limitY() const
Returns the Range limits of the second coordinate.
double getRMag() const
Sets the magnitude of the range.
double yOffset() const
Returns the yOffset of the (periodic) transform.
virtual const std::vector< AxisTick > & setTicks(AxisModelBase &axis_model, hippodraw::Axes::Type axis)
double getFirstTick() const
Returns the value for the first tick step.
std::vector< AxisTick > m_ticks
The ticks last generated by this transform.
double moduloAddX(double x1, double x2) const
Modulo Addition along X axis.
double moduloSubX(double x1, double x2) const
Modulo Subtraction along X axis.
A class to maintain tick coordinates and string values.
Definition: AxisTick.h:29
The AxisModelBase class maintains the Range and scaling of an axis.
Definition: AxisModelBase.h:33
A transform that transforms coordinates in one dimension from one coordinate system to another...
double xOffset() const
Returns the xOffset of the (periodic) transform.
const Range & getRange(bool scaled) const
Returns the range represented by this AxisModel.

Generated for HippoDraw Class Library by doxygen