40 #include "Eigen/Geometry"
43 #include "boost/algorithm/string.hpp"
44 #include "boost/tuple/tuple.hpp"
45 #include "boost/format.hpp"
50 namespace afwCoord = lsst::afw::coord;
51 namespace ex = lsst::pex::exceptions;
52 namespace afwGeom = lsst::afw::geom;
53 namespace dafBase = lsst::daf::base;
57 typedef std::map<std::string, afwCoord::CoordSystem> CoordSystemMap;
59 CoordSystemMap
const getCoordSystemMap() {
77 double const cosDelta1,
78 double const cosDelta2
81 double const havDDelta = std::sin(dDelta/2.0) * std::sin(dDelta/2.0);
82 double const havDAlpha = std::sin(dAlpha/2.0) * std::sin(dAlpha/2.0);
83 double const havD = havDDelta + cosDelta1 * cosDelta2 * havDAlpha;
84 double const sinDHalf = std::sqrt(havD);
89 double const epochTolerance = 1.0e-12;
92 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord> commonFk5(
afwCoord::Coord const& c1,
108 return std::make_pair(fk51, fk52);
118 static CoordSystemMap idmap = getCoordSystemMap();
119 if (idmap.find(system) != idmap.end()) {
120 return idmap[system];
122 throw LSST_EXCEPT(ex::InvalidParameterError,
"System " + system +
" not defined.");
129 double const NaN = std::numeric_limits<double>::quiet_NaN();
130 double const JD2000 = 2451544.50;
150 Dms(
int const d,
int const m,
double const s,
bool const isSouth=
false) {
151 sign = (d < 0 || isSouth) ? -1 : 1;
159 double const absVal = std::fabs(deg0);
160 sign = (deg0 >= 0) ? 1 : -1;
162 min =
static_cast<int>(
std::floor((absVal - deg)*60.0));
163 sec = ((absVal - deg)*60.0 - min)*60.0;
197 double const T = (jd - 2451545.0)/36525.0;
198 return (280.46061837 + 360.98564736629*(jd - 2451545.0) + 0.000387933*T*T - (T*T*T/38710000.0)) *
afwGeom::degrees;
205 double const atPoleEpsilon = 0.0;
208 if (fabs(p3d.getX()) <= atPoleEpsilon && fabs(p3d.getY()) <= atPoleEpsilon) {
218 if ( fabs(p3d.getX()) <= atPoleEpsilon && fabs(p3d.getY()) <= atPoleEpsilon) {
226 std::pair<afwGeom::Angle, afwGeom::Angle> lonLat;
229 double const inorm = 1.0/p3d.
asEigen().norm();
230 double const x = inorm*p3d.getX();
231 double const y = inorm*p3d.getY();
232 double const z = inorm*p3d.getZ();
233 if (fabs(x) <= atPoleEpsilon && fabs(y) <= atPoleEpsilon) {
242 if (fabs(p3d.getX()) <= atPoleEpsilon && fabs(p3d.getY()) <= atPoleEpsilon) {
266 if ( (60.00 - dms.sec) < 0.005 ) {
272 if (dms.deg == 360) {
278 std::string fmt(
"%02d:%02d:%05.2f");
279 std::string s = (
boost::format(fmt) % dms.deg % dms.min % dms.sec).str();
308 std::string
const dms,
311 if (dms.find(
":") == std::string::npos) {
313 (
boost::format(
"String is not in xx:mm:ss format: %s") % dms).str());
315 std::vector<std::string> elements;
316 boost::split(elements, dms, boost::is_any_of(
":"));
317 if (elements.size() != 3) {
319 (
boost::format(
"Could not parse string as xx:mm:ss format: %s") % dms).str());
321 int const deg = abs(atoi(elements[0].c_str()));
322 int const min = atoi(elements[1].c_str());
323 double const sec = atof(elements[2].c_str());
326 if ( (elements[0].c_str())[0] ==
'-' ) {
336 std::string
const hms
345 std::string
const dms
357 double const T = (epoch - 2000.0)/100.0;
358 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;
378 _longitude(NaN), _latitude(NaN), _epoch(epoch) {
394 _longitude(0. * afwGeom::
radians),
395 _latitude(0. * afwGeom::
radians),
398 std::pair<afwGeom::Angle, afwGeom::Angle> lonLat = pointToLonLat(p3d, defaultLongitude, normalize);
413 _longitude(ra), _latitude(dec), _epoch(epoch) {
423 std::string
const ra,
424 std::string
const dec,
450 (
boost::format(
"Latitude coord must be: -PI/2 <= lat <= PI/2 (%f).") %
465 _longitude = longitude;
466 _latitude = latitude;
480 return afwGeom::Point2D(getLongitude().asHours(), getLatitude().asDegrees());
482 return afwGeom::Point2D(getLongitude().asAngularUnits(unit), getLatitude().asAngularUnits(unit));
492 double lng = getLongitude();
493 double lat = getLatitude();
494 double const x = std::cos(lng) * std::cos(lat);
495 double const y = std::sin(lng) * std::cos(lat);
496 double const z = std::sin(lat);
509 Coord const &poleFrom
511 double const alphaGP = poleFrom[0];
512 double const deltaGP = poleFrom[1];
513 double const lCP = poleTo[0];
515 double const alpha = getLongitude();
516 double const delta = getLatitude();
518 afwGeom::Angle const l = (lCP - std::atan2(std::sin(alpha - alphaGP),
519 std::tan(delta)*std::cos(deltaGP) - std::cos(alpha - alphaGP)*std::sin(deltaGP))) *
afwGeom::radians;
520 afwGeom::Angle const b = std::asin( (std::sin(deltaGP)*std::sin(delta) + std::cos(deltaGP)*std::cos(delta)*std::cos(alpha - alphaGP))) *
afwGeom::radians;
534 double const c = std::cos(theta);
535 double const mc = 1.0 - c;
536 double const s = std::sin(theta);
541 double const ux = u[0];
542 double const uy = u[1];
543 double const uz = u[2];
547 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];
548 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];
549 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];
552 std::pair<afwGeom::Angle, afwGeom::Angle> lonLat = pointToLonLat(xprime);
553 _longitude = lonLat.first;
554 _latitude = lonLat.second;
579 Eigen::Vector3d r = getVector().asEigen();
598 u << -std::sin(getLongitude()), std::cos(getLongitude()), 0.0;
599 Eigen::Vector3d
w = r.cross(u);
600 Eigen::Vector3d v = arcLen * std::cos(phi)*u + arcLen * std::sin(phi)*
w;
603 Eigen::Vector3d axisVector = r.cross(v);
604 axisVector.normalize();
607 rotate(axisCoord, arcLen);
616 Eigen::Vector3d r2 = getVector().asEigen();
618 u2 << -std::sin(getLongitude()), std::cos(getLongitude()), 0.0;
619 Eigen::Vector3d w2 = r2.cross(u2);
624 v2Coord.
rotate(axisCoord, arcLen);
672 "Cannot make Topocentric with convert() (must also specify Observatory).\n"
673 "Instantiate TopocentricCoord() directly.");
677 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC allowed.");
695 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
701 return haversine(alpha1 - alpha2, delta1 - delta2, std::cos(delta1), std::cos(delta2));
712 std::pair<afwGeom::Angle, afwGeom::Angle>
718 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
727 double const cosDelta1 = std::cos(delta1);
728 double const cosDelta2 = std::cos(delta2);
730 afwGeom::Angle separation = haversine(dAlpha, dDelta, cosDelta1, cosDelta2);
733 double const y = std::sin(dAlpha)*cosDelta2;
734 double const x = cosDelta1*std::sin(delta2) - std::sin(delta1)*cosDelta2*std::cos(dAlpha);
737 return std::make_pair(bearing, separation);
747 std::pair<afwGeom::Angle, afwGeom::Angle>
753 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
760 double const sinDelta1 = std::sin(delta1);
761 double const cosDelta1 = std::cos(delta1);
762 double const sinDelta2 = std::sin(delta2);
763 double const cosDelta2 = std::cos(delta2);
764 double const cosAlphaDiff = std::cos(alpha2 - alpha1);
765 double const sinAlphaDiff = std::sin(alpha2 - alpha1);
767 double const div = cosDelta1 * cosAlphaDiff * cosDelta2 + sinDelta1 * sinDelta2;
768 double const xi = cosDelta1 * sinAlphaDiff / div;
769 double const eta = (cosDelta1 * cosAlphaDiff * sinDelta2 - sinDelta1 * cosDelta2) / div;
779 return Fk5Coord(getLongitude(), getLatitude(), getEpoch()).
precess(epoch);
785 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
793 return this->toFk5().
toIcrs();
840 return Fk5Coord(getLongitude(), getLatitude(), getEpoch()).
precess(epoch);
846 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
856 if ( fabs(getEpoch() - 2000.0) > epochTolerance ) {
860 return IcrsCoord(getLongitude(), getLatitude());
872 if ( fabs(getEpoch() - 2000.0) > epochTolerance ) {
890 Coord c = transform(equPoleInEcliptic, eclPoleInEquatorial);
897 return this->toEcliptic(getEpoch());
926 double const sinh = std::sin(phi)* std::sin(delta) + std::cos(phi) * std::cos(delta) * std::cos(H);
930 double const tanAnumerator = std::sin(H);
931 double const tanAdenominator = (std::cos(H) * std::sin(phi) - std::tan(delta) * std::cos(phi));
952 if ( fabs(getEpoch() - epochTo) < epochTolerance) {
953 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
961 double const T = (jd0 - JD2000)/36525.0;
962 double const t = (jd - jd0)/36525.0;
963 double const tt = t*t;
964 double const ttt = tt*t;
966 afwGeom::Angle const xi = ((2306.2181 + 1.39656*T - 0.000139*T*T)*t +
968 afwGeom::Angle const z = ((2306.2181 + 1.39656*T - 0.000139*T*T)*t +
970 afwGeom::Angle const theta = ((2004.3109 - 0.85330*T - 0.000217*T*T)*t -
977 double const a = std::cos(delta0) * std::sin((alpha0 + xi));
978 double const b = std::cos(theta) * std::cos(delta0) * std::cos((alpha0 + xi)) - std::sin(theta) * std::sin(delta0);
979 double const c = std::sin(theta) * std::cos(delta0) * std::cos((alpha0 + xi)) + std::cos(theta) * std::sin(delta0);
984 return Fk5Coord(alpha, delta, epochTo);
1005 return Fk5Coord(getLongitude(), getLatitude(), 2000.0).
precess(epoch);
1011 return Fk5Coord(getLongitude(), getLatitude(), 2000.0);
1018 return IcrsCoord(getLongitude(), getLatitude());
1043 Coord c = transform(GalacticPoleInFk5(), Fk5PoleInGalactic());
1050 return this->toFk5(2000.0);
1079 return EclipticCoord(getLongitude(), getLatitude(), getEpoch());
1090 Coord const fk5PoleInEcliptic(ninety, ninety - eclPoleIncl, epoch);
1091 Coord c = transform(eclipticPoleInFk5, fk5PoleInEcliptic);
1098 return this->toFk5(getEpoch());
1108 double const epochTo
1142 double const tanHnum = std::sin(A);
1143 double const tanHdenom = std::cos(A)*std::sin(phi) + std::tan(h)*std::cos(phi);
1147 double const sinDelta = std::sin(phi)*std::sin(h) - std::cos(phi)*std::cos(h)*std::cos(A);
1150 return Fk5Coord(alpha, delta, epoch);
1156 return this->toFk5(getEpoch());
1170 (
boost::format(
"Expected observatory %s, saw %s") % _obs % obs).str());
1172 if (fabs(date.
get() - getEpoch()) > std::numeric_limits<double>::epsilon()) {
1174 (
boost::format(
"Expected date %g, saw %g") % getEpoch() % date.
get()).str());
1220 return boost::shared_ptr<Fk5Coord>(
new Fk5Coord(ra, dec, epoch));
1224 "ICRS has no epoch, use overloaded makeCoord with args (system, ra, dec).");
1228 "Galactic has no epoch, use overloaded makeCoord with (system, ra, dec).");
1231 return boost::shared_ptr<EclipticCoord>(
new EclipticCoord(ra, dec, epoch));
1235 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1236 "Instantiate TopocentricCoord() directly.");
1240 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, and TOPOCENTRIC allowed.");
1263 return boost::shared_ptr<Fk5Coord>(
new Fk5Coord(ra, dec, 2000.0));
1266 return boost::shared_ptr<IcrsCoord>(
new IcrsCoord(ra, dec));
1269 return boost::shared_ptr<GalacticCoord>(
new GalacticCoord(ra, dec));
1272 return boost::shared_ptr<EclipticCoord>(
new EclipticCoord(ra, dec, 2000.0));
1276 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1277 "Instantiate TopocentricCoord() directly.");
1281 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, and TOPOCENTRIC allowed.");
1303 Coord c(p3d, 2000.0, normalize, defaultLongitude);
1318 Coord c(p3d, 2000.0, normalize, defaultLongitude);
1365 std::string
const ra,
1366 std::string
const dec,
1378 std::string
const ra,
1379 std::string
const dec
1394 return boost::shared_ptr<Fk5Coord>(
new Fk5Coord());
1397 return boost::shared_ptr<IcrsCoord>(
new IcrsCoord());
1400 return boost::shared_ptr<GalacticCoord>(
new GalacticCoord());
1403 return boost::shared_ptr<EclipticCoord>(
new EclipticCoord());
1407 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1408 "Instantiate TopocentricCoord() directly.");
1412 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, allowed.");
1422 % coord[0].asDegrees()
1423 % coord[1].asDegrees()).str();
1424 if (className ==
"TopocentricCoord") {
1428 }
else if (className !=
"IcrsCoord" && className !=
"GalacticCoord") {
virtual Fk5Coord toFk5() const
Convert ourself from Ecliptic to Fk5 (use current epoch)
virtual IcrsCoord toIcrs() const
Icrs converter for IcrsCoord. (ie. a no-op)
boost::shared_ptr< Coord > Ptr
virtual EclipticCoord toEcliptic() const
Convert ourself to Ecliptic: lambda, beta (use existing epoch)
Class for handling dates/times, including MJD, UTC, and TAI.
lsst::afw::coord::Coord Coord
lsst::afw::geom::Angle _longitude
virtual GalacticCoord toGalactic() const
Convert ourself to Galactic: l, b.
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
A class to handle Galactic coordinates (inherits from Coord)
lsst::afw::geom::Angle hmsStringToAngle(std::string const hms)
Convert a hh:mm:ss string to Angle.
double asAngularUnits(AngleUnit const &units) const
AngleUnit const radians
constant with units of radians
virtual Fk5Coord toFk5() const
Convert ourself to Fk5 (ie. a no-op): RA, Dec (keep current epoch)
Store information about an observatory ... lat/long, elevation.
EclipticCoord precess(double const epochTo) const
precess to new epoch
virtual Fk5Coord toFk5() const
Convert outself from Topocentric to Fk5 (use current epoch)
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &obsDate) const
Convert ourself to Altitude/Azimuth: alt, az.
std::pair< lsst::afw::geom::Angle, lsst::afw::geom::Angle > getTangentPlaneOffset(Coord const &c) const
Get the offset on the tangent plane.
Fk5Coord precess(double const epochTo) const
Precess ourselves from whence we are to a new epoch.
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &date) const
Convert ourself from Topocentric to Topocentric ... a no-op.
virtual TopocentricCoord toTopocentric() const
Convert ourself from Topocentric to Topocentric with no observatory or date arguments.
virtual EclipticCoord toEcliptic(double const epoch) const
Convert ourself from Ecliptic to Ecliptic ... a no-op (but precess to new epoch)
double get(DateSystem system=MJD, Timescale scale=TAI) const
Coord()
Default constructor for the Coord base class.
std::pair< lsst::afw::geom::Angle, lsst::afw::geom::Angle > getOffsetFrom(Coord const &c) const
Compute the offset from a coordinate.
lsst::afw::coord::IcrsCoord IcrsCoord
virtual IcrsCoord toIcrs() const
Convert ourself to ICRS: RA, Dec (basically J2000)
void rotate(Coord const &axis, lsst::afw::geom::Angle const theta)
Rotate our current coords about a pole.
A class used to convert scalar POD types such as double to Angle.
void _verifyValues() const
Make sure the values we've got are in the range 0 <= x < 2PI.
virtual void reset(lsst::afw::geom::Angle const longitude, lsst::afw::geom::Angle const latitude)
A coordinate class intended to represent absolute positions.
lsst::afw::geom::Angle _latitude
virtual Fk5Coord toFk5(double const epoch) const
Convert ourself to Fk5: RA, Dec (precess to new epoch)
virtual Fk5Coord toFk5() const
Convert ourself from galactic to Fk5 (no epoch specified)
A class to handle topocentric (AltAz) coordinates (inherits from Coord)
virtual Fk5Coord toFk5() const
Convert ourself to Fk5: RA, Dec (use current epoch)
virtual EclipticCoord toEcliptic() const
Convert ourself to Ecliptic: lambda, beta (use current epoch)
EigenVector const & asEigen() const
Return a fixed-size Eigen representation of the coordinate object.
lsst::afw::geom::Angle getDec() const
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.
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 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
Point< double, 3 > Point3D
A class to handle Fk5 coordinates (inherits from Coord)
virtual GalacticCoord toGalactic() const
Convert ourself to Galactic: l, b.
#define LSST_EXCEPT(type,...)
A class to handle Ecliptic coordinates (inherits from Coord)
virtual std::string getClassName() const
Extent< int, N > floor(Extent< double, N > const &input)
lsst::afw::geom::Angle Angle
lsst::afw::geom::Angle getRa() const
lsst::afw::geom::Angle getLongitude() const
The main access method for the longitudinal coordinate.
virtual IcrsCoord toIcrs() const
Convert ourself to ICRS: RA, Dec (basically J2000)
AngleUnit const arcseconds
lsst::afw::geom::Angle getLongitude() const
The main access method for the longitudinal coordinate.
afw::table::Key< double > b
Point< double, 2 > Point2D
CoordSystem makeCoordEnum(std::string const system)
A utility function to get the enum value of a coordinate system from a string name.
virtual Fk5Coord toFk5() const
Fk5 converter for IcrsCoord. (no epoch specified)
std::ostream & operator<<(std::ostream &stream, Exception const &e)
virtual GalacticCoord toGalactic() const
Convert ourself from Galactic to Galactic ... a no-op.
Coord::Ptr convert(CoordSystem system) const
Convert to a specified Coord type.
lsst::afw::geom::Point3D getVector() const
Return our contents in a position vector.
lsst::afw::geom::Angle getLatitude() const
The main access method for the latitudinal coordinate.
lsst::afw::geom::Angle getLatitude() const
The main access method for the longitudinal coordinate.
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 EclipticCoord toEcliptic() const
Convert ourself from Ecliptic to Ecliptic ... a no-op (use the current epoch)
lsst::afw::geom::Point2D getPosition(lsst::afw::geom::AngleUnit unit=lsst::afw::geom::degrees) const
Return our contents in a Point2D object.
lsst::afw::geom::Angle eclipticPoleInclination(double const epoch)
get the inclination of the ecliptic pole (obliquity) at epoch
Include files required for standard LSST Exception handling.
Coord transform(Coord const &poleFrom, Coord const &poleTo) const
Tranform our current coords to another spherical polar system.
lsst::afw::geom::Angle angularSeparation(Coord const &c) const
compute the angular separation between two Coords
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &obsDate) const
Convert ourself to Altitude/Azimuth: alt, az.
Functions to handle coordinates.