/*
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 <cmath>
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);
}
syntax highlighted by Code2HTML, v. 0.9.1