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;
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.");
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)
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)
double get(DateSystem system=MJD, Timescale scale=TAI) const
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)
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.
Include files required for standard LSST Exception handling.
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
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.