Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.apo.nmsu.edu/Telescopes/coordConv/html/coord_8cc_source.html
Дата изменения: Thu May 7 21:42:46 2015
Дата индексирования: Sun Apr 10 02:11:12 2016
Кодировка:
lsst.coordConv: src/coord.cc Source File
lsst.coordConv  unknown
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
coord.cc
Go to the documentation of this file.
1 #include <cmath>
2 #include <iomanip>
3 #include <stdexcept>
4 #include <sstream>
5 #include "coordConv/mathUtils.h"
6 #include "coordConv/physConst.h"
7 #include "coordConv/angSideAng.h"
8 #include "coordConv/coordSys.h"
9 
10 namespace coordConv {
11 
12  double distanceFromParallax(double parallax) {
13  return AUPerParsec / std::max(parallax, MinParallax);
14  }
15 
16  double parallaxFromDistance(double dist) {
17  return std::max(AUPerParsec / dist, MinParallax);
18  }
19 
20  Coord::Coord(double equatAng, double polarAng, double parallax) {
21  _setPosFromSph(equatAng, polarAng, parallax);
22  _setCache();
23  _pm.setZero();
24  }
25 
26  Coord::Coord(double equatAng, double polarAng, double parallax, double equatPM, double polarPM, double radVel) {
27  _setPosFromSph(equatAng, polarAng, parallax);
28  _setCache();
29 
30  const double RadPerYear_per_ArcsecPerCentury = RadPerDeg / (ArcsecPerDeg * 100.0);
31  const double AUPerYear_per_KmPerSec = SecPerDay * DaysPerYear / KmPerAU;
32 
33  const double sinEquat = sind(equatAng);
34  const double cosEquat = cosd(equatAng);
35  const double sinPolar = sind(polarAng);
36  const double cosPolar = cosd(polarAng);;
37 
38  // change units of proper motion from arcsec/century to au/year
39  // (multiply by distance and fix the units)
40  const double pmAUPerYear1 = equatPM * _dist * RadPerYear_per_ArcsecPerCentury;
41  const double pmAUPerYear2 = polarPM * _dist * RadPerYear_per_ArcsecPerCentury;
42 
43  // change units of radial velocity from km/sec to au/year
44  const double radVelAUPerYear = radVel * AUPerYear_per_KmPerSec;
45 // const double radVelAUPerYear = _atInfinity ? 0 : radVel * AUPerYear_per_KmPerSec;
46 
47  // compute velocity vector in au/year
48  _pm <<
49  - (pmAUPerYear2 * sinPolar * cosEquat) - (pmAUPerYear1 * cosPolar * sinEquat) + (radVelAUPerYear * cosPolar * cosEquat),
50  - (pmAUPerYear2 * sinPolar * sinEquat) + (pmAUPerYear1 * cosPolar * cosEquat) + (radVelAUPerYear * cosPolar * sinEquat),
51  + (pmAUPerYear2 * cosPolar) + (radVelAUPerYear * sinPolar);
52  }
53 
54  Coord::Coord(Eigen::Vector3d const &pos)
55  :
56  _pos(pos),
57  _pm(Eigen::Vector3d::Constant(0.0))
58  {
59  _setCache();
60  }
61 
62  Coord::Coord(Eigen::Vector3d const &pos, Eigen::Vector3d const &pm)
63  :
64  _pos(pos),
65  _pm(pm)
66  {
67  _setCache();
68  }
69 
71  :
72  _pos(Eigen::Vector3d::Constant(DoubleNaN)),
73  _pm(Eigen::Vector3d::Constant(DoubleNaN))
74  {
75  _setCache();
76  }
77 
78  double Coord::getParallax() const {
79  return _atInfinity ? 0 : AUPerParsec / _dist;
80  }
81 
82  bool Coord::getSphPos(double &equatAng, double &polarAng) const {
83  double x = _pos(0);
84  double y = _pos(1);
85  double z = _pos(2);
86 
87  if (_atPole) {
88  equatAng = 0.0;
89  polarAng = (z > 0.0) ? 90.0 : -90.0;
90  } else {
91  double posXYMag = hypot(x, y);
92  equatAng = wrapPos(atan2d(y, x));
93  polarAng = atan2d(z, posXYMag);
94  }
95  return _atPole;
96  }
97 
98  bool Coord::getPM(double &equatPM, double &polarPM) const {
99  double const ArcsecPerCentury_per_RadPerYear = 100.0 * ArcsecPerDeg / RadPerDeg;
100 
101  double x = _pos(0);
102  double y = _pos(1);
103  double z = _pos(2);
104  double vX = _pm(0);
105  double vY = _pm(1);
106  double vZ = _pm(2);
107 
108  // now that radial velocity has been computed
109  // handle the "at pole" case
110  if (_atPole) {
111  equatPM = 0.0;
112  polarPM = 0.0;
113  return _atPole;
114  }
115 
116  // useful quantities
117  double magPxy = hypot(x, y);
118  double magPxySq = magPxy * magPxy;
119  double magPSq = _dist * _dist;
120 
121  // compute proper motion in rad per year,
122  // then convert to arcsec per century;
123  // the divisions are safe because:
124  // - magPxySq must have some reasonable minimum value,
125  // else scFromCC would have set atPole true,
126  // and that case has already been handled above
127  // - magPSq must have some reasonable minimum value,
128  // else scFromCC would have set isOK false
129  equatPM = (((x * vY) - (y * vX)) / magPxySq) * ArcsecPerCentury_per_RadPerYear;
130  polarPM = (((vZ * magPxy) - ((z / magPxy) * ((x * vX) + (y * vY)))) / magPSq) * ArcsecPerCentury_per_RadPerYear;
131  return _atPole;
132  }
133 
134  double Coord::getRadVel() const {
135  // compute radial velocity in (au/year) and convert to (km/s)
136  double const KMPerSec_per_AUPerYear = KmPerAU / (DaysPerYear * SecPerDay);
137  return (_pos / _dist).dot(_pm) * KMPerSec_per_AUPerYear;
138 // return _atInfinity ? 0 : _pos.dot(_pm) * KMPerSec_per_AUPerYear / _dist;
139  }
140 
141  bool Coord::isfinite() const {
142  for (int i = 0; i < 3; ++i) {
143  if (!std::isfinite(_pos(i))) return false;
144  if (!std::isfinite(_pm(i))) return false;
145  }
146  if (!std::isfinite(_dist)) return false;
147  return true;
148  }
149 
150  double Coord::angularSeparation(Coord const &coord) const {
151  double crossMag = _pos.cross(coord.getVecPos()).norm();
152  double dotProd = _pos.dot(coord.getVecPos());
153  return atan2d(crossMag, dotProd);
154  }
155 
156  double Coord::orientationTo(Coord const &coord) const {
157  Eigen::Vector3d fromU = _pos / _dist;
158  Eigen::Vector3d toU = coord.getVecPos();
159  toU.normalize();
160 
161  double sinVal = (toU(1) * fromU(0)) - (toU(0) * fromU(1));
162  double cosVal = (toU(2) * ((fromU(0) * fromU(0)) + (fromU(1) * fromU(1))))
163  - (fromU(2) * ((toU(0) * fromU(0)) + (toU(1) * fromU(1))));
164  // 2e-10 is based on experimentation; max observed error was < 1.5" with this limit
165  if ((std::abs(sinVal) > 2e-10) || (std::abs(cosVal) > 2e-10)) {
166  return wrapCtr(90 - atan2d(sinVal, cosVal));
167  } else {
168  return DoubleNaN;
169  }
170  }
171 
172  Coord Coord::offset(double &toOrient, double fromOrient, double dist) const {
173  if (atPole()) {
174  throw std::runtime_error("cannot offset; at pole");
175  }
176  // short-circuit zero offset
177  if (dist == 0) {
178  toOrient = wrapCtr(fromOrient);
179  return *this;
180  }
181 
182  // code is a minor adaptation of LSST afw Coord::offset
183 
184  // To do the rotation, compute a rotation matrix based on axis of rotation
185  //
186  // The axis of rotation is given by r x v,
187  // where:
188  // - r is a unit vector along _pos, the vector position of this coord
189  // - v is a unit vector in the direction of the great circle offset (tangent to the sphere at _pos),
190  //
191  // compute v as follows:
192  // let u = a unit vector along the direction of increasing equatorial angle
193  // = (-ry, rx, 0), normalized (which is impossible at the pole)
194  // let w = a unit vector along the direction of increasing polar angle
195  // = r x u
196  // the vector v must satisfy the following:
197  // r . v = 0
198  // u . v = cos(fromOrient)
199  // w . v = sin(fromOrient)
200  // v is a linear combination of u and w
201  // v = cos(fromOrient)*u + sin(fromOrient)*w
202 
203  // Thus, we must:
204  // - create u vector
205  // - solve w vector (r cross u)
206  // - compute v
207  Eigen::Vector3d u = Eigen::Vector3d(-_pos(1), _pos(0), 0) / hypot(_pos(0), _pos(1));
208  Eigen::Vector3d w = (_pos / _dist).cross(u);
209  Eigen::Vector3d v = (cosd(fromOrient) * u) + (sind(fromOrient) * w);
210 
211  // take r x v to get the axis
212  Eigen::Vector3d axisVector = (_pos / _dist).cross(v);
213  Eigen::Matrix3d rotMat;
214  computeRotationMatrix(rotMat, axisVector, dist);
215  Eigen::Vector3d toPos = rotMat * _pos;
216  Eigen::Vector3d toVel = rotMat * _pm;
217  Coord toCoord(toPos, toVel);
218  double unwrappedToOrient = toCoord.orientationTo(*this) + 180.0;
219  if (!std::isfinite(unwrappedToOrient)) {
220  // distance too small
221  unwrappedToOrient = fromOrient;
222  }
223  toOrient = wrapCtr(unwrappedToOrient);
224  return toCoord;
225  }
226 
227  std::string Coord::__repr__() const {
228  std::ostringstream os;
229  os << *this;
230  return os.str();
231  }
232 
233  void Coord::_setPosFromSph(double equatAng, double polarAng, double parallax) {
234  if ((polarAng < -90.0) || (polarAng > 90.0)) {
235  std::ostringstream os;
236  os << "polarAng = " << polarAng << " not in range [-90, 90]";
237  throw std::runtime_error(os.str());
238  }
239 
240  double const dist = distanceFromParallax(parallax);
241 
242  _pos <<
243  dist * cosd(polarAng) * cosd(equatAng),
244  dist * cosd(polarAng) * sind(equatAng),
245  dist * sind(polarAng);
246  }
247 
248  void Coord::_setCache() {
249  _dist = _pos.norm();
250 
251  // make sure |_pos| is large enough to compute with
252  if (_dist * _dist < std::numeric_limits<double>::min()) {
253  std::ostringstream os;
254  os << "Magnitude of _pos = (" << _pos(0) << ", " << _pos(1) << ", " << _pos(2) << ") too small";
255  throw std::runtime_error(os.str());
256  }
257  _atInfinity = _dist > 0.9 * AUPerParsec / MinParallax;
258  // this test for atPole is based on reliably round-tripping equatPM to 6 digits
259  double xyFracMag = hypot(_pos(0), _pos(1)) / _dist;
260  _atPole = (xyFracMag * xyFracMag < std::numeric_limits<double>::epsilon());
261  }
262 
263  std::ostream &operator<<(std::ostream &os, Coord const &coord) {
264  double equatAng, polarAng, equatPM, polarPM;
265  coord.getSphPos(equatAng, polarAng);
266  coord.getPM(equatPM, polarPM);
267  double radVel = coord.getRadVel();
268  double parallax = coord.getParallax();
269  std::ios_base::fmtflags oldFlags = os.flags();
270  std::streamsize const oldPrecision = os.precision();
271  os << std::fixed
272  << "Coord(" << std::setprecision(6) << equatAng << ", " << polarAng << ", "
273  << std::setprecision(5) << parallax;
274  if ((equatPM != 0) || (polarPM != 0) || (radVel != 0)) {
275  os << std::setprecision(2) << ", " << equatPM << ", " << polarPM << ", " << radVel;
276  }
277  os << ")" << std::setprecision(oldPrecision);
278  os.flags(oldFlags);
279  return os;
280  }
281 
282 }
double angularSeparation(Coord const &coord) const
Definition: coord.cc:150
std::string __repr__() const
Definition: coord.cc:227
const double AUPerParsec
Definition: physConst.h:21
const double MinParallax
Definition: coord.h:10
bool getSphPos(double &equatAng, double &polarAng) const
Definition: coord.cc:82
double hypot(double x, double y)
Definition: mathUtils.cc:8
bool isfinite() const
Definition: coord.cc:141
double cosd(double ang)
cosine of angle in degrees
Definition: mathUtils.h:55
double wrapCtr(double ang)
Definition: mathUtils.cc:33
const double DoubleNaN
Definition: mathUtils.h:16
const double SecPerDay
Definition: physConst.h:23
double sind(double ang)
sine of angle in degrees
Definition: mathUtils.h:52
const double DaysPerYear
Definition: physConst.h:24
double distanceFromParallax(double parallax)
Definition: coord.cc:12
bool getPM(double &equatPM, double &polarPM) const
Definition: coord.cc:98
double parallaxFromDistance(double dist)
Definition: coord.cc:16
double getRadVel() const
Definition: coord.cc:134
double atan2d(double x, double y)
arctangent2 in degrees
Definition: mathUtils.h:70
Coord offset(double &toOrient, double fromOrient, double dist) const
Definition: coord.cc:172
Eigen::Vector3d const getVecPos() const
Definition: coord.h:135
const double KmPerAU
Definition: physConst.h:20
double getParallax() const
Definition: coord.cc:78
const double RadPerDeg
Definition: physConst.h:19
void computeRotationMatrix(Eigen::Matrix3d &rotMat, Eigen::Vector3d const &axis, double rotAngle)
Definition: mathUtils.cc:33
bool atPole() const
Definition: coord.h:86
double orientationTo(Coord const &coord) const
Definition: coord.cc:156
std::ostream & operator<<(std::ostream &out, Coord const &coord)
Definition: coord.cc:263
double wrapPos(double ang)
Definition: mathUtils.cc:20
const double ArcsecPerDeg
Definition: physConst.h:22