/* This projection is from Section 5.6.1 of Calabretta and Greisen (2002), "Representations of celestial coordinates in FITS", Astronomy and Astrophysics 395, 1077-1122. The paper is available online at http://www.atnf.csiro.au/~mcalabre/WCS */ #include using namespace std; #include "ProjectionTSC.h" #include "xpUtil.h" ProjectionTSC::ProjectionTSC(const int f, const int w, const int h) : ProjectionBase(f, w, h) { isWrapAround_ = false; xScale_ = 1; yScale_ = 2./3.; xOffset_ = -width_/8; yOffset_ = 0; // find the pixel values of the center of each cube face bool rotateSave = rotate_; rotate_ = false; for (int i = 0; i < 6; i++) { double lat_c, lon_c; GetCenterLatLon(i, lat_c, lon_c); sphericalToPixel(lon_c, lat_c, xPixel_[i], yPixel_[i]); xPixel_[i] -= xOffset_; } rotate_ = rotateSave; } void ProjectionTSC::GetCenterLatLon(const int face, double &lat_c, double &lon_c) const { switch (face) { case 0: lon_c = 0; lat_c = M_PI_2; break; case 1: lon_c = 0; lat_c = 0; break; case 2: lon_c = M_PI_2; lat_c = 0; break; case 3: lon_c = M_PI; lat_c = 0; break; case 4: lon_c = -M_PI_2; lat_c = 0; break; case 5: lon_c = 0; lat_c = -M_PI_2; break; default: xpExit("Unknown face???", __FILE__, __LINE__); break; } } void ProjectionTSC::GetXiEtaZeta(const int face, const double l, const double m, const double n, double &xi, double &eta, double &zeta) const { switch (face) { case 0: xi = m; eta = -l; zeta = n; break; case 1: xi = m; eta = n; zeta = l; break; case 2: xi = -l; eta = n; zeta = m; break; case 3: xi = -m; eta = n; zeta = -l; break; case 4: xi = l; eta = n; zeta = -m; break; case 5: xi = m; eta = l; zeta = -n; break; default: xpExit("Unknown face???", __FILE__, __LINE__); break; } } void ProjectionTSC::GetLMN(const int face, const double xi, const double eta, const double zeta, double &l, double &m, double &n) const { switch (face) { case 0: m = xi; l = -eta; n = zeta; break; case 1: m = xi; n = eta; l = zeta; break; case 2: l = -xi; n = eta; m = zeta; break; case 3: m = -xi; n = eta; l = -zeta; break; case 4: l = xi; n = eta; m = -zeta; break; case 5: m = xi; l = eta; n = -zeta; break; default: xpExit("Unknown face???", __FILE__, __LINE__); break; } } int ProjectionTSC::GetFace(const double x, const double y) const { int returnVal = -1; double dist = width_; for (int i = 0; i < 6; i++) { const double dx = x - xPixel_[i]; const double dy = y - yPixel_[i]; const double thisDist = sqrt(dx*dx + dy*dy); if (thisDist < dist) { dist = thisDist; returnVal = i; } } // check that the point is on the cube face if (fabs(x - xPixel_[returnVal]) > width_/8) return(-1); if (fabs(y - yPixel_[returnVal]) > height_/6) return(-1); return(returnVal); } bool ProjectionTSC::pixelToSpherical(const double x, const double y, double &lon, double &lat) { const double offsetX = x + width_/2 - centerX_ - xOffset_; const double offsetY = y + height_/2 - centerY_ - yOffset_; const double X = TWO_PI * (offsetX/width_ - 0.5)/xScale_; const double Y = M_PI * (0.5 - offsetY/height_)/yScale_; const int face = GetFace(offsetX, offsetY); if (face < 0) return(false); double lat_c, lon_c; GetCenterLatLon(face, lat_c, lon_c); const double chi = 4 * (X - lon_c) / M_PI; const double psi = 4 * (Y - lat_c) / M_PI; const double zeta = 1/sqrt(1 + chi*chi + psi*psi); const double xi = chi * zeta; const double eta = psi * zeta; double l, m, n; GetLMN(face, xi, eta, zeta, l, m, n); lat = asin(n); lon = atan2(m, l); if (fabs(lon) > M_PI) return(false); if (rotate_) RotateXYZ(lat, lon); if (lon > M_PI) lon -= TWO_PI; else if (lon < -M_PI) lon += TWO_PI; return(true); } bool ProjectionTSC::sphericalToPixel(double lon, double lat, double &x, double &y) const { if (rotate_) RotateZYX(lat, lon); const double l = cos(lat) * cos(lon); const double m = cos(lat) * sin(lon); const double n = sin(lat); int face = -1; if (fabs(l) >= fabs(m) && fabs(l) >= fabs(n)) { face = ((l < 0) ? 3 : 1); } else if (fabs(m) >= fabs(l) && fabs(m) >= fabs(n)) { face = ((m < 0) ? 4 : 2); } else if (fabs(n) >= fabs(l) && fabs(n) >= fabs(m)) { face = ((n < 0) ? 5 : 0); } double lon_c, lat_c; GetCenterLatLon(face, lat_c, lon_c); double xi, eta, zeta; GetXiEtaZeta(face, l, m, n, xi, eta, zeta); const double chi = xi/zeta; const double psi = eta/zeta; const double X = lon_c + chi * M_PI / 4; const double Y = lat_c + psi * M_PI / 4; x = width_ * (X * xScale_ / TWO_PI + 0.5); y = height_ * (0.5 - Y * yScale_ / M_PI); x += (centerX_ - width_/2 + xOffset_); y += (centerY_ - height_/2 + yOffset_); if (y < 0 || y >= height_) return(false); return(true); }