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);
677 "Cannot make Topocentric with convert() (must also specify Observatory).\n"
678 "Instantiate TopocentricCoord() directly.");
682 "Cannot convert to UNKNOWN coordinate system");
686 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC allowed.");
704 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
710 return haversine(alpha1 - alpha2, delta1 - delta2, std::cos(delta1), std::cos(delta2));
721 std::pair<afwGeom::Angle, afwGeom::Angle>
727 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
736 double const cosDelta1 = std::cos(delta1);
737 double const cosDelta2 = std::cos(delta2);
739 afwGeom::Angle separation = haversine(dAlpha, dDelta, cosDelta1, cosDelta2);
742 double const y = std::sin(dAlpha)*cosDelta2;
743 double const x = cosDelta1*std::sin(delta2) - std::sin(delta1)*cosDelta2*std::cos(dAlpha);
746 return std::make_pair(bearing, separation);
756 std::pair<afwGeom::Angle, afwGeom::Angle>
762 std::pair<afwCoord::Fk5Coord, afwCoord::Fk5Coord>
const& fk5 = commonFk5(*
this, c);
769 double const sinDelta1 = std::sin(delta1);
770 double const cosDelta1 = std::cos(delta1);
771 double const sinDelta2 = std::sin(delta2);
772 double const cosDelta2 = std::cos(delta2);
773 double const cosAlphaDiff = std::cos(alpha2 - alpha1);
774 double const sinAlphaDiff = std::sin(alpha2 - alpha1);
776 double const div = cosDelta1 * cosAlphaDiff * cosDelta2 + sinDelta1 * sinDelta2;
777 double const xi = cosDelta1 * sinAlphaDiff / div;
778 double const eta = (cosDelta1 * cosAlphaDiff * sinDelta2 - sinDelta1 * cosDelta2) / div;
788 return Fk5Coord(getLongitude(), getLatitude(), getEpoch()).
precess(epoch);
794 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
802 return this->toFk5().
toIcrs();
849 return Fk5Coord(getLongitude(), getLatitude(), getEpoch()).
precess(epoch);
855 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
865 if ( fabs(getEpoch() - 2000.0) > epochTolerance ) {
869 return IcrsCoord(getLongitude(), getLatitude());
881 if ( fabs(getEpoch() - 2000.0) > epochTolerance ) {
899 Coord c = transform(equPoleInEcliptic, eclPoleInEquatorial);
906 return this->toEcliptic(getEpoch());
935 double const sinh = std::sin(phi)* std::sin(delta) + std::cos(phi) * std::cos(delta) * std::cos(H);
939 double const tanAnumerator = std::sin(H);
940 double const tanAdenominator = (std::cos(H) * std::sin(phi) - std::tan(delta) * std::cos(phi));
961 if ( fabs(getEpoch() - epochTo) < epochTolerance) {
962 return Fk5Coord(getLongitude(), getLatitude(), getEpoch());
970 double const T = (jd0 - JD2000)/36525.0;
971 double const t = (jd - jd0)/36525.0;
972 double const tt = t*t;
973 double const ttt = tt*t;
975 afwGeom::Angle const xi = ((2306.2181 + 1.39656*T - 0.000139*T*T)*t +
977 afwGeom::Angle const z = ((2306.2181 + 1.39656*T - 0.000139*T*T)*t +
979 afwGeom::Angle const theta = ((2004.3109 - 0.85330*T - 0.000217*T*T)*t -
986 double const a = std::cos(delta0) * std::sin((alpha0 + xi));
987 double const b = std::cos(theta) * std::cos(delta0) * std::cos((alpha0 + xi)) - std::sin(theta) * std::sin(delta0);
988 double const c = std::sin(theta) * std::cos(delta0) * std::cos((alpha0 + xi)) + std::cos(theta) * std::sin(delta0);
993 return Fk5Coord(alpha, delta, epochTo);
1014 return Fk5Coord(getLongitude(), getLatitude(), 2000.0).
precess(epoch);
1020 return Fk5Coord(getLongitude(), getLatitude(), 2000.0);
1027 return IcrsCoord(getLongitude(), getLatitude());
1052 Coord c = transform(GalacticPoleInFk5(), Fk5PoleInGalactic());
1059 return this->toFk5(2000.0);
1088 return EclipticCoord(getLongitude(), getLatitude(), getEpoch());
1099 Coord const fk5PoleInEcliptic(ninety, ninety - eclPoleIncl, epoch);
1100 Coord c = transform(eclipticPoleInFk5, fk5PoleInEcliptic);
1107 return this->toFk5(getEpoch());
1117 double const epochTo
1151 double const tanHnum = std::sin(A);
1152 double const tanHdenom = std::cos(A)*std::sin(phi) + std::tan(h)*std::cos(phi);
1156 double const sinDelta = std::sin(phi)*std::sin(h) - std::cos(phi)*std::cos(h)*std::cos(A);
1159 return Fk5Coord(alpha, delta, epoch);
1165 return this->toFk5(getEpoch());
1179 (
boost::format(
"Expected observatory %s, saw %s") % _obs % obs).str());
1181 if (fabs(date.
get() - getEpoch()) > std::numeric_limits<double>::epsilon()) {
1183 (
boost::format(
"Expected date %g, saw %g") % getEpoch() % date.
get()).str());
1222 afwGeom::
Angle const ra,
1223 afwGeom::
Angle const dec,
1229 return std::shared_ptr<Fk5Coord>(
new Fk5Coord(ra, dec, epoch));
1233 "ICRS has no epoch, use overloaded makeCoord with args (system, ra, dec).");
1237 "Galactic has no epoch, use overloaded makeCoord with (system, ra, dec).");
1240 return std::shared_ptr<EclipticCoord>(
new EclipticCoord(ra, dec, epoch));
1244 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1245 "Instantiate TopocentricCoord() directly.");
1249 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, and TOPOCENTRIC allowed.");
1266 afwGeom::
Angle const ra,
1267 afwGeom::
Angle const dec
1272 return std::shared_ptr<Fk5Coord>(
new Fk5Coord(ra, dec, 2000.0));
1275 return std::shared_ptr<IcrsCoord>(
new IcrsCoord(ra, dec));
1278 return std::shared_ptr<GalacticCoord>(
new GalacticCoord(ra, dec));
1281 return std::shared_ptr<EclipticCoord>(
new EclipticCoord(ra, dec, 2000.0));
1285 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1286 "Instantiate TopocentricCoord() directly.");
1290 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, and TOPOCENTRIC allowed.");
1307 lsst::afw::geom::
Point3D const &p3d,
1310 afwGeom::
Angle const defaultLongitude
1312 Coord c(p3d, 2000.0, normalize, defaultLongitude);
1323 lsst::afw::geom::
Point3D const &p3d,
1325 afwGeom::
Angle const defaultLongitude
1327 Coord c(p3d, 2000.0, normalize, defaultLongitude);
1338 lsst::afw::geom::
Point2D const &p2d,
1339 afwGeom::AngleUnit unit,
1357 lsst::afw::geom::
Point2D const &p2d,
1358 afwGeom::AngleUnit unit
1374 std::
string const ra,
1375 std::
string const dec,
1387 std::
string const ra,
1388 std::
string const dec
1403 return std::shared_ptr<Fk5Coord>(
new Fk5Coord());
1406 return std::shared_ptr<IcrsCoord>(
new IcrsCoord());
1416 "Cannot make Topocentric with makeCoord() (must also specify Observatory).\n"
1417 "Instantiate TopocentricCoord() directly.");
1421 "Undefined CoordSystem: only FK5, ICRS, GALACTIC, ECLIPTIC, allowed.");
1432 % coord[0].asDegrees()
1433 % coord[1].asDegrees()).str();
1438 }
else if (coordSystem !=
ICRS && coordSystem !=
GALACTIC) {
1449 std::vector<
PTR(afwCoord::
Coord const)> const coords,
1454 assert(coords.size() > 0);
1457 for (
auto&& cc : coords) {
1465 sum.
scale(1.0/coords.size());
1472 std::vector<
PTR(afwCoord::
Coord const)> const coords,
1476 if (coords.size() == 0) {
1477 throw LSST_EXCEPT(ex::LengthError,
"No coordinates provided to average");
1482 system = coords[0]->getCoordSystem();
1483 for (
auto&& cc : coords) {
1484 if (cc->getCoordSystem() != system) {
1486 (
boost::format(
"Coordinates are not all in the same system: %d vs %d") %
1487 cc->getCoordSystem() % system).str());
1490 return doAverageCoord(coords, system);
1494 std::vector<PTR(afwCoord::Coord const)> converted;
1495 converted.reserve(coords.size());
1496 for (
auto&& cc : coords) {
1497 converted.push_back(cc->getCoordSystem() == system ? cc : cc->convert(system));
1499 return doAverageCoord(converted, system);
Extent< double, 3 > Extent3D
virtual EclipticCoord toEcliptic() const
Convert ourself from Ecliptic to Ecliptic ... a no-op (use the current epoch)
lsst::afw::geom::Point3D getVector() const
Return our contents in a position vector.
Coord transform(Coord const &poleFrom, Coord const &poleTo) const
Tranform our current coords to another spherical polar system.
lsst::afw::geom::Angle Angle
Class for handling dates/times, including MJD, UTC, and TAI.
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &date) const
Convert ourself from Topocentric to Topocentric ... a no-op.
lsst::afw::coord::Coord Coord
void scale(double factor)
A class to handle Galactic coordinates (inherits from Coord)
virtual IcrsCoord toIcrs() const
Convert ourself to ICRS: RA, Dec (basically J2000)
lsst::afw::geom::Angle hmsStringToAngle(std::string const hms)
Convert a hh:mm:ss string to Angle.
virtual Fk5Coord toFk5() const
Fk5 converter for IcrsCoord. (no epoch specified)
virtual IcrsCoord toIcrs() const
Icrs converter for IcrsCoord. (ie. a no-op)
Store information about an observatory ... lat/long, elevation.
virtual EclipticCoord toEcliptic() const
Convert ourself to Ecliptic: lambda, beta (use existing epoch)
A coordinate class intended to represent offsets and dimensions.
lsst::afw::geom::Angle getLatitude() 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)
Fk5Coord precess(double const epochTo) const
Precess ourselves from whence we are to a new epoch.
virtual EclipticCoord toEcliptic(double const epoch) const
Convert ourself from Ecliptic to Ecliptic ... a no-op (but precess to new epoch)
lsst::afw::geom::Angle getLatitude() const
The main access method for the latitudinal coordinate.
Point< double, 2 > Point2D
std::pair< lsst::afw::geom::Angle, lsst::afw::geom::Angle > getTangentPlaneOffset(Coord const &c) const
Get the offset on the tangent plane.
virtual GalacticCoord toGalactic() const
Convert ourself from Galactic to Galactic ... a no-op.
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &obsDate) const
Convert ourself to Altitude/Azimuth: alt, az.
virtual GalacticCoord toGalactic() const
Convert ourself to Galactic: l, b.
virtual GalacticCoord toGalactic() const
Convert ourself to Galactic: l, b.
double get(DateSystem system=MJD, Timescale scale=TAI) const
std::ostream & operator<<(std::ostream &os, const Position &pos)
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 ...
lsst::afw::geom::Angle _longitude
lsst::afw::geom::Angle getLongitude() const
The main access method for the longitudinal coordinate.
A class used to convert scalar POD types such as double to Angle.
Point< double, 3 > Point3D
void _verifyValues() const
Make sure the values we've got are in the range 0 <= x < 2PI.
A coordinate class intended to represent absolute positions.
virtual TopocentricCoord toTopocentric() const
Convert ourself from Topocentric to Topocentric with no observatory or date arguments.
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 topocentric (AltAz) coordinates (inherits from Coord)
virtual CoordSystem getCoordSystem() const
lsst::afw::coord::IcrsCoord IcrsCoord
boost::shared_ptr< Coord > averageCoord(std::vector< boost::shared_ptr< Coord const >> const coords, CoordSystem system=UNKNOWN)
virtual void reset(lsst::afw::geom::Angle const longitude, lsst::afw::geom::Angle const latitude)
AngleUnit const radians
constant with units of radians
lsst::afw::geom::Angle getRa() const
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 from Ecliptic to Fk5 (use current epoch)
void rotate(Coord const &axis, lsst::afw::geom::Angle const theta)
Rotate our current coords about a pole.
double asAngularUnits(AngleUnit const &units) const
virtual IcrsCoord toIcrs() const
Convert ourself to ICRS: RA, Dec (basically J2000)
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 ...
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.
lsst::afw::geom::Angle getLongitude() const
The main access method for the longitudinal coordinate.
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 Fk5 coordinates (inherits from Coord)
#define LSST_EXCEPT(type,...)
A class to handle Ecliptic coordinates (inherits from Coord)
Coord()
Default constructor for the Coord base class.
lsst::afw::geom::Angle _latitude
virtual Fk5Coord toFk5() const
Convert ourself to Fk5 (ie. a no-op): RA, Dec (keep current epoch)
Extent< int, N > floor(Extent< double, N > const &input)
virtual Fk5Coord toFk5() const
Convert outself from Topocentric to Fk5 (use current epoch)
EigenVector const & asEigen() const
Return a fixed-size Eigen representation of the coordinate object.
boost::shared_ptr< Coord > 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.
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.
lsst::afw::geom::Angle getDec() const
std::pair< lsst::afw::geom::Angle, lsst::afw::geom::Angle > getOffsetFrom(Coord const &c) const
Compute the offset from a coordinate.
virtual std::string getClassName() const
Include files required for standard LSST Exception handling.
lsst::afw::geom::Angle angularSeparation(Coord const &c) const
compute the angular separation between two Coords
EclipticCoord precess(double const epochTo) const
precess to new epoch
virtual Fk5Coord toFk5() const
Convert ourself from galactic to Fk5 (no epoch specified)
A class to handle Icrs coordinates (inherits from Coord)
virtual EclipticCoord toEcliptic() const
Convert ourself to Ecliptic: lambda, beta (use current epoch)
lsst::afw::geom::Angle dmsStringToAngle(std::string const dms)
Convert a dd:mm:ss string to Angle.
lsst::afw::geom::Angle eclipticPoleInclination(double const epoch)
get the inclination of the ecliptic pole (obliquity) at epoch
AngleUnit const arcseconds
virtual Fk5Coord toFk5() const
Convert ourself to Fk5: RA, Dec (use current epoch)
Functions to handle coordinates.
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &obsDate) const
Convert ourself to Altitude/Azimuth: alt, az.