39 #include "Eigen/Geometry"
42 #include "boost/algorithm/string.hpp"
43 #include "boost/tuple/tuple.hpp"
44 #include "boost/format.hpp"
49 namespace afwCoord = lsst::afw::coord;
50 namespace ex = lsst::pex::exceptions;
51 namespace afwGeom = lsst::afw::geom;
52 namespace dafBase = lsst::daf::base;
56 typedef std::map<std::string, afwCoord::CoordSystem> CoordSystemMap;
58 CoordSystemMap
const getCoordSystemMap() {
76 double const cosDelta1,
77 double const cosDelta2
80 double const havDDelta = std::sin(dDelta/2.0) * std::sin(dDelta/2.0);
81 double const havDAlpha = std::sin(dAlpha/2.0) * std::sin(dAlpha/2.0);
82 double const havD = havDDelta + cosDelta1 * cosDelta2 * havDAlpha;
83 double const sinDHalf = std::sqrt(havD);
88 double const epochTolerance = 1.0e-12;
91 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord> commonFk5(
afwCoord::Coord const& c1,
107 return std::make_pair(fk51, fk52);
117 static CoordSystemMap idmap = getCoordSystemMap();
118 if (idmap.find(system) != idmap.end()) {
119 return idmap[system];
121 throw LSST_EXCEPT(ex::InvalidParameterError,
"System " + system +
" not defined.");
128 double const NaN = std::numeric_limits<double>::quiet_NaN();
129 double const JD2000 = 2451544.50;
149 Dms(
int const d,
int const m,
double const s,
bool const isSouth=
false) {
150 sign = (d < 0 || isSouth) ? -1 : 1;
158 double const absVal = std::fabs(deg0);
159 sign = (deg0 >= 0) ? 1 : -1;
160 deg =
static_cast<int>(std::floor(absVal));
161 min =
static_cast<int>(std::floor((absVal - deg)*60.0));
162 sec = ((absVal - deg)*60.0 -
min)*60.0;
196 double const T = (jd - 2451545.0)/36525.0;
197 return (280.46061837 + 360.98564736629*(jd - 2451545.0) + 0.000387933*T*T - (T*T*T/38710000.0)) *
afwGeom::degrees;
204 double const atPoleEpsilon = 0.0;
207 if (fabs(p3d.getX()) <= atPoleEpsilon && fabs(p3d.getY()) <= atPoleEpsilon) {
217 if ( fabs(p3d.getX()) <= atPoleEpsilon && fabs(p3d.getY()) <= atPoleEpsilon) {
225 std::pair<afwGeom::Angle, afwGeom::Angle> lonLat;
228 double const inorm = 1.0/p3d.
asEigen().norm();
229 double const x = inorm*p3d.getX();
230 double const y = inorm*p3d.getY();
231 double const z = inorm*p3d.getZ();
232 if (fabs(x) <= atPoleEpsilon && fabs(y) <= atPoleEpsilon) {
241 if (fabs(p3d.getX()) <= atPoleEpsilon && fabs(p3d.getY()) <= atPoleEpsilon) {
265 if ( (60.00 - dms.sec) < 0.005 ) {
271 if (dms.deg == 360) {
277 std::string fmt(
"%02d:%02d:%05.2f");
278 std::string s = (
boost::format(fmt) % dms.deg % dms.min % dms.sec).str();
307 std::string
const dms,
310 if (dms.find(
":") == std::string::npos) {
312 (
boost::format(
"String is not in xx:mm:ss format: %s") % dms).str());
314 std::vector<std::string> elements;
315 boost::split(elements, dms, boost::is_any_of(
":"));
316 if (elements.size() != 3) {
318 (
boost::format(
"Could not parse string as xx:mm:ss format: %s") % dms).str());
320 int const deg = abs(atoi(elements[0].c_str()));
321 int const min = atoi(elements[1].c_str());
322 double const sec = atof(elements[2].c_str());
325 if ( (elements[0].c_str())[0] ==
'-' ) {
335 std::string
const hms
344 std::string
const dms
356 double const T = (epoch - 2000.0)/100.0;
357 return (23.0 + 26.0/60.0 + (21.448 - 46.82*T - 0.0006*T*T - 0.0018*T*T*T)/3600.0) *
afwGeom::degrees;
377 _longitude(NaN), _latitude(NaN),
_epoch(epoch) {
393 _longitude(0. * afwGeom::
radians),
394 _latitude(0. * afwGeom::
radians),
397 std::pair<afwGeom::Angle, afwGeom::Angle> lonLat = pointToLonLat(p3d, defaultLongitude, normalize);
412 _longitude(ra), _latitude(dec),
_epoch(epoch) {
422 std::string
const ra,
423 std::string
const dec,
449 (
boost::format(
"Latitude coord must be: -PI/2 <= lat <= PI/2 (%f).") %
464 _longitude = longitude;
465 _latitude = latitude;
479 return afwGeom::Point2D(getLongitude().asHours(), getLatitude().asDegrees());
481 return afwGeom::Point2D(getLongitude().asAngularUnits(unit), getLatitude().asAngularUnits(unit));
491 double lng = getLongitude();
492 double lat = getLatitude();
493 double const x = std::cos(lng) * std::cos(lat);
494 double const y = std::sin(lng) * std::cos(lat);
495 double const z = std::sin(lat);
508 Coord const &poleFrom
510 double const alphaGP = poleFrom[0];
511 double const deltaGP = poleFrom[1];
512 double const lCP = poleTo[0];
514 double const alpha = getLongitude();
515 double const delta = getLatitude();
517 afwGeom::Angle const l = (lCP - std::atan2(std::sin(alpha - alphaGP),
518 std::tan(delta)*std::cos(deltaGP) - std::cos(alpha - alphaGP)*std::sin(deltaGP))) *
afwGeom::radians;
519 afwGeom::Angle const b = std::asin( (std::sin(deltaGP)*std::sin(delta) + std::cos(deltaGP)*std::cos(delta)*std::cos(alpha - alphaGP))) *
afwGeom::radians;
533 double const c = std::cos(theta);
534 double const mc = 1.0 - c;
535 double const s = std::sin(theta);
540 double const ux = u[0];
541 double const uy = u[1];
542 double const uz = u[2];
546 xprime[0] = (ux*ux + (1.0 - ux*ux)*c)*x[0] + (ux*uy*mc - uz*s)*x[1] + (ux*uz*mc + uy*s)*x[2];
547 xprime[1] = (uy*uy + (1.0 - uy*uy)*c)*x[1] + (uy*uz*mc - ux*s)*x[2] + (ux*uy*mc + uz*s)*x[0];
548 xprime[2] = (uz*uz + (1.0 - uz*uz)*c)*x[2] + (uz*ux*mc - uy*s)*x[0] + (uy*uz*mc + ux*s)*x[1];
551 std::pair<afwGeom::Angle, afwGeom::Angle> lonLat = pointToLonLat(xprime);
552 _longitude = lonLat.first;
553 _latitude = lonLat.second;
578 Eigen::Vector3d r = getVector().asEigen();
597 u << -std::sin(getLongitude()), std::cos(getLongitude()), 0.0;
598 Eigen::Vector3d
w = r.cross(u);
599 Eigen::Vector3d v = arcLen * std::cos(phi)*u + arcLen * std::sin(phi)*
w;
602 Eigen::Vector3d axisVector = r.cross(v);
603 axisVector.normalize();
606 rotate(axisCoord, arcLen);
615 Eigen::Vector3d r2 = getVector().asEigen();
617 u2 << -std::sin(getLongitude()), std::cos(getLongitude()), 0.0;
618 Eigen::Vector3d w2 = r2.cross(u2);
623 v2Coord.
rotate(axisCoord, arcLen);
671 "Cannot make Topocentric with convert() (must also specify Observatory).\n"
672 "Instantiate TopocentricCoord() directly.");
676 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC allowed.");
694 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
700 return haversine(alpha1 - alpha2, delta1 - delta2, std::cos(delta1), std::cos(delta2));
711 std::pair<afwGeom::Angle, afwGeom::Angle>
717 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
726 double const cosDelta1 = std::cos(delta1);
727 double const cosDelta2 = std::cos(delta2);
729 afwGeom::Angle separation = haversine(dAlpha, dDelta, cosDelta1, cosDelta2);
732 double const y = std::sin(dAlpha)*cosDelta2;
733 double const x = cosDelta1*std::sin(delta2) - std::sin(delta1)*cosDelta2*std::cos(dAlpha);
736 return std::make_pair(bearing, separation);
746 std::pair<afwGeom::Angle, afwGeom::Angle>
752 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
759 double const sinDelta1 = std::sin(delta1);
760 double const cosDelta1 = std::cos(delta1);
761 double const sinDelta2 = std::sin(delta2);
762 double const cosDelta2 = std::cos(delta2);
763 double const cosAlphaDiff = std::cos(alpha2 - alpha1);
764 double const sinAlphaDiff = std::sin(alpha2 - alpha1);
766 double const div = cosDelta1 * cosAlphaDiff * cosDelta2 + sinDelta1 * sinDelta2;
767 double const xi = cosDelta1 * sinAlphaDiff / div;
768 double const eta = (cosDelta1 * cosAlphaDiff * sinDelta2 - sinDelta1 * cosDelta2) / div;
778 return Fk5Coord(getLongitude(), getLatitude(), getEpoch()).
precess(epoch);
784 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
792 return this->toFk5().
toIcrs();
839 return Fk5Coord(getLongitude(), getLatitude(), getEpoch()).
precess(epoch);
845 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
855 if ( fabs(getEpoch() - 2000.0) > epochTolerance ) {
859 return IcrsCoord(getLongitude(), getLatitude());
871 if ( fabs(getEpoch() - 2000.0) > epochTolerance ) {
889 Coord c = transform(equPoleInEcliptic, eclPoleInEquatorial);
896 return this->toEcliptic(getEpoch());
925 double const sinh = std::sin(phi)* std::sin(delta) + std::cos(phi) * std::cos(delta) * std::cos(H);
929 double const tanAnumerator = std::sin(H);
930 double const tanAdenominator = (std::cos(H) * std::sin(phi) - std::tan(delta) * std::cos(phi));
951 if ( fabs(getEpoch() - epochTo) < epochTolerance) {
952 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
960 double const T = (jd0 - JD2000)/36525.0;
961 double const t = (jd - jd0)/36525.0;
962 double const tt = t*t;
963 double const ttt = tt*t;
965 afwGeom::Angle const xi = ((2306.2181 + 1.39656*T - 0.000139*T*T)*t +
967 afwGeom::Angle const z = ((2306.2181 + 1.39656*T - 0.000139*T*T)*t +
969 afwGeom::Angle const theta = ((2004.3109 - 0.85330*T - 0.000217*T*T)*t -
976 double const a = std::cos(delta0) * std::sin((alpha0 + xi));
977 double const b = std::cos(theta) * std::cos(delta0) * std::cos((alpha0 + xi)) - std::sin(theta) * std::sin(delta0);
978 double const c = std::sin(theta) * std::cos(delta0) * std::cos((alpha0 + xi)) + std::cos(theta) * std::sin(delta0);
983 return Fk5Coord(alpha, delta, epochTo);
1004 return Fk5Coord(getLongitude(), getLatitude(), 2000.0).
precess(epoch);
1010 return Fk5Coord(getLongitude(), getLatitude(), 2000.0);
1017 return IcrsCoord(getLongitude(), getLatitude());
1042 Coord c = transform(GalacticPoleInFk5(), Fk5PoleInGalactic());
1049 return this->toFk5(2000.0);
1078 return EclipticCoord(getLongitude(), getLatitude(), getEpoch());
1089 Coord const fk5PoleInEcliptic(ninety, ninety - eclPoleIncl, epoch);
1090 Coord c = transform(eclipticPoleInFk5, fk5PoleInEcliptic);
1097 return this->toFk5(getEpoch());
1107 double const epochTo
1141 double const tanHnum = std::sin(A);
1142 double const tanHdenom = std::cos(A)*std::sin(phi) + std::tan(h)*std::cos(phi);
1146 double const sinDelta = std::sin(phi)*std::sin(h) - std::cos(phi)*std::cos(h)*std::cos(A);
1149 return Fk5Coord(alpha, delta, epoch);
1155 return this->toFk5(getEpoch());
1169 (
boost::format(
"Expected observatory %s, saw %s") % _obs % obs).str());
1171 if (fabs(date.
get() - getEpoch()) > std::numeric_limits<double>::epsilon()) {
1173 (
boost::format(
"Expected date %g, saw %g") % getEpoch() % date.
get()).str());
1219 return boost::shared_ptr<Fk5Coord>(
new Fk5Coord(ra, dec, epoch));
1223 "ICRS has no epoch, use overloaded makeCoord with args (system, ra, dec).");
1227 "Galactic has no epoch, use overloaded makeCoord with (system, ra, dec).");
1230 return boost::shared_ptr<EclipticCoord>(
new EclipticCoord(ra, dec, epoch));
1234 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1235 "Instantiate TopocentricCoord() directly.");
1239 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, and TOPOCENTRIC allowed.");
1262 return boost::shared_ptr<Fk5Coord>(
new Fk5Coord(ra, dec, 2000.0));
1265 return boost::shared_ptr<IcrsCoord>(
new IcrsCoord(ra, dec));
1268 return boost::shared_ptr<GalacticCoord>(
new GalacticCoord(ra, dec));
1271 return boost::shared_ptr<EclipticCoord>(
new EclipticCoord(ra, dec, 2000.0));
1275 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1276 "Instantiate TopocentricCoord() directly.");
1280 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, and TOPOCENTRIC allowed.");
1302 Coord c(p3d, 2000.0, normalize, defaultLongitude);
1317 Coord c(p3d, 2000.0, normalize, defaultLongitude);
1364 std::string
const ra,
1365 std::string
const dec,
1377 std::string
const ra,
1378 std::string
const dec
1393 return boost::shared_ptr<Fk5Coord>(
new Fk5Coord());
1396 return boost::shared_ptr<IcrsCoord>(
new IcrsCoord());
1399 return boost::shared_ptr<GalacticCoord>(
new GalacticCoord());
1402 return boost::shared_ptr<EclipticCoord>(
new EclipticCoord());
1406 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1407 "Instantiate TopocentricCoord() directly.");
1411 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, allowed.");
lsst::afw::geom::Point2D getPosition(lsst::afw::geom::AngleUnit unit=lsst::afw::geom::degrees) const
Return our contents in a Point2D object.
virtual Fk5Coord toFk5() const
Convert ourself to Fk5: RA, Dec (use current epoch)
virtual void reset(lsst::afw::geom::Angle const longitude, lsst::afw::geom::Angle const latitude)
special reset() overload to make sure no epoch can be set
lsst::afw::geom::Angle Angle
Class for handling dates/times, including MJD, UTC, and TAI.
lsst::afw::coord::Coord Coord
A class to handle Galactic coordinates (inherits from Coord)
lsst::afw::geom::Angle _latitude
lsst::afw::geom::Angle hmsStringToAngle(std::string const hms)
Convert a hh:mm:ss string to Angle.
lsst::afw::geom::Angle angularSeparation(Coord const &c) const
compute the angular separation between two Coords
boost::shared_ptr< Coord > Ptr
std::pair< lsst::afw::geom::Angle, lsst::afw::geom::Angle > getOffsetFrom(Coord const &c) const
Compute the offset from a coordinate.
Store information about an observatory ... lat/long, elevation.
virtual GalacticCoord toGalactic() const
Convert ourself to Galactic: l, b.
lsst::afw::geom::Angle getLongitude() const
The main access method for the longitudinal coordinate.
virtual Fk5Coord toFk5(double const epoch) const
Convert ourself to Fk5: RA, Dec (precess to new epoch)
virtual void reset(lsst::afw::geom::Angle const longitude, lsst::afw::geom::Angle const latitude)
special reset() overload to make sure no epoch can be set
virtual GalacticCoord toGalactic() const
Convert ourself to Galactic: l, b.
lsst::afw::geom::Angle _longitude
Point< double, 2 > Point2D
virtual IcrsCoord toIcrs() const
Convert ourself to ICRS: RA, Dec (basically J2000)
double get(DateSystem system=MJD, Timescale scale=TAI) const
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &date) const
Convert ourself from Topocentric to Topocentric ... a no-op.
A class used to convert scalar POD types such as double to Angle.
Point< double, 3 > Point3D
virtual Fk5Coord toFk5() const
Convert ourself from galactic to Fk5 (no epoch specified)
A coordinate class intended to represent absolute positions.
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &obsDate) const
Convert ourself to Altitude/Azimuth: alt, az.
Fk5Coord precess(double const epochTo) const
Precess ourselves from whence we are to a new epoch.
Coord::Ptr convert(CoordSystem system) const
Convert to a specified Coord type.
virtual EclipticCoord toEcliptic(double const epoch) const
Convert ourself from Ecliptic to Ecliptic ... a no-op (but precess to new epoch)
A class to handle topocentric (AltAz) coordinates (inherits from Coord)
void rotate(Coord const &axis, lsst::afw::geom::Angle const theta)
Rotate our current coords about a pole.
Include files required for standard LSST Exception handling.
lsst::afw::geom::Angle getLongitude() const
The main access method for the longitudinal coordinate.
lsst::afw::coord::IcrsCoord IcrsCoord
std::pair< lsst::afw::geom::Angle, lsst::afw::geom::Angle > getTangentPlaneOffset(Coord const &c) const
Get the offset on the tangent plane.
AngleUnit const radians
constant with units of radians
lsst::afw::geom::Point3D getVector() const
Return our contents in a position vector.
Coord::Ptr makeCoord(CoordSystem const system, lsst::afw::geom::Angle const ra, lsst::afw::geom::Angle const dec, double const epoch)
Factory function to create a Coord of arbitrary type with decimal RA,Dec.
lsst::afw::geom::Angle getLatitude() const
The main access method for the longitudinal coordinate.
std::pair< double, double > rotate(double x, double y, double angle)
virtual TopocentricCoord toTopocentric() const
Convert ourself from Topocentric to Topocentric with no observatory or date arguments.
virtual Fk5Coord toFk5() const
Convert outself from Topocentric to Fk5 (use current epoch)
double asAngularUnits(AngleUnit const &units) const
virtual Fk5Coord toFk5() const
Convert ourself to Fk5 (ie. a no-op): RA, Dec (keep current epoch)
virtual IcrsCoord toIcrs() const
Icrs converter for IcrsCoord. (ie. a no-op)
virtual Fk5Coord toFk5() const
Convert ourself from Ecliptic to Fk5 (use current epoch)
std::string angleToDmsString(lsst::afw::geom::Angle const deg)
a Function to convert a coordinate in decimal degrees to a string with form dd:mm:ss ...
lsst::afw::geom::Angle offset(lsst::afw::geom::Angle const phi, lsst::afw::geom::Angle const arcLen)
offset our current coords along a great circle defined by an angle wrt a declination parallel ...
std::string angleToHmsString(lsst::afw::geom::Angle const deg)
a function to convert decimal degrees to a string with form hh:mm:ss.s
Interface for DateTime class.
virtual EclipticCoord toEcliptic() const
Convert ourself from Ecliptic to Ecliptic ... a no-op (use the current epoch)
A class to handle Fk5 coordinates (inherits from Coord)
void _verifyValues() const
Make sure the values we've got are in the range 0 <= x < 2PI.
#define LSST_EXCEPT(type,...)
A class to handle Ecliptic coordinates (inherits from Coord)
EclipticCoord precess(double const epochTo) const
precess to new epoch
virtual void reset(lsst::afw::geom::Angle const longitude, lsst::afw::geom::Angle const latitude)
EigenVector const & asEigen() const
Return a fixed-size Eigen representation of the coordinate object.
Coord()
Default constructor for the Coord base class.
virtual Fk5Coord toFk5() const
Fk5 converter for IcrsCoord. (no epoch specified)
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &obsDate) const
Convert ourself to Altitude/Azimuth: alt, az.
lsst::afw::geom::Angle getDec() const
afw::table::Key< double > b
CoordSystem makeCoordEnum(std::string const system)
A utility function to get the enum value of a coordinate system from a string name.
virtual EclipticCoord toEcliptic() const
Convert ourself to Ecliptic: lambda, beta (use existing epoch)
virtual EclipticCoord toEcliptic() const
Convert ourself to Ecliptic: lambda, beta (use current epoch)
virtual IcrsCoord toIcrs() const
Convert ourself to ICRS: RA, Dec (basically J2000)
lsst::afw::geom::Angle getLatitude() const
The main access method for the latitudinal coordinate.
lsst::afw::geom::Angle getRa() const
A class to handle Icrs coordinates (inherits from Coord)
lsst::afw::geom::Angle dmsStringToAngle(std::string const dms)
Convert a dd:mm:ss string to Angle.
virtual GalacticCoord toGalactic() const
Convert ourself from Galactic to Galactic ... a no-op.
lsst::afw::geom::Angle eclipticPoleInclination(double const epoch)
get the inclination of the ecliptic pole (obliquity) at epoch
Coord transform(Coord const &poleFrom, Coord const &poleTo) const
Tranform our current coords to another spherical polar system.
AngleUnit const arcseconds
Functions to handle coordinates.
std::ostream & operator<<(std::ostream &os, Stopwatch const &watch)