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") {
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.
Include files required for standard LSST Exception handling.
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.
std::ostream & operator<<(std::ostream &os, CameraPoint const &cameraPoint)
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.
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.
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)
Extent< int, N > floor(Extent< double, N > const &input)
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 std::string getClassName() const
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.