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).") %
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);
lsst::afw::geom::Point2D getPosition(lsst::afw::geom::AngleUnit unit=lsst::afw::geom::degrees) const
Return our contents in a Point2D object.
virtual CoordSystem getCoordSystem() const
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
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
AngleUnit const radians
constant with units of radians
std::pair< lsst::afw::geom::Angle, lsst::afw::geom::Angle > getOffsetFrom(Coord const &c) const
Compute the offset from a coordinate.
Hold the location of an observatory.
virtual GalacticCoord toGalactic() const
Convert ourself to Galactic: l, b.
Include files required for standard LSST Exception handling.
A coordinate class intended to represent offsets and dimensions.
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
EigenVector const & asEigen() const
Return a fixed-size Eigen representation of the coordinate object.
virtual IcrsCoord toIcrs() const
Convert ourself to ICRS: RA, Dec (basically J2000)
lsst::afw::coord::IcrsCoord IcrsCoord
table::Key< geom::Angle > latitude
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &date) const
Convert ourself from Topocentric to Topocentric ...
A class used to convert scalar POD types such as double to Angle.
virtual Fk5Coord toFk5() const
Convert ourself from galactic to Fk5 (no epoch specified)
Extent< double, 3 > Extent3D
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.
double get(DateSystem system=MJD, Timescale scale=TAI) const
Get date as a double in a specified representation, such as MJD.
virtual EclipticCoord toEcliptic(double const epoch) const
Convert ourself from Ecliptic to Ecliptic ...
A class representing an Angle.
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
get telescope longitude (positive values are E of Greenwich)
table::Key< geom::Angle > longitude
boost::shared_ptr< Coord > averageCoord(std::vector< boost::shared_ptr< Coord const >> const coords, CoordSystem system=UNKNOWN)
Return average of a list of coordinates.
std::pair< lsst::afw::geom::Angle, lsst::afw::geom::Angle > getTangentPlaneOffset(Coord const &c) const
Get the offset on the tangent plane.
lsst::afw::geom::Point3D getVector() const
Return our contents in a position vector.
double asAngularUnits(AngleUnit const &units) const
Convert an Angle to a float in radians.
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)
virtual Fk5Coord toFk5() const
Convert ourself to Fk5 (ie.
virtual IcrsCoord toIcrs() const
Icrs converter for IcrsCoord.
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 ...
Point< double, 3 > Point3D
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,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
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)
Return the component-wise floor (round towards more negative).
lsst::afw::geom::Angle Angle
Coord()
Default constructor for the Coord base class.
virtual Fk5Coord toFk5() const
Fk5 converter for IcrsCoord.
AngleUnit const arcseconds
virtual TopocentricCoord toTopocentric(Observatory const &obs, lsst::daf::base::DateTime const &obsDate) const
Convert ourself to Altitude/Azimuth: alt, az.
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.
void scale(double factor)
lsst::afw::geom::Angle getDec() const
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 std::string getClassName() const
virtual EclipticCoord toEcliptic() const
Convert ourself to Ecliptic: lambda, beta (use existing epoch)
std::ostream & operator<<(std::ostream &stream, Exception const &e)
Push the text representation of an exception onto a stream.
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
This is the base class for spherical coordinates.
void wrap()
Wraps this angle to the range [0, 2 pi)
lsst::afw::geom::Angle getLatitude() const
get telescope latitude
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 ...
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.
Functions to handle coordinates.