44#include "Eigen/Cholesky"
60 if (shift ==
nullptr)
return false;
62 static const double eps = 1e-5;
65 double dy = shift->getCoefficient(0, 0, 1);
67 static Point dumb(4000, 4000);
69 fabs(dumb.
x + dx - shift->apply(dumb).x) < eps &&
fabs(dumb.
y + dy - shift->apply(dumb).y) < eps)
79 double xtmin1, xtmax1, ytmin1, ytmax1;
85 double xtmin2, xtmax2, ytmin2, ytmax2;
91 if (inscribed)
return fr1 * fr2;
102 double eps =
x * 0.01;
103 if (eps == 0) eps = 0.01;
113 return ((dxdx * dydy - dxdy * dydx) / (eps * eps));
120 const double step)
const {
128 derivative.
a11() = (xp - xp0) /
step;
129 derivative.
a21() = (yp - yp0) /
step;
132 derivative.
a22() = (yp - yp0) /
step;
138 const double step)
const {
153 double a11 = der.
A11();
154 double a22 = der.
A22();
155 double a21 = der.
A21();
156 double a12 = der.
A12();
157 res.
vx = a11 * (a11 * in.vx + 2 * a12 * in.vxy) + a12 * a12 * in.vy;
158 res.
vy = a21 * a21 * in.vx + a22 * a22 * in.vy + 2. * a21 * a22 * in.vxy;
159 res.
vxy = a21 * a11 * in.vx + a22 * a12 * in.vy + (a21 * a12 + a11 * a22) * in.vxy;
166 double a11 = der.
A11();
167 double a22 = der.
A22();
168 double a21 = der.
A21();
169 double a12 = der.
A12();
184 double b11 = a11 * vIn[xx] + a12 * vIn[xy];
185 double b22 = a21 * vIn[xy] + a22 * vIn[yy];
186 double b12 = a11 * vIn[xy] + a12 * vIn[yy];
187 double b21 = a21 * vIn[xx] + a22 * vIn[xy];
191 vOut[xx] = b11 * a11 + b12 * a12;
192 vOut[xy] = b11 * a21 + b12 * a22;
193 vOut[yy] = b21 * a21 + b22 * a22;
229 std::string(
"AstrometryTransform::paramRef should never be called "));
234 "AstrometryTransform::paramRef should never be called ");
239 "AstrometryTransform::paramDerivatives() should never be called ");
254 "AstrometryTransform::write, something went wrong for file " + fileName);
260 "AstrometryTransform::write(ostream), should never be called. MEans that it is missing in some "
276 const Frame ®ion);
280 void apply(
double xIn,
double yIn,
double &xOut,
double &yOut)
const;
295 return _direct->clone();
305 const Frame ®ion)
const {
310 const double precision,
const Frame ®ion) {
312 _roughInverse = _direct->roughInverse(region);
313 precision2 = precision * precision;
318 _direct = model._direct->clone();
319 _roughInverse = model._roughInverse->clone();
320 precision2 = model.precision2;
326 _direct = model._direct->clone();
327 _roughInverse = model._roughInverse->clone();
328 precision2 = model.precision2;
333 Point outGuess = _roughInverse->apply(in);
340 Point inGuess = _direct->apply(outGuess);
341 _direct->computeDerivative(outGuess, directDer);
343 double xShift, yShift;
344 reverseDer.
apply(xIn - inGuess.
x, yIn - inGuess.
y, xShift, yShift);
345 outGuess.
x += xShift;
346 outGuess.
y += yShift;
347 move2 = xShift * xShift + yShift * yShift;
348 }
while ((move2 > precision2) && (loop < maxloop));
349 if (loop == maxloop)
LOGLS_WARN(_log,
"Problems applying AstrometryTransformInverse at " << in);
355 stream <<
" AstrometryTransformInverse of :" <<
endl << *_direct <<
endl;
360 "Cannot fit a AstrometryTransformInverse. Use StarMatchList::inverseTransform instead.");
382 void apply(
double xIn,
double yIn,
double &xOut,
double &yOut)
const;
394 _first = first.clone();
395 _second = second.clone();
399 double &yOut)
const {
401 _first->apply(xIn, yIn, xout, yout);
402 _second->apply(xout, yout, xOut, yOut);
406 stream <<
"Composed AstrometryTransform consisting of:" <<
std::endl;
407 _first->print(stream);
408 _second->print(stream);
413 return _first->fit(starMatchList);
417 return std::make_unique<AstrometryTransformComposition>(*_second, *_first);
433 if (composition ==
nullptr)
434 return std::make_unique<AstrometryTransformComposition>(
left,
right);
441 const double)
const {
446 const double)
const {
452 return std::make_shared<ast::UnitMap>(2);
456 stream <<
"AstrometryTransformIdentity 1" <<
endl;
464 " AstrometryTransformIdentity::read : format is not 1 ");
475 _coeffs.
resize(2 * _nterms, 0.);
490 for (
double x = frame.xMin +
step / 2;
x <= frame.xMax;
x +=
step)
491 for (
double y = frame.yMin +
step / 2;
y <= frame.yMax;
y +=
step) {
492 auto pix = std::make_shared<BaseStar>(
x,
y, 0, 0);
495 auto tp = std::make_shared<BaseStar>(xtr, ytr, 0, 0);
510 double xStart = domain.
xMin;
511 double yStart = domain.
yMin;
512 double xStep = domain.
getWidth() / (nSteps + 1);
513 double yStep = domain.
getHeight() / (nSteps + 1);
525 poly.fit(starMatchList);
529void AstrometryTransformPolynomial::computeMonomials(
double xIn,
double yIn,
double *monomial)
const {
543 for (
std::size_t iy = 0; iy <= _order - ix; ++iy) {
544 monomial[k] = xx * yy;
555 _nterms = (_order + 1) * (_order + 2) / 2;
560 _coeffs.
resize(2 * _nterms);
563 for (
std::size_t k = 0; k < _nterms; ++k) _coeffs[k] = 0;
567 _coeffs[k] = old_coeffs[k];
568 _coeffs[k + _nterms] = old_coeffs[k + old_nterms];
574 double &yOut)
const {
584 double monomials[_nterms];
585 computeMonomials(xIn, yIn, monomials);
589 const double *c = &_coeffs[0];
590 const double *pm = &monomials[0];
592 for (
int k = _nterms; k--;) xOut += (*(pm++)) * (*(c++));
594 for (
int k = _nterms; k--;) yOut += (*(pm++)) * (*(c++));
603 derivative.
dx() = derivative.
dy() = 0;
607 double dermx[2 * _nterms];
608 double *dermy = dermx + _nterms;
609 double xin = where.x;
610 double yin = where.y;
617 dermx[k] = ix * xxm1;
621 for (
std::size_t iy = 1; iy <= _order - ix; ++iy) {
622 dermx[k] = ix * xxm1 * yym1 * yin;
623 dermy[k] = iy * xx * yym1;
628 if (ix >= 1) xxm1 *= xin;
634 const double *mx = &dermx[0];
635 const double *my = &dermy[0];
636 const double *c = &_coeffs[0];
638 double a11 = 0, a12 = 0;
639 for (
int k = _nterms; k--;) {
640 a11 += (*(mx++)) * (*c);
641 a12 += (*(my++)) * (*(c++));
643 derivative.
a11() = a11;
644 derivative.
a12() = a12;
646 double a21 = 0, a22 = 0;
649 for (
int k = _nterms; k--;) {
650 a21 += (*(mx++)) * (*c);
651 a22 += (*(my++)) * (*(c++));
653 derivative.
a21() = a21;
654 derivative.
a22() = a22;
670 double monomials[_nterms];
674 double dermx[2 * _nterms];
675 double *dermy = dermx + _nterms;
684 dermx[k] = ix * xxm1;
690 for (
std::size_t iy = 1; iy <= _order - ix; ++iy) {
691 monomials[k] = xx * yy;
692 dermx[k] = ix * xxm1 * yy;
693 dermy[k] = iy * xx * yym1;
699 if (ix >= 1) xxm1 *= xin;
703 double xout = 0, yout = 0;
704 const double *c = &_coeffs[0];
705 const double *pm = &monomials[0];
706 for (
int k = _nterms; k--;) xout += (*(pm++)) * (*(c++));
708 for (
int k = _nterms; k--;) yout += (*(pm++)) * (*(c++));
714 const double *mx = &dermx[0];
715 const double *my = &dermy[0];
716 double a11 = 0, a12 = 0;
717 for (
int k = _nterms; k--;) {
718 a11 += (*(mx++)) * (*c);
719 a12 += (*(my++)) * (*(c++));
722 double a21 = 0, a22 = 0;
725 for (
int k = _nterms; k--;) {
726 a21 += (*(mx++)) * (*c);
727 a22 += (*(my++)) * (*(c++));
731 res.
vx = a11 * (a11 * in.vx + 2 * a12 * in.vxy) + a12 * a12 * in.vy;
732 res.
vy = a21 * a21 * in.vx + a22 * a22 * in.vy + 2. * a21 * a22 * in.vxy;
733 res.
vxy = a21 * a11 * in.vx + a22 * a12 * in.vy + (a21 * a12 + a11 * a22) * in.vxy;
743 assert((degX + degY <= _order) && whichCoord < 2);
747 return _coeffs[(degX + degY) * (degX + degY + 1) / 2 + degY + whichCoord * _nterms];
752 assert((degX + degY <= _order) && whichCoord < 2);
753 return _coeffs[(degX + degY) * (degX + degY + 1) / 2 + degY + whichCoord * _nterms];
759 assert(whichCoord < 2);
760 if (degX + degY <= _order)
761 return _coeffs[(degX + degY) * (degX + degY + 1) / 2 + degY + whichCoord * _nterms];
767 assert(i < 2 * Eigen::Index(_nterms));
772 assert(i < 2 * Eigen::Index(_nterms));
778 computeMonomials(where.x, where.y, dx);
780 dy[_nterms + k] = dx[k];
781 dx[_nterms + k] = dy[k] = 0;
788 if (powX + powY) ss <<
"*";
789 if (powX > 0) ss <<
"x";
790 if (powX > 1) ss <<
"^" << powX;
791 if (powY > 0) ss <<
"y";
792 if (powY > 1) ss <<
"^" << powY;
805 bool printed =
false;
809 if (coefficient != 0 ||
isnan(coefficient)) {
811 if (printed && p +
py != 0) stream <<
" + ";
813 stream << coefficient << monomialString(p -
py,
py);
822 if (_order > 0) stream <<
"Linear determinant = " <<
determinant();
835 Point center = frame.getCenter();
841static AstrometryTransformLinear shiftAndNormalize(StarMatchList
const &starMatchList) {
847 for (
const auto & a_match : starMatchList) {
848 Point
const &point1 = a_match.point1;
855 if (
count == 0)
return AstrometryTransformLinear();
861 return AstrometryTransformLinearScale(2. / xspan, 2. / yspan) *
862 AstrometryTransformLinearShift(-xav, -yav);
865static double sq(
double x) {
return x *
x; }
867double AstrometryTransformPolynomial::computeFit(StarMatchList
const &starMatchList,
868 AstrometryTransform
const &shiftToCenter,
869 const bool useErrors) {
870 Eigen::MatrixXd A(2 * _nterms, 2 * _nterms);
872 Eigen::VectorXd B(2 * _nterms);
875 double monomials[_nterms];
876 for (
const auto & a_match : starMatchList) {
877 Point tmp = shiftToCenter.apply(a_match.point1);
878 FatPoint point1(tmp, a_match.point1.vx, a_match.point1.vy, a_match.point1.vxy);
879 FatPoint
const &point2 = a_match.point2;
880 double wxx, wyy, wxy;
882 computeMonomials(point1.x, point1.y, monomials);
885 double vxx = (tr1.vx + point2.vx);
886 double vyy = (tr1.vy + point2.vy);
887 double vxy = (tr1.vxy + point2.vxy);
888 double det = vxx * vyy - vxy * vxy;
895 apply(point1.x, point1.y, tr1.x, tr1.y);
897 double resx = point2.x - tr1.x;
898 double resy = point2.y - tr1.y;
899 sumr2 += wxx * sq(resx) + wyy * sq(resy) + 2 * wxy * resx * resy;
901 double bxcoeff = wxx * resx + wxy * resy;
902 double bycoeff = wyy * resy + wxy * resx;
905 A(i, j) += wxx * monomials[i] * monomials[j];
906 A(i + _nterms, j + _nterms) += wyy * monomials[i] * monomials[j];
907 A(j, i + _nterms) = A(i, j + _nterms) += wxy * monomials[i] * monomials[j];
909 B(j) += bxcoeff * monomials[j];
910 B(j + _nterms) += bycoeff * monomials[j];
913 Eigen::LDLT<Eigen::MatrixXd, Eigen::Lower> factor(A);
915 if (factor.info() != Eigen::Success) {
916 LOGL_ERROR(_log,
"AstrometryTransformPolynomial::fit could not factorize");
920 Eigen::VectorXd sol = factor.solve(B);
921 for (
std::size_t k = 0; k < 2 * _nterms; ++k) _coeffs[k] += sol(k);
922 if (starMatchList.size() == _nterms)
return 0;
923 return (sumr2 - B.dot(sol));
927 if (starMatchList.
size() < _nterms) {
928 LOGLS_FATAL(_log,
"AstrometryTransformPolynomial::fit trying to fit a polynomial transform of order "
929 << _order <<
" with only " << starMatchList.
size() <<
" matches.");
935 computeFit(starMatchList, conditionner,
false);
936 computeFit(starMatchList, conditionner,
true);
937 double chi2 = computeFit(starMatchList, conditionner,
true);
939 (*this) = (*this) * conditionner;
940 if (starMatchList.
size() == _nterms)
return 0;
947 return std::make_unique<AstrometryTransformLinear>((*
this) * (
right));
949 return std::make_unique<AstrometryTransformPolynomial>((*
this) * (
right));
983 assert(powX + powY <=
order);
984 return coeffs.
at((powX + powY) * (powX + powY + 1) / 2 + powY);
988 assert(powX + powY <=
order);
989 return coeffs.
at((powX + powY) * (powX + powY + 1) / 2 + powY);
995static void operator+=(PolyXY &
left,
const PolyXY &
right) {
997 assert(
left.getOrder() >= rdeg);
999 for (
std::size_t j = 0; j <= rdeg - i; ++j)
left.getCoefficient(i, j) +=
right.getCoefficient(i, j);
1003static PolyXY operator*(
const long double &a,
const PolyXY &polyXY) {
1013static PolyXY product(
const PolyXY &p1,
const PolyXY &p2) {
1016 PolyXY
result(deg1 + deg2);
1021 result.getCoefficient(i1 + i2, j1 + j2) +=
1022 p1.getCoefficient(i1, j1) * p2.getCoefficient(i2, j2);
1030 powers[0].getCoefficient(0, 0) = 1L;
1035static PolyXY composition(
const PolyXY &polyXY,
const PolyXY &polyX,
const PolyXY &polyY) {
1037 PolyXY
result(pdeg *
max(polyX.getOrder(), polyY.getOrder()));
1040 computePowers(polyX, pdeg, pXPowers);
1041 computePowers(polyY, pdeg, pYPowers);
1044 result += polyXY.getCoefficient(px,
py) * product(pXPowers.
at(px), pYPowers.
at(
py));
1061 PolyXY rx(composition(plx, prx, pry));
1062 PolyXY ry(composition(ply, prx, pry));
1076 if (_order >=
right._order) {
1085 return (
right + (*
this));
1092 for (
std::size_t j = 0; j <= res._order - i; ++j) {
1101 return std::make_shared<ast::PolyMap>(toAstPolyMapCoefficients(), inverse->toAstPolyMapCoefficients());
1105 s <<
" AstrometryTransformPolynomial 1" <<
endl;
1106 s <<
"order " << _order <<
endl;
1107 int oldprec = s.precision();
1109 for (
std::size_t k = 0; k < 2 * _nterms; ++k) s << _coeffs[k] <<
' ';
1119 " AstrometryTransformPolynomial::read : format is not 1 ");
1122 s >>
order >> _order;
1123 if (
order !=
"order")
1125 " AstrometryTransformPolynomial::read : expecting \"order\" and found " +
order);
1127 for (
std::size_t k = 0; k < 2 * _nterms; ++k) s >> _coeffs[k];
1130ndarray::Array<double, 2, 2> AstrometryTransformPolynomial::toAstPolyMapCoefficients()
const {
1132 ndarray::Array<double, 2, 2>
result = ndarray::allocate(ndarray::makeVector(nCoeffs,
std::size_t(4)));
1134 ndarray::Size k = 0;
1135 for (
std::size_t iCoord = 0; iCoord < 2; ++iCoord) {
1139 result[k][1] = iCoord + 1;
1150 Frame const &domain,
1151 double const precision,
1155 double xStart = domain.
xMin;
1156 double yStart = domain.
yMin;
1157 double xStep = domain.
getWidth() / (nSteps - 1);
1158 double yStep = domain.
getHeight() / (nSteps - 1);
1161 Point in(xStart + i * xStep, yStart + j * yStep);
1174 auto success =
poly->fit(sm);
1175 if (success == -1) {
1177 errMsg <<
"Cannot fit a polynomial of order " <<
order <<
" with " << nSteps <<
"^2 points";
1182 for (
auto const &i : sm) chi2 += i.point2.computeDist2(
poly->apply((i.point1)));
1183 LOGLS_TRACE(_log,
"inversePoly order " <<
order <<
": " << chi2 <<
" / " << npairs <<
" = "
1184 << chi2 / npairs <<
" < " << precision * precision);
1186 if (chi2 / npairs < precision * precision)
break;
1189 if (chi2 > oldChi2) {
1190 LOGLS_WARN(_log,
"inversePolyTransform: chi2 increases ("
1191 << chi2 <<
" > " << oldChi2 <<
"); ending fit with order: " <<
order);
1192 LOGLS_WARN(_log,
"inversePolyTransform: requested precision not reached: "
1193 << chi2 <<
" / " << npairs <<
" = " << chi2 / npairs <<
" < "
1194 << precision * precision);
1201 oldPoly = dynamic_pointer_cast<AstrometryTransformPolynomial>(
1205 if (
order > maxOrder)
1206 LOGLS_WARN(_log,
"inversePolyTransform: Reached max order without reaching requested precision: "
1207 << chi2 <<
" / " << npairs <<
" = " << chi2 / npairs <<
" < "
1208 << precision * precision);
1218 const double A12,
const double A21,
const double A22)
1232 "Trying to build a AstrometryTransformLinear from a higher order transform. Aborting. ");
1252 const double)
const {
1276 "AstrometryTransformLinear::invert singular transformation: transform contents will be "
1277 "dumped to stderr.");
1290 const Frame &)
const {
1297 stream <<
"Linear AstrometryTransform:" <<
std::endl;
1312 LOGLS_FATAL(_log,
"AstrometryTransformLinearShift::fit trying to fit a linear transform with only "
1313 << npairs <<
" matches.");
1319 Eigen::VectorXd B(2);
1321 Eigen::MatrixXd A(2, 2);
1324 for (
auto const &it : starMatchList) {
1325 FatPoint const &point1 = it.point1;
1326 FatPoint const &point2 = it.point2;
1327 double deltax = point2.
x - point1.
x;
1328 double deltay = point2.
y - point1.
y;
1329 double vxx = point1.
vx + point2.
vx;
1330 double vyy = point1.
vy + point2.
vy;
1331 double vxy = point1.
vxy + point2.
vxy;
1332 double det = vxx * vyy - vxy * vxy;
1333 double wxx = vyy /
det;
1334 double wyy = vxx /
det;
1335 double wxy = -vxy /
det;
1336 B(0) += deltax * wxx + wxy * deltay;
1337 B(1) += deltay * wyy + wxy * deltax;
1341 sumr2 += deltax * deltax * wxx + deltay * deltay * wyy + 2. * wxy * deltax * deltay;
1343 double det = A(0, 0) * A(1, 1) - A(0, 1) * A(1, 0);
1344 if (
det <= 0)
return -1;
1345 double tmp = A(0, 0);
1346 A(0, 0) = A(1, 1) /
det;
1347 A(1, 1) = tmp /
det;
1348 A(0, 1) = A(1, 0) = -A(0, 1) /
det;
1349 Eigen::VectorXd sol = A * B;
1351 return (sumr2 - sol.dot(B));
1355 const double scaleFactor) {
1356 double c = scaleFactor *
std::cos(angleRad);
1357 double s = scaleFactor *
std::sin(angleRad);
1363 Point a_point(0., 0.);
1364 if (center) a_point = *center;
1368 dx() = a_point.
x -
Dx();
1369 dy() = a_point.
y -
dy();
1374static double rad2deg(
double rad) {
return rad * 180. /
M_PI; }
1398 ra0 = deg2rad(tangentPoint.
x);
1399 dec0 = deg2rad(tangentPoint.
y);
1403 if (corrections)
corr = std::make_unique<AstrometryTransformPolynomial>(*corrections);
1422 if (original.
corr)
corr = std::make_unique<AstrometryTransformPolynomial>(*original.
corr);
1437 LOGL_WARN(_log,
"No sidereal coordinates at pole!");
1446 if (rat < 0.0) rat += (2. *
M_PI);
1448 xOut = rad2deg(rat);
1449 yOut = rad2deg(dect);
1469 return Point(inverse.
Dx(), inverse.
Dy());
1475 : _skyWcs(
std::
move(skyWcs)) {}
1478 auto const outCoord = _skyWcs->pixelToSky(
geom::Point2D(xIn, yIn));
1479 xOut = outCoord[0].asDegrees();
1480 yOut = outCoord[1].asDegrees();
1484 out <<
"AstrometryTransformSkyWcs(" << *_skyWcs <<
")";
1492 return std::make_unique<AstrometryTransformSkyWcs>(
getSkyWcs());
1499 :
BaseTanWcs(pixToTan, tangentPoint, corrections) {}
1506 if (
right.getOrder() == 1) {
1507 return std::make_unique<TanPixelToRaDec>((*
this) * (
right));
1520 if (
corr !=
nullptr) {
1521 LOGL_WARN(_log,
"You are inverting a TanPixelToRaDec with corrections.");
1522 LOGL_WARN(_log,
"The inverse you get ignores the corrections!");
1533 const Frame ®ion)
const {
1549 double &yTangentPlane)
const {
1553 double xtmp = xTangentPlane;
1554 double ytmp = yTangentPlane;
1555 corr->apply(xtmp, ytmp, xTangentPlane, yTangentPlane);
1567 stream <<
" tangent point " << tp.
x <<
' ' << tp.
y <<
endl;
1570 if (
corr) stream <<
"PV correction: " <<
endl << *
corr;
1583 "TanPixelToRaDec::fit is NOT implemented (although it is doable)) ");
1591 :
BaseTanWcs(pixToTan, tangentPoint, corrections) {}
1607 const Frame ®ion)
1620 double &yTangentPlane)
const {
1624 corr->
apply(xPixel, yPixel, xtmp, ytmp);
1638 stream <<
" tangent point " << tp.
x <<
' ' << tp.
y <<
endl;
1641 if (
corr) stream <<
"PV correction: " <<
endl << *
corr;
1654 "TanSipPixelToRaDec::fit is NOT implemented (although it is doable)) ");
1661 : linTan2Pix(
std::
move(tan2Pix)) {
1668 ra0 = deg2rad(tangentPoint.
x);
1669 dec0 = deg2rad(tangentPoint.
y);
1701 double ra = deg2rad(in.x);
1702 double dec = deg2rad(in.y);
1703 if (ra - ra0 >
M_PI) ra -= (2. *
M_PI);
1704 if (ra - ra0 < -
M_PI) ra += (2. *
M_PI);
1712 double l = sinda * coss;
1713 double m = sins * sin0 + coss * cos0 * cosda;
1715 m = (sins * cos0 - coss * sin0 * cosda) /
m;
1719 sq(sin0) - sq(coss) + sq(coss * cos0) * (1 + sq(cosda)) + 2 * sins * sin0 * coss * cos0 * cosda;
1720 double a11 = coss * (cosda * sins * sin0 + coss * cos0) / deno;
1721 double a12 = -sinda * sin0 / deno;
1722 double a21 = coss * sinda * sins / deno;
1723 double a22 = cosda / deno;
1726 tmp.
vx = a11 * (a11 * in.vx + 2 * a12 * in.vxy) + a12 * a12 * in.vy;
1727 tmp.
vy = a21 * a21 * in.vx + a22 * a22 * in.vy + 2. * a21 * a22 * in.vxy;
1728 tmp.
vxy = a21 * a11 * in.vx + a22 * a12 * in.vy + (a21 * a12 + a11 * a22) * in.vxy;
1738 double ra = deg2rad(xIn);
1739 double dec = deg2rad(yIn);
1740 if (ra - ra0 >
M_PI) ra -= (2. *
M_PI);
1741 if (ra - ra0 < -
M_PI) ra += (2. *
M_PI);
1746 double l =
std::sin(ra - ra0) * coss;
1747 double m = sins * sin0 + coss * cos0 *
std::cos(ra - ra0);
1749 m = (sins * cos0 - coss * sin0 *
std::cos(ra - ra0)) /
m;
1753 linTan2Pix.
apply(l,
m, xOut, yOut);
1762 stream <<
"tan2pix " << linTan2Pix <<
std::endl;
1763 stream <<
"tangent point " << tp.
x <<
' ' << tp.
y <<
endl;
1782 "TanRaDecToPixel::fit is NOT implemented (although it is doable)) ");
1789 : _userFun(userFun), _userData(userData) {}
1792 _userFun(xIn, yIn, xOut, yOut, _userData);
1796 stream <<
"UserTransform with user function @ " << _userFun <<
"and userData@ " << _userData <<
endl;
1801 "UserTransform::fit is NOT implemented (and will never be)) ");
1815 " astrometryTransformRead : cannot open " + fileName);
1831 "astrometryTransformRead : could not find a AstrometryTransformtype");
1832 if (type ==
"AstrometryTransformIdentity") {
1836 }
else if (type ==
"AstrometryTransformPolynomial") {
1842 " astrometryTransformRead : No reader for AstrometryTransform type " + type);
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
LSST DM logging module built on log4cxx.
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
#define LOGL_WARN(logger, message...)
Log a warn-level message using a varargs/printf style interface.
#define LOGLS_FATAL(logger, message)
Log a fatal-level message using an iostream-based interface.
#define LOG_GET(logger)
Returns a Log object associated with logger.
#define LOGL_ERROR(logger, message...)
Log a error-level message using a varargs/printf style interface.
#define LOGLS_TRACE(logger, message)
Log a trace-level message using an iostream-based interface.
#define LOGL_FATAL(logger, message...)
Log a fatal-level message using a varargs/printf style interface.
table::PointKey< double > crpix
std::unique_ptr< AstrometryTransformPolynomial > corr
virtual void pixToTangentPlane(double xPixel, double yPixel, double &xTangentPlane, double &yTangentPlane) const =0
Transform from pixels to tangent plane (degrees)
Point getCrPix() const
Get the pixel origin of the WCS (CRPIX in FITS WCS terminology, but zero-based)
BaseTanWcs & operator=(const BaseTanWcs &original)
BaseTanWcs(AstrometryTransformLinear const &pixToTan, Point const &tangentPoint, const AstrometryTransformPolynomial *corrections=nullptr)
AstrometryTransformLinear getLinPart() const
The Linear part (corresponding to CD's and CRPIX's)
Point getTangentPoint() const
Get the sky origin (CRVAL in FITS WCS terminology) in degrees.
void apply(double xIn, double yIn, double &xOut, double &yOut) const
Transform pixels to ICRS RA, Dec in degrees.
AstrometryTransformLinear linPixelToTan
void setCorrections(std::unique_ptr< AstrometryTransformPolynomial > corrections)
Assign the correction polynomial (what it means is left to derived classes)
A Point with uncertainties.
rectangle with sides parallel to axes.
Point getCenter() const
Center of the frame.
double getHeight() const
size along y axis
double xMin
coordinate of boundary.
double getWidth() const
size along x axis
PolyXY(AstrometryTransformPolynomial const &transform, std::size_t whichCoord)
long double getCoefficient(std::size_t powX, std::size_t powY) const
std::size_t getOrder() const
long double & getCoefficient(std::size_t powX, std::size_t powY)
A hanger for star associations.
The transformation that handles pixels to sideral transformations (Gnomonic, possibly with polynomial...
TanPixelToRaDec operator*(AstrometryTransformLinear const &right) const
composition with AstrometryTransformLinear
std::unique_ptr< AstrometryTransform > clone() const
returns a copy (allocated by new) of the transformation.
TanRaDecToPixel inverted() const
approximate inverse : it ignores corrections;
double fit(StarMatchList const &starMatchList)
Not implemented yet, because we do it otherwise.
virtual void pixToTangentPlane(double xPixel, double yPixel, double &xTangentPlane, double &yTangentPlane) const
transforms from pixel space to tangent plane (degrees)
void print(std::ostream &out) const
prints the transform coefficients to stream.
std::unique_ptr< AstrometryTransform > roughInverse(const Frame ®ion) const
Overload the "generic routine" (available for all AstrometryTransform types.
AstrometryTransformPolynomial getPixelToTangentPlane() const
the transformation from pixels to tangent plane (degrees)
std::unique_ptr< AstrometryTransform > inverseTransform(double precision, const Frame ®ion) const
Inverse transform: returns a TanRaDecToPixel if there are no corrections, or the iterative solver if ...
std::unique_ptr< AstrometryTransform > composeAndReduce(AstrometryTransformLinear const &right) const
Return a reduced composition of newTransform = this(right()), or nullptr if it cannot be reduced.
This one is the Tangent Plane (called gnomonic) projection (from celestial sphere to tangent plane)
void transformPosAndErrors(const FatPoint &in, FatPoint &out) const
transform with analytical derivatives
Point getTangentPoint() const
tangent point coordinates (degrees)
double fit(StarMatchList const &starMatchList)
fits a transform to a std::list of Point pairs (p1,p2, the Point fields in StarMatch).
void setTangentPoint(Point const &tangentPoint)
Resets the projection (or tangent) point.
std::unique_ptr< AstrometryTransform > inverseTransform(double precision, const Frame ®ion) const
Inverse transform: returns a TanPixelToRaDec.
TanPixelToRaDec inverted() const
exact typed inverse:
void apply(double xIn, double yIn, double &xOut, double &yOut) const
std::unique_ptr< AstrometryTransform > clone() const
returns a copy (allocated by new) of the transformation.
AstrometryTransformLinear getLinPart() const
The Linear part (corresponding to CD's and CRPIX's)
std::unique_ptr< AstrometryTransform > roughInverse(const Frame ®ion) const
Overload the "generic routine" (available for all AstrometryTransform types.
void print(std::ostream &out) const
prints the transform coefficients to stream.
std::unique_ptr< AstrometryTransform > inverseTransform(double precision, const Frame ®ion) const
Inverse transform: returns a TanRaDecToPixel if there are no corrections, or the iterative solver if ...
void print(std::ostream &out) const
prints the transform coefficients to stream.
double fit(StarMatchList const &starMatchList)
Not implemented yet, because we do it otherwise.
virtual void pixToTangentPlane(double xPixel, double yPixel, double &xTangentPlane, double &yTangentPlane) const
transforms from pixel space to tangent plane (degrees)
std::unique_ptr< AstrometryTransform > clone() const
returns a copy (allocated by new) of the transformation.
AstrometryTransformPolynomial getPixelToTangentPlane() const
the transformation from pixels to tangent plane (degrees)
virtual char const * what(void) const noexcept
Return a character string summarizing this exception.
Reports invalid arguments.
Reports errors in the logical structure of the program.
Reports attempts to access elements using an invalid key.
Reports errors that are due to events beyond the control of the program.
T emplace_back(T... args)
Low-level polynomials (including special polynomials) in C++.
AstrometryTransformLinear normalizeCoordinatesTransform(const Frame &frame)
Returns the transformation that maps the input frame along both axes to [-1,1].
std::shared_ptr< AstrometryTransformPolynomial > inversePolyTransform(AstrometryTransform const &forward, Frame const &domain, double precision, std::size_t maxOrder=9, std::size_t nSteps=50)
Approximate the inverse by a polynomial, to some precision.
bool isIntegerShift(const AstrometryTransform *transform)
Shorthand test to tell if a transform is a simple integer shift.
std::unique_ptr< AstrometryTransform > compose(AstrometryTransform const &left, AstrometryTransform const &right)
Returns a pointer to a composition of transforms, representing left(right()).
std::unique_ptr< AstrometryTransform > astrometryTransformRead(const std::string &fileName)
The virtual constructor from a file.
void(const double, const double, double &, double &, const void *) AstrometryTransformFun
signature of the user-provided routine that actually does the coordinate transform for UserTransform.
basic_ostream< char, traits > & operator<<(basic_ostream< char, traits > &, const char *)
T setprecision(T... args)
table::Key< table::Array< int > > degree