NumCpp  2.11.0
A Templatized Header Only C++ Implementation of the Python NumPy Library
Celestial.hpp
Go to the documentation of this file.
1 #pragma once
29 
30 #include <cmath>
31 #include <iostream>
32 #include <string>
33 
36 #include "NumCpp/Core/Types.hpp"
38 #include "NumCpp/Functions/dot.hpp"
40 #include "NumCpp/NdArray.hpp"
42 #include "NumCpp/Utils/num2str.hpp"
43 #include "NumCpp/Utils/sqr.hpp"
44 #include "NumCpp/Vector/Vec3.hpp"
45 
47 {
48  //================================================================================
50  class RA
51  {
52  public:
53  //============================================================================
56  RA() = default;
57 
58  //============================================================================
63  explicit RA(double inDegrees) :
64  degrees_(inDegrees),
65  radians_(deg2rad(inDegrees))
66  {
67  if (inDegrees < 0 || inDegrees >= 360)
68  {
69  THROW_INVALID_ARGUMENT_ERROR("input degrees must be of the range [0, 360)");
70  }
71 
72  hours_ = static_cast<uint8>(std::floor(degrees_ / 15.));
73  const double decMinutes = (degrees_ - static_cast<double>(hours_) * 15.) * 4.;
74  minutes_ = static_cast<uint8>(std::floor(decMinutes));
75  seconds_ = static_cast<double>((decMinutes - static_cast<double>(minutes_)) * 60.);
76  }
77 
78  //============================================================================
85  RA(uint8 inHours, uint8 inMinutes, double inSeconds)
86  noexcept :
87  hours_(inHours),
88  minutes_(inMinutes),
89  seconds_(inSeconds)
90  {
91  degrees_ = static_cast<double>(hours_) * 15. + static_cast<double>(minutes_) / 4. + seconds_ / 240.;
92  radians_ = deg2rad(degrees_);
93  }
94 
95  //============================================================================
100  [[nodiscard]] double radians() const noexcept
101  {
102  return radians_;
103  }
104 
105  //============================================================================
110  [[nodiscard]] double degrees() const noexcept
111  {
112  return degrees_;
113  }
114 
115  //============================================================================
120  [[nodiscard]] uint8 hours() const noexcept
121  {
122  return hours_;
123  }
124 
125  //============================================================================
130  [[nodiscard]] uint8 minutes() const noexcept
131  {
132  return minutes_;
133  }
134 
135  //============================================================================
140  [[nodiscard]] double seconds() const noexcept
141  {
142  return seconds_;
143  }
144 
145  //============================================================================
150  [[nodiscard]] std::string str() const
151  {
152  std::string out =
153  "RA hms: " + utils::num2str(hours_) + " hours, " + utils::num2str(minutes_) + " minutes, ";
154  out += utils::num2str(seconds_) + " seconds\nRA degrees: " + utils::num2str(degrees_) + '\n';
155  return out;
156  }
157 
158  //============================================================================
161  void print() const
162  {
163  std::cout << *this;
164  }
165 
166  //============================================================================
173  bool operator==(const RA& inRhs) const noexcept
174  {
175  return utils::essentiallyEqual(degrees_, inRhs.degrees_);
176  }
177 
178  //============================================================================
185  bool operator!=(const RA& inRhs) const noexcept
186  {
187  return !(*this == inRhs);
188  }
189 
190  //============================================================================
196  friend std::ostream& operator<<(std::ostream& inStream, const RA& inRa)
197  {
198  inStream << inRa.str();
199  return inStream;
200  }
201 
202  private:
203  //====================================Attributes==============================
204  uint8 hours_{ 0 };
205  uint8 minutes_{ 0 };
206  double seconds_{ 0. };
207  double degrees_{ 0. };
208  double radians_{ 0. };
209  };
210 
211  //================================================================================
213  class Dec
214  {
215  public:
216  //================================================================================
218  enum class Sign
219  {
220  NEGATIVE = 0,
221  POSITIVE
222  };
223 
224  //============================================================================
227  Dec() = default;
228 
229  //============================================================================
234  explicit Dec(double inDegrees) :
235  degrees_(inDegrees),
236  radians_(deg2rad(inDegrees))
237  {
238  if (inDegrees < -90 || inDegrees > 90)
239  {
240  THROW_INVALID_ARGUMENT_ERROR("input degrees must be of the range [-90, 90]");
241  }
242 
243  sign_ = degrees_ < 0 ? Sign::NEGATIVE : Sign::POSITIVE;
244  const double absDegrees = std::abs(degrees_);
245  degreesWhole_ = static_cast<uint8>(std::floor(absDegrees));
246 
247  const double decMinutes = (absDegrees - static_cast<double>(degreesWhole_)) * 60.;
248  minutes_ = static_cast<uint8>(std::floor(decMinutes));
249  seconds_ = (decMinutes - static_cast<double>(minutes_)) * 60.;
250  }
251 
252  //============================================================================
260  Dec(Sign inSign, uint8 inDegrees, uint8 inMinutes, double inSeconds) noexcept :
261  sign_(inSign),
262  degreesWhole_(inDegrees),
263  minutes_(inMinutes),
264  seconds_(inSeconds)
265  {
266  degrees_ = static_cast<double>(degreesWhole_) + static_cast<double>(minutes_) / 60. + seconds_ / 3600.;
267  degrees_ *= sign_ == Sign::NEGATIVE ? -1 : 1;
268 
269  radians_ = deg2rad(degrees_);
270  }
271 
272  //============================================================================
277  [[nodiscard]] Sign sign() const noexcept
278  {
279  return sign_;
280  }
281 
282  //============================================================================
287  [[nodiscard]] double degrees() const noexcept
288  {
289  return degrees_;
290  }
291 
292  //============================================================================
297  [[nodiscard]] double radians() const noexcept
298  {
299  return radians_;
300  }
301 
302  //============================================================================
307  [[nodiscard]] uint8 degreesWhole() const noexcept
308  {
309  return degreesWhole_;
310  }
311 
312  //============================================================================
317  [[nodiscard]] uint8 minutes() const noexcept
318  {
319  return minutes_;
320  }
321 
322  //============================================================================
327  [[nodiscard]] double seconds() const noexcept
328  {
329  return seconds_;
330  }
331 
332  //============================================================================
337  [[nodiscard]] std::string str() const
338  {
339  std::string strSign = sign_ == Sign::NEGATIVE ? "-" : "+";
340  std::string out = "Dec dms: " + strSign + utils::num2str(degreesWhole_) + " degrees, " +
341  utils::num2str(minutes_) + " minutes, ";
342  out += utils::num2str(seconds_) + " seconds\nDec degrees = " + utils::num2str(degrees_) + '\n';
343  return out;
344  }
345 
346  //============================================================================
349  void print() const
350  {
351  std::cout << *this;
352  }
353 
354  //============================================================================
361  bool operator==(const Dec& inRhs) const noexcept
362  {
363  return utils::essentiallyEqual(degrees_, inRhs.degrees_);
364  }
365 
366  //============================================================================
373  bool operator!=(const Dec& inRhs) const noexcept
374  {
375  return !(*this == inRhs);
376  }
377 
378  //============================================================================
386  friend std::ostream& operator<<(std::ostream& inStream, const Dec& inDec)
387  {
388  inStream << inDec.str();
389  return inStream;
390  }
391 
392  private:
393  //====================================Attributes==============================
394  Sign sign_{ Sign::POSITIVE };
395  uint8 degreesWhole_{ 0 };
396  uint8 minutes_{ 0 };
397  double seconds_{ 0. };
398  double degrees_{ 0. };
399  double radians_{ 0. };
400  };
401 
402  //================================================================================
404  class Celestial
405  {
406  public:
407  //============================================================================
410  Celestial() = default;
411 
412  //============================================================================
418  Celestial(double inRaDegrees, double inDecDegrees) :
419  ra_(inRaDegrees),
420  dec_(inDecDegrees)
421  {
422  polarToCartesian();
423  }
424 
425  //============================================================================
436  Celestial(uint8 inRaHours,
437  uint8 inRaMinutes,
438  double inRaSeconds,
439  Dec::Sign inSign,
440  uint8 inDecDegreesWhole,
441  uint8 inDecMinutes,
442  double inDecSeconds) :
443  ra_(inRaHours, inRaMinutes, inRaSeconds),
444  dec_(inSign, inDecDegreesWhole, inDecMinutes, inDecSeconds)
445  {
446  polarToCartesian();
447  }
448 
449  //============================================================================
455  Celestial(const RA& inRA, const Dec& inDec) noexcept :
456  ra_(inRA),
457  dec_(inDec)
458  {
459  polarToCartesian();
460  }
461 
462  //============================================================================
469  Celestial(double inX, double inY, double inZ) :
470  x_(inX),
471  y_(inY),
472  z_(inZ)
473  {
474  cartesianToPolar();
475  }
476 
477  //============================================================================
482  Celestial(const Cartesian& inCartesianVector) :
483  x_(inCartesianVector.x),
484  y_(inCartesianVector.y),
485  z_(inCartesianVector.z)
486  {
487  cartesianToPolar();
488  }
489 
490  //============================================================================
495  Celestial(const Vec3& inCartesianVector) :
496  x_(inCartesianVector.x),
497  y_(inCartesianVector.y),
498  z_(inCartesianVector.z)
499  {
500  cartesianToPolar();
501  }
502 
503  //============================================================================
508  Celestial(const NdArray<double>& inCartesianVector)
509  {
510  if (inCartesianVector.size() != 3)
511  {
512  THROW_INVALID_ARGUMENT_ERROR("NdArray input must be of length 3.");
513  }
514 
515  x_ = inCartesianVector[0];
516  y_ = inCartesianVector[1];
517  z_ = inCartesianVector[2];
518 
519  cartesianToPolar();
520  }
521 
522  //============================================================================
527  [[nodiscard]] const Dec& dec() const noexcept
528  {
529  return dec_;
530  }
531 
532  //============================================================================
537  [[nodiscard]] const RA& ra() const noexcept
538  {
539  return ra_;
540  }
541 
542  //============================================================================
547  [[nodiscard]] double x() const noexcept
548  {
549  return x_;
550  }
551 
552  //============================================================================
557  [[nodiscard]] double y() const noexcept
558  {
559  return y_;
560  }
561 
562  //============================================================================
567  [[nodiscard]] double z() const noexcept
568  {
569  return z_;
570  }
571 
572  //============================================================================
577  [[nodiscard]] NdArray<double> xyz() const
578  {
579  NdArray<double> out = { x_, y_, z_ };
580  return out;
581  }
582 
583  //============================================================================
590  [[nodiscard]] double degreeSeperation(const Celestial& inOtherCelestial) const
591  {
592  return rad2deg(radianSeperation(inOtherCelestial));
593  }
594 
595  //============================================================================
603  [[nodiscard]] double degreeSeperation(const NdArray<double>& inVector) const
604  {
605  return rad2deg(radianSeperation(inVector));
606  }
607 
608  //============================================================================
615  [[nodiscard]] double radianSeperation(const Celestial& inOtherCelestial) const
616  {
617  return std::acos(dot(xyz(), inOtherCelestial.xyz()).item());
618  }
619 
620  //============================================================================
628  [[nodiscard]] double radianSeperation(const NdArray<double>& inVector) const
629  {
630  if (inVector.size() != 3)
631  {
632  THROW_INVALID_ARGUMENT_ERROR("input vector must be of length 3.");
633  }
634 
635  return std::acos(dot(xyz(), inVector.flatten()).item());
636  }
637 
638  //============================================================================
643  [[nodiscard]] std::string str() const
644  {
645  std::string returnStr;
646  returnStr = ra_.str();
647  returnStr += dec_.str();
648  returnStr += "Cartesian = " + xyz().str();
649  return returnStr;
650  }
651 
652  //============================================================================
655  void print() const
656  {
657  std::cout << *this;
658  }
659 
660  //============================================================================
667  bool operator==(const Celestial& inRhs) const noexcept
668  {
669  return ra_ == inRhs.ra_ && dec_ == inRhs.dec_;
670  }
671 
672  //============================================================================
679  bool operator!=(const Celestial& inRhs) const noexcept
680  {
681  return !(*this == inRhs);
682  }
683 
684  //============================================================================
692  friend std::ostream& operator<<(std::ostream& inStream, const Celestial& inCoord)
693  {
694  inStream << inCoord.str();
695  return inStream;
696  }
697 
698  private:
699  //====================================Attributes==============================
700  RA ra_{};
701  Dec dec_{};
702  double x_{ 1. };
703  double y_{ 0. };
704  double z_{ 0. };
705 
706  //============================================================================
709  void cartesianToPolar()
710  {
711  double degreesRa = rad2deg(std::atan2(y_, x_));
712  if (degreesRa < 0)
713  {
714  degreesRa += 360;
715  }
716  ra_ = RA(degreesRa);
717 
718  const double r = std::sqrt(utils::sqr(x_) + utils::sqr(y_) + utils::sqr(z_));
719  const double degreesDec = rad2deg(std::asin(z_ / r));
720  dec_ = Dec(degreesDec);
721  }
722 
723  //============================================================================
726  void polarToCartesian() noexcept
727  {
728  const double raRadians = deg2rad(ra_.degrees());
729  const double decRadians = deg2rad(dec_.degrees());
730 
731  x_ = std::cos(raRadians) * std::cos(decRadians);
732  y_ = std::sin(raRadians) * std::cos(decRadians);
733  z_ = std::sin(decRadians);
734  }
735  };
736 } // namespace nc::coordinates::reference_frames
#define THROW_INVALID_ARGUMENT_ERROR(msg)
Definition: Error.hpp:37
size_type size() const noexcept
Definition: NdArrayCore.hpp:4477
self_type flatten() const
Definition: NdArrayCore.hpp:2800
std::string str() const
Definition: NdArrayCore.hpp:4535
Holds a 3D vector.
Definition: Vec3.hpp:51
Cartensian coordinates.
Definition: Cartesian.hpp:45
Holds a full celestial Celestial object.
Definition: Celestial.hpp:405
Celestial(uint8 inRaHours, uint8 inRaMinutes, double inRaSeconds, Dec::Sign inSign, uint8 inDecDegreesWhole, uint8 inDecMinutes, double inDecSeconds)
Definition: Celestial.hpp:436
Celestial(double inX, double inY, double inZ)
Definition: Celestial.hpp:469
double y() const noexcept
Definition: Celestial.hpp:557
Celestial(const Cartesian &inCartesianVector)
Definition: Celestial.hpp:482
double z() const noexcept
Definition: Celestial.hpp:567
bool operator==(const Celestial &inRhs) const noexcept
Definition: Celestial.hpp:667
Celestial(const RA &inRA, const Dec &inDec) noexcept
Definition: Celestial.hpp:455
NdArray< double > xyz() const
Definition: Celestial.hpp:577
Celestial(const NdArray< double > &inCartesianVector)
Definition: Celestial.hpp:508
double degreeSeperation(const NdArray< double > &inVector) const
Definition: Celestial.hpp:603
const Dec & dec() const noexcept
Definition: Celestial.hpp:527
double radianSeperation(const Celestial &inOtherCelestial) const
Definition: Celestial.hpp:615
Celestial(double inRaDegrees, double inDecDegrees)
Definition: Celestial.hpp:418
friend std::ostream & operator<<(std::ostream &inStream, const Celestial &inCoord)
Definition: Celestial.hpp:692
std::string str() const
Definition: Celestial.hpp:643
const RA & ra() const noexcept
Definition: Celestial.hpp:537
bool operator!=(const Celestial &inRhs) const noexcept
Definition: Celestial.hpp:679
double degreeSeperation(const Celestial &inOtherCelestial) const
Definition: Celestial.hpp:590
Celestial(const Vec3 &inCartesianVector)
Definition: Celestial.hpp:495
double x() const noexcept
Definition: Celestial.hpp:547
double radianSeperation(const NdArray< double > &inVector) const
Definition: Celestial.hpp:628
void print() const
Definition: Celestial.hpp:655
Holds a Declination object.
Definition: Celestial.hpp:214
double degrees() const noexcept
Definition: Celestial.hpp:287
Sign sign() const noexcept
Definition: Celestial.hpp:277
double radians() const noexcept
Definition: Celestial.hpp:297
uint8 minutes() const noexcept
Definition: Celestial.hpp:317
void print() const
Definition: Celestial.hpp:349
Dec(Sign inSign, uint8 inDegrees, uint8 inMinutes, double inSeconds) noexcept
Definition: Celestial.hpp:260
uint8 degreesWhole() const noexcept
Definition: Celestial.hpp:307
friend std::ostream & operator<<(std::ostream &inStream, const Dec &inDec)
Definition: Celestial.hpp:386
std::string str() const
Definition: Celestial.hpp:337
bool operator==(const Dec &inRhs) const noexcept
Definition: Celestial.hpp:361
double seconds() const noexcept
Definition: Celestial.hpp:327
Dec(double inDegrees)
Definition: Celestial.hpp:234
bool operator!=(const Dec &inRhs) const noexcept
Definition: Celestial.hpp:373
Sign
Struct Enum for positive or negative Dec angle.
Definition: Celestial.hpp:219
Holds a right ascension object.
Definition: Celestial.hpp:51
uint8 minutes() const noexcept
Definition: Celestial.hpp:130
double radians() const noexcept
Definition: Celestial.hpp:100
double seconds() const noexcept
Definition: Celestial.hpp:140
void print() const
Definition: Celestial.hpp:161
double degrees() const noexcept
Definition: Celestial.hpp:110
friend std::ostream & operator<<(std::ostream &inStream, const RA &inRa)
Definition: Celestial.hpp:196
uint8 hours() const noexcept
Definition: Celestial.hpp:120
RA(double inDegrees)
Definition: Celestial.hpp:63
bool operator==(const RA &inRhs) const noexcept
Definition: Celestial.hpp:173
std::string str() const
Definition: Celestial.hpp:150
bool operator!=(const RA &inRhs) const noexcept
Definition: Celestial.hpp:185
Definition: AER.hpp:36
std::string num2str(dtype inNumber)
Definition: num2str.hpp:44
bool essentiallyEqual(dtype inValue1, dtype inValue2) noexcept
Definition: essentiallyEqual.hpp:48
constexpr dtype sqr(dtype inValue) noexcept
Definition: sqr.hpp:42
NdArray< dtype > dot(const NdArray< dtype > &inArray1, const NdArray< dtype > &inArray2)
Definition: dot.hpp:47
constexpr auto deg2rad(dtype inValue) noexcept
Definition: deg2rad.hpp:47
auto sin(dtype inValue) noexcept
Definition: sin.hpp:49
auto abs(dtype inValue) noexcept
Definition: abs.hpp:49
auto cos(dtype inValue) noexcept
Definition: cos.hpp:49
dtype floor(dtype inValue) noexcept
Definition: floor.hpp:48
constexpr auto rad2deg(dtype inValue) noexcept
Definition: rad2deg.hpp:48
auto sqrt(dtype inValue) noexcept
Definition: sqrt.hpp:48
std::uint8_t uint8
Definition: Types.hpp:42