GammaLib 2.0.0
Loading...
Searching...
No Matches
GWcsAZP.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GWcsAZP.cpp - Zenithal/azimuthal perspective (AZP) projection class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2011-2021 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GWcsAZP.cpp
23 * @brief Zenithal/azimuthal perspective (AZP) projection class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GException.hpp"
32#include "GMath.hpp"
33#include "GWcsAZP.hpp"
34#include "GWcsRegistry.hpp"
35
36/* __ Method name definitions ____________________________________________ */
37#define G_PRJ_SET "GWcsAZP::prj_set()"
38#define G_PRJ_X2S "GWcsAZP::prj_x2s(int, int, int, int, double*, double*,"\
39 " double*, double*, int*)"
40#define G_PRJ_S2X "GWcsAZP::prj_s2x(int, int, int, int, double*, double*,"\
41 " double*, double*, int*)"
42
43/* __ Macros _____________________________________________________________ */
44
45/* __ Coding definitions _________________________________________________ */
46
47/* __ Debug definitions __________________________________________________ */
48
49/* __ Local prototypes ___________________________________________________ */
50
51/* __ Constants __________________________________________________________ */
52
53/* __ Globals ____________________________________________________________ */
55const GWcsRegistry g_wcs_azp_registry(&g_wcs_azp_seed);
56
57
58/*==========================================================================
59 = =
60 = Constructors/destructors =
61 = =
62 ==========================================================================*/
63
64/***********************************************************************//**
65 * @brief Void constructor
66 ***************************************************************************/
68{
69 // Initialise class members
71
72 // Return
73 return;
74}
75
76
77/***********************************************************************//**
78 * @brief Constructor
79 *
80 * @param[in] coords Coordinate system.
81 * @param[in] crval1 X value of reference pixel.
82 * @param[in] crval2 Y value of reference pixel.
83 * @param[in] crpix1 X index of reference pixel (starting from 1).
84 * @param[in] crpix2 Y index of reference pixel (starting from 1).
85 * @param[in] cdelt1 Increment in x direction at reference pixel [deg].
86 * @param[in] cdelt2 Increment in y direction at reference pixel [deg].
87 ***************************************************************************/
88GWcsAZP::GWcsAZP(const std::string& coords,
89 const double& crval1, const double& crval2,
90 const double& crpix1, const double& crpix2,
91 const double& cdelt1, const double& cdelt2) :
92 GWcs(coords, crval1, crval2, crpix1, crpix2, cdelt1, cdelt2)
93
94{
95 // Initialise class members
97
98 // Setup WCS derived parameters
99 wcs_set();
100
101 // Return
102 return;
103}
104
105
106/***********************************************************************//**
107 * @brief Copy constructor
108 *
109 * @param[in] wcs World Coordinate System.
110 ***************************************************************************/
111GWcsAZP::GWcsAZP(const GWcsAZP& wcs) : GWcs(wcs)
112{
113 // Initialise class members for clean destruction
114 init_members();
115
116 // Copy members
117 copy_members(wcs);
118
119 // Return
120 return;
121}
122
123
124/***********************************************************************//**
125 * @brief Destructor
126 ***************************************************************************/
128{
129 // Free members
130 free_members();
131
132 // Return
133 return;
134}
135
136
137/*==========================================================================
138 = =
139 = Operators =
140 = =
141 ==========================================================================*/
142
143/***********************************************************************//**
144 * @brief Assignment operator
145 *
146 * @param[in] wcs World Coordinate System.
147 * @return World Coordinate System.
148 ***************************************************************************/
150{
151 // Execute only if object is not identical
152 if (this != &wcs) {
153
154 // Copy base class members
155 this->GWcs::operator=(wcs);
156
157 // Free members
158 free_members();
159
160 // Initialise private members for clean destruction
161 init_members();
162
163 // Copy members
164 copy_members(wcs);
165
166 } // endif: object was not identical
167
168 // Return this object
169 return *this;
170}
171
172
173/*==========================================================================
174 = =
175 = Public methods =
176 = =
177 ==========================================================================*/
178
179/***********************************************************************//**
180 * @brief Clear instance
181 *
182 * This method properly resets the object to an initial state.
183 ***************************************************************************/
185{
186 // Free class members (base and derived classes, derived class first)
187 free_members();
188 this->GWcs::free_members();
190
191 // Initialise members
193 this->GWcs::init_members();
194 init_members();
195
196 // Return
197 return;
198}
199
200
201/***********************************************************************//**
202 * @brief Clone instance
203 *
204 * @return Pointer to deep copy of World Coordinate System.
205 ***************************************************************************/
207{
208 return new GWcsAZP(*this);
209}
210
211
212
213/***********************************************************************//**
214 * @brief Print WCS information
215 *
216 * @param[in] chatter Chattiness (defaults to NORMAL).
217 * @return String containing WCS information.
218 ***************************************************************************/
219std::string GWcsAZP::print(const GChatter& chatter) const
220{
221 // Initialise result string
222 std::string result;
223
224 // Continue only if chatter is not silent
225 if (chatter != SILENT) {
226
227 // Append header
228 result.append("=== GWcsAZP ===");
229
230 // Append information
231 result.append(wcs_print(chatter));
232
233 } // endif: chatter was not silent
234
235 // Return result
236 return result;
237}
238
239
240/*==========================================================================
241 = =
242 = Private methods =
243 = =
244 ==========================================================================*/
245
246/***********************************************************************//**
247 * @brief Initialise class members
248 ***************************************************************************/
250{
251 // Return
252 return;
253}
254
255
256/***********************************************************************//**
257 * @brief Copy class members
258 *
259 * @param[in] wcs World Coordinate System.
260 ***************************************************************************/
262{
263 // Return
264 return;
265}
266
267
268/***********************************************************************//**
269 * @brief Delete class members
270 ***************************************************************************/
272{
273 // Return
274 return;
275}
276
277
278/***********************************************************************//**
279 * @brief Setup of projection
280 *
281 * This method sets up the projection information. The method has been
282 * adapted from the wcslib function prj.c::azpset.
283 *
284 * @exception GException::runtime_error
285 * PV(1) or PV(2) are invalid.
286 *
287 * Given:
288 * m_pv[1] Distance parameter, mu in units of r0.
289 * m_pv[2] Tilt angle, gamma in degrees.
290 *
291 * Given and/or returned:
292 * m_r0 Reset to 180/pi if 0.
293 * m_phi0 Reset to 0.0 if undefined.
294 * m_theta0 Reset to 90.0 if undefined.
295 *
296 * Returned:
297 * m_x0 Fiducial offset in x.
298 * m_y0 Fiducial offset in y.
299 * m_w[0] r0*(mu+1)
300 * m_w[1] tan(gamma)
301 * m_w[2] sec(gamma)
302 * m_w[3] cos(gamma)
303 * m_w[4] sin(gamma)
304 * m_w[5] asin(-1/mu) for |mu| >= 1, -90 otherwise
305 * m_w[6] mu*cos(gamma)
306 * m_w[7] 1 if |mu*cos(gamma)| < 1, 0 otherwise
307 ***************************************************************************/
308void GWcsAZP::prj_set(void) const
309{
310 // Signal that projection has been set (needs to be done before calling
311 // the prj_off() method to avoid an endless loop)
312 m_prjset = true;
313
314 // Initialise projection parameters
315 m_w.assign(8, 0.0);
316
317 // Set undefined parameters
318 if (undefined(m_pv[1])) m_pv[1] = 0.0;
319 if (undefined(m_pv[2])) m_pv[2] = 0.0;
320 if (m_r0 == 0.0) m_r0 = gammalib::rad2deg;
321
322 // Precompute
323 m_w[0] = m_r0*(m_pv[1] + 1.0);
324 if (m_w[0] == 0.0) {
325 std::string msg = "PV(1)=-1 encountered.";
327 }
328 m_w[3] = gammalib::cosd(m_pv[2]);
329 if (m_w[3] == 0.0) {
330 std::string msg = "cos(PV(2))=0 encountered.";
332 }
333 m_w[2] = 1.0/m_w[3];
334 m_w[4] = gammalib::sind(m_pv[2]);
335 m_w[1] = m_w[4] / m_w[3];
336 if (std::abs(m_pv[1]) > 1.0) {
337 m_w[5] = gammalib::asind(-1.0/m_pv[1]);
338 }
339 else {
340 m_w[5] = -90.0;
341 }
342 m_w[6] = m_pv[1] * m_w[3];
343 m_w[7] = (std::abs(m_w[6]) < 1.0) ? 1.0 : 0.0;
344
345 // Compute fiducial offset
346 prj_off(0.0, 90.0);
347
348 // Return
349 return;
350}
351
352
353/***********************************************************************//**
354 * @brief Pixel-to-spherical deprojection
355 *
356 * @param[in] nx X vector length.
357 * @param[in] ny Y vector length (0=no replication).
358 * @param[in] sxy Input vector step.
359 * @param[in] spt Output vector step.
360 * @param[in] x Vector of projected x coordinates.
361 * @param[in] y Vector of projected y coordinates.
362 * @param[out] phi Longitude of the projected point in native spherical
363 * coordinates [deg].
364 * @param[out] theta Latitude of the projected point in native spherical
365 * coordinates [deg].
366 * @param[out] stat Status return value for each vector element (always 0)
367 *
368 * Deproject pixel (x,y) coordinates in the plane of projection to native
369 * spherical coordinates (phi,theta).
370 *
371 * This method has been adapted from the wcslib function prj.c::azpx2s().
372 * The interface follows very closely that of wcslib. In contrast to the
373 * wcslib routine, however, the method assumes that the projection has been
374 * setup previously (as this will be done by the constructor).
375 ***************************************************************************/
376void GWcsAZP::prj_x2s(int nx, int ny, int sxy, int spt,
377 const double* x, const double* y,
378 double* phi, double* theta, int* stat) const
379{
380 // Set tolerance
381 const double tol = 1.0e-13;
382
383 // Initialize projection if required
384 if (!m_prjset) {
385 prj_set();
386 }
387
388 // Set value replication length mx,my
389 int mx;
390 int my;
391 if (ny > 0) {
392 mx = nx;
393 my = ny;
394 }
395 else {
396 mx = 1;
397 my = 1;
398 ny = nx;
399 }
400
401 // Initialise status code and statistics
402 int status = 0;
403 int n_invalid = 0;
404
405 // Do x dependence
406 const double* xp = x;
407 int rowoff = 0;
408 int rowlen = nx * spt;
409 for (int ix = 0; ix < nx; ++ix, rowoff += spt, xp += sxy) {
410 double xj = *xp + m_x0;
411 double* phip = phi + rowoff;
412 for (int iy = 0; iy < my; ++iy, phip += rowlen) {
413 *phip = xj;
414 }
415 }
416
417 // Do y dependence
418 const double* yp = y;
419 double* phip = phi;
420 double* thetap = theta;
421 int* statp = stat;
422 for (int iy = 0; iy < ny; ++iy, yp += sxy) {
423 double yj = *yp + m_y0;
424 double yc = yj * m_w[3];
425 double yc2 = yc*yc;
426 double q = m_w[0] + yj*m_w[4];
427 for (int ix = 0; ix < mx; ++ix, phip += spt, thetap += spt) {
428 double xj = *phip;
429 double r = sqrt(xj*xj + yc2);
430 if (r == 0.0) {
431 *phip = 0.0;
432 *thetap = 90.0;
433 *(statp++) = 0;
434
435 }
436 else {
437 *phip = gammalib::atan2d(xj, -yc);
438 double s = r / q;
439 double t = s * m_pv[1]/std::sqrt(s*s + 1.0);
440 s = gammalib::atan2d(1.0, s);
441 if (std::abs(t) > 1.0) {
442 if (std::abs(t) > 1.0+tol) {
443 *thetap = 0.0;
444 *(statp++) = 1;
445 status = 3;
446 n_invalid++;
447 continue;
448 }
449 t = (t < 0) ? -90.0 : 90.0;
450 }
451 else {
452 t = gammalib::asind(t);
453 }
454 double a = s - t;
455 double b = s + t + 180.0;
456 if (a > 90.0) a -= 360.0;
457 if (b > 90.0) b -= 360.0;
458 *thetap = (a > b) ? a : b;
459 *(statp++) = 0;
460 }
461 }
462 }
463
464 // Check status code
465 gammalib::check_prj_x2s_status(G_PRJ_X2S, status, n_invalid);
466
467 // Return
468 return;
469}
470
471
472/***********************************************************************//**
473 * @brief Generic spherical-to-pixel projection
474 *
475 * @param[in] nphi Longitude vector length.
476 * @param[in] ntheta Latitude vector length (0=no replication).
477 * @param[in] spt Input vector step.
478 * @param[in] sxy Output vector step.
479 * @param[in] phi Longitude vector of the projected point in native spherical
480 * coordinates [deg].
481 * @param[in] theta Latitude vector of the projected point in native spherical
482 * coordinates [deg].
483 * @param[out] x Vector of projected x coordinates.
484 * @param[out] y Vector of projected y coordinates.
485 * @param[out] stat Status return value for each vector element (always 0)
486 *
487 * Project native spherical coordinates (phi,theta) to pixel (x,y)
488 * coordinates in the plane of projection.
489 *
490 * This method has been adapted from the wcslib function prj.c::azps2x().
491 * The interface follows very closely that of wcslib. In contrast to the
492 * wcslib routine, however, the method assumes that the projection has been
493 * setup previously (as this will be done by the constructor).
494 ***************************************************************************/
495void GWcsAZP::prj_s2x(int nphi, int ntheta, int spt, int sxy,
496 const double* phi, const double* theta,
497 double* x, double* y, int* stat) const
498{
499 // Initialize projection if required
500 if (!m_prjset) {
501 prj_set();
502 }
503
504 // Set value replication length mphi,mtheta
505 int mphi;
506 int mtheta;
507 if (ntheta > 0) {
508 mphi = nphi;
509 mtheta = ntheta;
510 }
511 else {
512 mphi = 1;
513 mtheta = 1;
514 ntheta = nphi;
515 }
516
517 // Initialise status code and statistics
518 int status = 0;
519 int n_invalid = 0;
520
521 // Do phi dependence
522 const double* phip = phi;
523 int rowoff = 0;
524 int rowlen = nphi * sxy;
525 for (int iphi = 0; iphi < nphi; ++iphi, rowoff += sxy, phip += spt) {
526 double sinphi;
527 double cosphi;
528 gammalib::sincosd(*phip, &sinphi, &cosphi);
529 double* xp = x + rowoff;
530 double* yp = y + rowoff;
531 for (int itheta = 0; itheta < mtheta; ++itheta) {
532 *xp = sinphi;
533 *yp = cosphi;
534 xp += rowlen;
535 yp += rowlen;
536 }
537 }
538
539 // Do theta dependence
540 const double* thetap = theta;
541 double* xp = x;
542 double* yp = y;
543 int* statp = stat;
544 for (int itheta = 0; itheta < ntheta; ++itheta, thetap += spt) {
545
546 // Compute sin(theta) and cos(theta)
547 double sinthe;
548 double costhe;
549 gammalib::sincosd(*thetap, &sinthe, &costhe);
550
551 // ...
552 for (int iphi = 0; iphi < mphi; ++iphi, xp += sxy, yp += sxy) {
553
554 double s = m_w[1]*(*yp);
555 double t = (m_pv[1] + sinthe) + costhe*s;
556
557 // ...
558 if (t == 0.0) {
559 *xp = 0.0;
560 *yp = 0.0;
561 *(statp++) = 1;
562 status = 4;
563 n_invalid++;
564 }
565
566 // ...
567 else {
568 double r = m_w[0]*costhe/t;
569
570 // Bounds checking
571 int istat = 0;
572 if (m_bounds) {
573
574 // Is there overlap?
575 if (*thetap < m_w[5]) {
576 istat = 1;
577 status = 4;
578 n_invalid++;
579 }
580
581 // Is there divergence?
582 else if (m_w[7] > 0.0) {
583 t = m_pv[1] / sqrt(1.0 + s*s);
584 if (std::abs(t) <= 1.0) {
585 s = gammalib::atand(-s);
586 t = gammalib::asind(t);
587 double a = s - t;
588 double b = s + t + 180.0;
589 if (a > 90.0) a -= 360.0;
590 if (b > 90.0) b -= 360.0;
591 if (*thetap < ((a > b) ? a : b)) {
592 istat = 1;
593 status = 4;
594 n_invalid++;
595 }
596 }
597 }
598 }
599
600 // Set value
601 *xp = r*(*xp) - m_x0;
602 *yp = -r*(*yp) * m_w[2] - m_y0;
603 *(statp++) = istat;
604 } // endelse
605 } // endfor: phi
606 } // endfor: theta
607
608 // Check status code
609 gammalib::check_prj_s2x_status(G_PRJ_S2X, status, n_invalid);
610
611 // Return
612 return;
613}
Exception handler interface definition.
Mathematical function definitions.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
GVector sqrt(const GVector &vector)
Computes square root of vector elements.
Definition GVector.cpp:1358
#define G_PRJ_X2S
Definition GWcsAIT.cpp:38
#define G_PRJ_S2X
Definition GWcsAIT.cpp:40
#define G_PRJ_SET
Definition GWcsAZP.cpp:37
const GWcsAZP g_wcs_azp_seed
Definition GWcsAZP.cpp:54
Zenithal/azimuthal perspective (AZP) projection class definition.
World Coordinate Projection registry class interface definition.
void free_members(void)
Delete class members.
void init_members(void)
Initialise class members.
Zenithal/azimuthal perspective (AZP) projection class definition.
Definition GWcsAZP.hpp:43
void copy_members(const GWcsAZP &wcs)
Copy class members.
Definition GWcsAZP.cpp:261
void prj_set(void) const
Setup of projection.
Definition GWcsAZP.cpp:308
GWcsAZP & operator=(const GWcsAZP &wcs)
Assignment operator.
Definition GWcsAZP.cpp:149
void init_members(void)
Initialise class members.
Definition GWcsAZP.cpp:249
virtual void clear(void)
Clear instance.
Definition GWcsAZP.cpp:184
GWcsAZP(void)
Void constructor.
Definition GWcsAZP.cpp:67
void prj_s2x(int nphi, int ntheta, int spt, int sxy, const double *phi, const double *theta, double *x, double *y, int *stat) const
Generic spherical-to-pixel projection.
Definition GWcsAZP.cpp:495
virtual ~GWcsAZP(void)
Destructor.
Definition GWcsAZP.cpp:127
void free_members(void)
Delete class members.
Definition GWcsAZP.cpp:271
void prj_x2s(int nx, int ny, int sxy, int spt, const double *x, const double *y, double *phi, double *theta, int *stat) const
Pixel-to-spherical deprojection.
Definition GWcsAZP.cpp:376
virtual std::string print(const GChatter &chatter=NORMAL) const
Print WCS information.
Definition GWcsAZP.cpp:219
virtual GWcsAZP * clone(void) const
Clone instance.
Definition GWcsAZP.cpp:206
Interface definition for the WCS registry class.
Abstract world coordinate system base class.
Definition GWcs.hpp:51
void free_members(void)
Delete class members.
Definition GWcs.cpp:1066
void prj_off(const double &phi0, const double &theta0) const
Compute fiducial offset to force (x,y) = (0,0) at (phi0,theta0)
Definition GWcs.cpp:3232
virtual GWcs & operator=(const GWcs &wcs)
Assignment operator.
Definition GWcs.cpp:180
std::string wcs_print(const GChatter &chatter=NORMAL) const
Print WCS information.
Definition GWcs.cpp:1642
void init_members(void)
Initialise class members.
Definition GWcs.cpp:962
double m_pv[PVN]
Projection parameters.
Definition GWcs.hpp:213
void wcs_set(void) const
Setup of World Coordinate System.
Definition GWcs.cpp:1262
bool m_bounds
Enable strict bounds checking.
Definition GWcs.hpp:214
bool m_prjset
Projection is set.
Definition GWcs.hpp:211
std::vector< double > m_w
Intermediate values.
Definition GWcs.hpp:217
double m_y0
Fiducial y offset.
Definition GWcs.hpp:216
double m_x0
Fiducial x offset.
Definition GWcs.hpp:215
double m_r0
Radius of the generating sphere.
Definition GWcs.hpp:212
bool undefined(const double &value) const
Check if value is undefined.
Definition GWcs.hpp:262
void sincosd(const double &angle, double *s, double *c)
Compute sine and cosine of angle in degrees.
Definition GMath.cpp:342
double asind(const double &value)
Compute arc sine in degrees.
Definition GMath.cpp:250
double cosd(const double &angle)
Compute cosine of angle in degrees.
Definition GMath.cpp:134
double sind(const double &angle)
Compute sine of angle in degrees.
Definition GMath.cpp:163
void check_prj_s2x_status(const std::string &origin, const int &status, const int &number)
Checks status of GWcs::prj_s2x method.
double atan2d(const double &y, const double &x)
Compute arc tangens in degrees.
Definition GMath.cpp:308
double atand(const double &value)
Compute arc tangens in degrees.
Definition GMath.cpp:282
void check_prj_x2s_status(const std::string &origin, const int &status, const int &number)
Checks status of GWcs::prj_x2s method.
const double rad2deg
Definition GMath.hpp:44