• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Stellarium / stellarium / 15291801018

28 May 2025 04:52AM UTC coverage: 11.931% (-0.02%) from 11.951%
15291801018

push

github

alex-w
Added new set of navigational stars (XIX century)

0 of 6 new or added lines in 2 files covered. (0.0%)

14124 existing lines in 74 files now uncovered.

14635 of 122664 relevant lines covered (11.93%)

18291.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

21.86
/src/core/modules/Star.hpp
1
/*
2
 * The big star catalogue extension to Stellarium:
3
 * Author and Copyright: Johannes Gajdosik, 2006, 2007
4
 *
5
 * Thanks go to Nigel Kerr for ideas and testing of BE/LE star repacking
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
20
 */
21

22
#ifndef STAR_HPP
23
#define STAR_HPP
24

25
#include "StelObjectType.hpp"
26
#include "StelUtils.hpp"
27
#include "StarMgr.hpp"
28
#include "ZoneData.hpp"
29
#include <QString>
30
#include <QtEndian>
31
#include <cmath>
32

33
// Epoch in JD of the star catalog data
34
#define STAR_CATALOG_JDEPOCH 2457389.0
35

36
class StelObject;
37

38
extern const QString       STAR_TYPE;
39

40
typedef short int          Int16;
41
typedef unsigned short int Uint16;
42

43
template<class Star>
44
class SpecialZoneArray;
45
template<class Star>
46
struct SpecialZoneData;
47

48
// structs for storing the stars in binary form. The idea is
49
// to store much data for bright stars (Star1), but only little or even
50
// very little data for faints stars (Star3). Using only less bytes for Star3
51
// makes it feasible to store hundreds of millions of them in main memory.
52

53
static inline float IndexToBV(int bV)
54
{
55
   return static_cast<float>(bV) * (4.f / 127.f) - 0.5f;
56
}
57

58
static inline int BVToIndex(float bV)
×
59
{
60
   // convert B-V in mag to index understood by internal B-V to color conversion table
61
   return static_cast<int>((bV + 0.5f) * 31.75f);
×
62
}
63

64
template<typename Derived>
65
struct Star
66
{
67
   // methods that must be implemented by the derived class are those not returning 0 or False here
68
   inline double getX0() const
12✔
69
   {
70
      return static_cast<const Derived *>(this)->getX0();
12✔
71
   } // either in rad (if no getX2()) or in internal astrometric unit (only if getX2())
72
   inline double getX1() const
12✔
73
   {
74
      return static_cast<const Derived *>(this)->getX1();
12✔
75
   } // either in rad (if no getX2()) or in internal astrometric unit (only if getX2())
76
   inline double getX2() const
24✔
77
   {
78
      return static_cast<const Derived *>(this)->getX2();
24✔
79
   } // either in rad (if no getX2()) or in internal astrometric unit (only if getX2())
80
   inline int getBVIndex() const
×
81
   {
82
      // need to check because some stars (e.g., Carbon stars) can have really high B-V
83
      // BV index to color table has only 128 entries, otherwise those stars will be black or weird color
84
      int index = BVToIndex(getBV());
×
85
      if (index < 0)
×
86
         return 0;
×
87
      if (index > 127)
×
88
         return 127;
×
89
      return index;
×
90
   }
91
   inline double  getMag() const { return static_cast<const Derived *>(this)->getMag(); } // should return in millimag
92
   inline float   getBV() const { return static_cast<const Derived *>(this)->getBV(); }   // should return in mag
×
93
   // VIP flag is for situation where it can bypass some check (e.g., magnitude display cutoff for Star1 in far
94
   // past/future)
95
   inline bool    isVIP() const { return static_cast<const Derived *>(this)->isVIP(); }
96
   inline StarId  getHip() const { return static_cast<const Derived *>(this)->getHip(); }
×
97
   inline StarId  getGaia() const { return static_cast<const Derived *>(this)->getGaia(); }
×
98
   inline bool    hasName() const { return static_cast<const Derived *>(this)->hasName(); }
99
   inline QString getNameI18n() const { return static_cast<const Derived *>(this)->getNameI18n(); }
100
   inline QString getScreenNameI18n() const { return static_cast<const Derived *>(this)->getScreenNameI18n(); }
101
   inline QString getDesignation() const { return static_cast<const Derived *>(this)->getDesignation(); }
102
   inline int     hasComponentID() const { return static_cast<const Derived *>(this)->hasComponentID(); }
103
   inline int     getObjType() const { return static_cast<const Derived *>(this)->getObjType(); }
104
   inline double  getPMTotal() const
105
   {
106
      return static_cast<const Derived *>(this)->getPMTotal();
107
   } // should return in mas/yr
108
   inline double getDx0() const
12✔
109
   {
110
      return static_cast<const Derived *>(this)->getDx0();
12✔
111
   } // should return in mas/yr (if pmra, then without cos(dec) components), 0 means no 1st proper motion
112
   inline double getDx1() const
12✔
113
   {
114
      return static_cast<const Derived *>(this)->getDx1();
12✔
115
   } // should return in mas/yr, 0 means no 2nd proper motion
116
   inline double getDx2() const
12✔
117
   {
118
      return static_cast<const Derived *>(this)->getDx2();
12✔
119
   } // should return in mas/yr, 0 means no 3rd proper motion
120
   inline double getPlx() const
12✔
121
   {
122
      return static_cast<const Derived *>(this)->getPlx();
12✔
123
   } // should return in mas, 0 means no parallax
124
   inline double getPlxErr() const
125
   {
126
      return static_cast<const Derived *>(this)->getPlxErr();
127
   } // should return in mas, 0 means no parallax error
128
   inline double getRV() const
12✔
129
   {
130
      return static_cast<const Derived *>(this)->getRV();
12✔
131
   } // should return in km/s, 0 means no radial velocity
132
   inline bool getPreciseAstrometricFlag() const
133
   {
134
      return static_cast<const Derived *>(this)->getPreciseAstrometricFlag();
135
   } // should only be true if full astrometric solution is available with getX2(), getDx2() too
136
   inline void getJ2000Pos(float dyrs, Vec3d & pos) const
×
137
   {
138
      // ideally whatever computation is done here should be done to get RA, DEC only
139
      // dont waste time computing other things because whoever calls this function dont need them
140
      if (getX2() != 0. ||
×
141
          getDx2() != 0.) { // as long as there is a 3rd component, we need to compute the full 3D position
×
142
         getEquatorialPos3D(dyrs, pos);
×
143
      } else {
144
         getEquatorialPos2D(dyrs, pos);
×
145
      }
146
   }
×
147
   // Special thanks to Anthony Brown's astrometry tutorial
148
   // This function only compute RA, DEC in rectangular coordinate system
149
   inline void getEquatorialPos3D(float dyrs, Vec3d & pos) const
×
150
   {
151
      double r0  = getX0();
×
152
      double r1  = getX1();
×
153
      double r2  = getX2();
×
154
      double pm0 = getDx0();
×
155
      double pm1 = getDx1();
×
156
      double pm2 = getDx2();
×
157
      double plx = getPlx();
×
158
      double vr  = getRV();
×
159
      Vec3d  r(r0, r1, r2);
×
160
      // proper motion
161
      Vec3d  pmvec0(pm0, pm1, pm2);
×
162
      pmvec0          = pmvec0 * MAS2RAD;
×
163
      double pmr0     = vr * plx / (AU / JYEAR_SECONDS) * MAS2RAD;
×
164
      double pmtotsqr = (pmvec0[0] * pmvec0[0] + pmvec0[1] * pmvec0[1] + pmvec0[2] * pmvec0[2]);
×
165

166
      double f        = 1. / sqrt(1. + 2. * pmr0 * dyrs + (pmtotsqr + pmr0 * pmr0) * dyrs * dyrs);
×
167
      Vec3d  u        = (r * (1. + pmr0 * dyrs) + pmvec0 * dyrs) * f;
×
168

169
      pos.set(u[0], u[1], u[2]);
×
170
   }
×
171
   inline void getEquatorialPos2D(float dyrs, Vec3d & pos) const
×
172
   {
173
      StelUtils::spheToRect(getX0() + dyrs * getDx0() * MAS2RAD, getX1() + dyrs * getDx1() * MAS2RAD, pos);
×
174
   }
×
175
   inline void getFull6DSolution(double & RA,
12✔
176
                                 double & DE,
177
                                 double & Plx,
178
                                 double & pmra,
179
                                 double & pmdec,
180
                                 double & RV,
181
                                 float    dyrs) const
182
   {
183
      if (getX2() != 0. || getDx2() != 0.) 
12✔
184
      {  // for star data type 0, have full astrometric solution
185
         // as long as there is a 3rd component, we need to compute the full 3D position using the equation below
186
         double r0  = getX0();
12✔
187
         double r1  = getX1();
12✔
188
         double r2  = getX2();
12✔
189
         double pm0 = getDx0();
12✔
190
         double pm1 = getDx1();
12✔
191
         double pm2 = getDx2();
12✔
192
         double plx = getPlx();
12✔
193
         double rv  = getRV();
12✔
194
         bool have_plx = plx != 0.;
12✔
195
         if (!have_plx)
12✔
196
            plx = 1.; // to avoid division by zero, any number will do
2✔
197
         Vec3d  r(r0, r1, r2);
12✔
198
         // proper motion
199
         Vec3d  pmvec0(pm0, pm1, pm2);
12✔
200
         pmvec0          = pmvec0 * MAS2RAD;
12✔
201
         double pmr0     = rv * plx / (AU / JYEAR_SECONDS) * MAS2RAD;
12✔
202
         double pmtotsqr = (pmvec0[0] * pmvec0[0] + pmvec0[1] * pmvec0[1] + pmvec0[2] * pmvec0[2]);
12✔
203

204
         double f2       = 1. / (1. + 2. * pmr0 * dyrs + (pmtotsqr + pmr0 * pmr0) * dyrs * dyrs);
12✔
205
         double f        = sqrt(f2);
12✔
206
         double f3       = f2 * f;
12✔
207
         Vec3d  u        = (r * (1. + pmr0 * dyrs) + pmvec0 * dyrs) * f;
12✔
208

209
         double Plx2   = plx * f;
12✔
210
         double pmr1   = (pmr0 + (pmtotsqr + pmr0 * pmr0) * dyrs) * f2;
12✔
211
         Vec3d  pmvec1 = pmvec0 * (1 + pmr0 * dyrs);
12✔
212

213
         pmvec1.set((pmvec1[0] - r[0] * pmtotsqr * dyrs) * f3,
12✔
214
                    (pmvec1[1] - r[1] * pmtotsqr * dyrs) * f3,
12✔
215
                    (pmvec1[2] - r[2] * pmtotsqr * dyrs) * f3);
12✔
216

217
         double xy = sqrt(u[0] * u[0] + u[1] * u[1]);
12✔
218
         Vec3d  p2(-u[1] / xy, u[0] / xy, 0.0);
12✔
219
         Vec3d  q2(-u[0] * u[2] / xy, -u[1] * u[2] / xy, xy);
12✔
220

221
         pmra = p2[0] * pmvec1[0] + p2[1] * pmvec1[1] + p2[2] * pmvec1[2];
12✔
222
         pmra /= MAS2RAD;
12✔
223
         pmdec = q2[0] * pmvec1[0] + q2[1] * pmvec1[1] + q2[2] * pmvec1[2];
12✔
224
         pmdec /= MAS2RAD;
12✔
225
         StelUtils::rectToSphe(&RA, &DE, u);
12✔
226
         if (RA < 0)
12✔
227
            RA += 2 * M_PI;
11✔
228
         if (have_plx)
12✔
229
            Plx = Plx2;
10✔
230
         else
231
            Plx = 0.;
2✔
232
         RV  = (pmr1 / MAS2RAD / Plx2) * (AU / JYEAR_SECONDS);
12✔
233
         return;
12✔
234
      }
235
      if (getDx1() != 0. || getDx2() != 0.)  // for star data type 1, have proper motion
×
236
      {
237
         DE    = getX1();
×
238
         pmra  = getDx0() * cos(DE);
×
239
         pmdec = getDx1();
×
240
         RA    = getX0() + dyrs * getDx0() * MAS2RAD;
×
241
         DE    = getX1() + dyrs * getDx1() * MAS2RAD;
×
242
         Plx   = getPlx();
×
243
         RV    = getRV();
×
244
         return;
×
245
      }
246
      else 
247
      {  // for star data type 2, have no proper motion
248
         RA    = getX0();
×
249
         DE    = getX1();
×
250
         Plx = 0.;
×
251
         RV = 0.;
×
252
         pmra = 0.;
×
253
         pmdec = 0.;
×
254
         return;
×
255
      }
256
   }
257

258
   //to get new 3D cartesian position for parallax effect given current star 3D cartesian position, planet orbital period and radius and current delta time from catalog epoch
259
   inline void getPlxEffect(double plx, Vec3d& bS, const Vec3d diffPos) const {
×
260
                if (plx <= 0.) return;
×
261
                bS *= 1000./ plx;
×
262
                bS += diffPos * MAS2RAD * 1000.;
×
263
   }
264

265
   inline void getBinaryOrbit(double epoch, Vec3d& v) const {
×
266
      double pmra = 0.;
×
267
      double pmdec = 0.;
×
268
      double rv = 0.;
×
269
      double plx = 0.;
×
270
      double ra = 0.;
×
271
      double dec = 0.;
×
272
      getBinaryOrbit(epoch, v, ra, dec, plx, pmra, pmdec, rv);
×
273
   }
×
274

275
   inline void getBinaryOrbit(double epoch, Vec3d& v, double& ra, double& dec, double& plx, double& pmra, double& pmdec, double& RV) const {
×
276
      double sep = 0.;
×
277
      double pa = 0.;
×
278
      getBinaryOrbit(epoch, v, ra, dec, plx, pmra, pmdec, RV, sep, pa);
×
279
   }
×
280

281
   inline void getBinaryOrbit(double epoch, Vec3d& v, double& ra, double& dec, double& plx, double& pmra, double& pmdec, double& RV, double& sep, double& pa) const {
×
282
      StarId star_id;  // star ID
283
      if (getGaia() == 0)
×
284
      {
285
         star_id = getHip();
×
286
      }
287
      else
288
      {
289
         star_id = getGaia();
×
290
      }
291

292
      // look up if hip is in the binary star map
293
      binaryorbitstar bso = StarMgr::getBinaryOrbitData(star_id);
×
294
      // check if bso is empty or not
295
      if (bso.hip == 0)
×
296
      {
297
         // exit the function because nothing to do, not a binary star
298
         return;
×
299
      }
300

301
      // Orbital elements of the secondary star
302
      double binary_period = bso.binary_period;  // Orbital period [days]
×
303
      float eccentricity = bso.eccentricity;  // Eccentricity
×
304
      float inclination = bso.inclination;  // Orbit inclination [rad]
×
305
      float big_omega = bso.big_omega;  // Position angle of ascending node [rad]
×
306
      float small_omega = bso.small_omega;  // Argument of periastron [rad]
×
307
      double periastron_epoch = bso.periastron_epoch;  // Julian Date at periastron passage
×
308
      double semi_major = bso.semi_major;  // Angular semi-major axis [arcsec]
×
309
      double bary_distance = bso.bary_distance;  // distance [parsec]
×
310
      double data_epoch = bso.data_epoch;  // Julian Date of the data
×
311
      double bary_ra = bso.bary_ra;  // Right Ascension of the barycenter [rad]
×
312
      double bary_dec = bso.bary_dec;  // Declination of the barycenter [rad]
×
313
      // motion of the barycenter
314
      double bary_rv = bso.bary_rv;  // Barycenter radial velocity [km/s]
×
315
      float primary_mass = bso.primary_mass;  // Primary star mass [solar mass]
×
316
      float secondary_mass = bso.secondary_mass;  // Secondary star mass [solar mass]
×
317
      double bary_pmra = bso.bary_pmra;  // Barycenter RA proper motion [mas/yr]
×
318
      double bary_pmdec = bso.bary_pmdec;  // Barycenter DEC proper motion [mas/yr]
×
319
      if (!data_epoch)
×
320
      {
321
         data_epoch = STAR_CATALOG_JDEPOCH;  // by default assume the date is the same as the catalog epoch
×
322
      }
323
      const double G = 4.49850215e-15;  // Gravitational constant in parsec^3 / (M_sun * yr^2)
×
324

325
      double dyrs = (epoch - data_epoch) / 365.25;
×
326
      semi_major = semi_major * bary_distance * MAS2RAD * 1000.;  // Convert to parsec
×
327
      double mass_ratio = secondary_mass / (primary_mass + secondary_mass);
×
328
      Vec3d bary_r;
×
329
      StelUtils::spheToRect(bary_ra, bary_dec, bary_r);  // barycenter position in equatorial cartesian coordinate
×
330

331
      // angular phase since periastron (at periastron_epoch)
332
      double ud = 2 * M_PI * (epoch - periastron_epoch) / binary_period;
×
333
      ud = fmod(ud, 2 * M_PI);  // warp u to [0, 2pi]
×
334
      
335
      // eccentric anomaly with newton's method
336
      double E = ud;
×
337
      // iterate until convergence or maximum iterations
338
      const int max_iterations = 100;
×
339
      const double tolerance = 1e-10;
×
340
      for (int j = 0; j < max_iterations; j++)
×
341
      {
342
         double delta = (E - eccentricity * sin(E) - ud) / (1 - eccentricity * cos(E));
×
343
         E = E - delta;
×
344
         if (fabs(delta) < tolerance)
×
345
         {
346
            break;
×
347
         }
348
      }
349

350
      // calculate true anomaly nu and bary_distance r
351
      double nu = 2 * atan(sqrt((1 + eccentricity) / (1 - eccentricity)) * tan(E / 2));
×
352
      double radius = semi_major * (1 - eccentricity * cos(E));  // in parsec
×
353
      Vec3d true_orbit(radius * cos(nu), radius * sin(nu), 0);  // all axis in parsec
×
354

355
      // Angular momentum per unit mass
356
      double h = sqrt(semi_major * (1 - eccentricity * eccentricity));
×
357
      double mu = G * (primary_mass + secondary_mass);
×
358
      double v_r = (1. / h) * eccentricity * sin(nu);  // radial velocity
×
359
      double v_theta = h / radius;  // Tangential velocity
×
360
      Vec3d true_orbit_vel(v_r * cos(nu) - v_theta * sin(nu), v_r * sin(nu) + v_theta * cos(nu), 0.);
×
361
      true_orbit_vel *= sqrt(mu);  // scale the velocity to physical units in parsec/yr
×
362

363
      // rotation matrix from true to sky plane
364
      Mat3d rot;
×
365
      rot.set(cos(big_omega) * cos(small_omega) - sin(big_omega) * sin(small_omega) * cos(inclination),
×
366
            -cos(big_omega) * sin(small_omega) - sin(big_omega) * cos(small_omega) * cos(inclination),
×
367
            sin(big_omega) * sin(inclination),
×
368
            sin(big_omega) * cos(small_omega) + cos(big_omega) * sin(small_omega) * cos(inclination),
×
369
            -sin(big_omega) * sin(small_omega) + cos(big_omega) * cos(small_omega) * cos(inclination),
×
370
            -cos(big_omega) * sin(inclination),
×
371
            sin(small_omega) * sin(inclination),
×
372
            cos(small_omega) * sin(inclination),
×
373
            cos(inclination));
374

375
      // to equatorial cartesian coordinate, similar to normal triad but with additional declination rotation
376
      Vec3d p(-sin(bary_ra), cos(bary_ra), 0.);
×
377
      Vec3d q(-sin(bary_dec) * cos(bary_ra), -sin(bary_dec) * sin(bary_ra), cos(bary_dec));
×
378
      Vec3d r(cos(bary_dec) * cos(bary_ra), cos(bary_dec) * sin(bary_ra), sin(bary_dec));
×
379

380
      // add the barycenter shift from proper motion
381
      Vec3d bary_pmvec0 = (p * bary_pmra + q * bary_pmdec) * MAS2RAD;
×
382
      double bary_pmr0 = bary_rv * (1000. / bary_distance) / (AU / JYEAR_SECONDS) * MAS2RAD;
×
383
      double bary_pmtotsqr = (bary_pmvec0[0] * bary_pmvec0[0] + bary_pmvec0[1] * bary_pmvec0[1] + bary_pmvec0[2] * bary_pmvec0[2]);
×
384
      double bary_f = 1. / sqrt(1. + 2. * bary_pmr0 * dyrs + (bary_pmtotsqr + bary_pmr0 * bary_pmr0) * dyrs * dyrs);
×
385
      Vec3d  bary_u = (bary_r * (1. + bary_pmr0 * dyrs) + bary_pmvec0 * dyrs) * bary_f;
×
386

387
      double xy = sqrt(bary_u[0] * bary_u[0] + bary_u[1] * bary_u[1]);
×
388
      Vec3d  p2(-bary_u[1] / xy, bary_u[0] / xy, 0.0);
×
389
      Vec3d  q2(-bary_u[0] * bary_u[2] / xy, -bary_u[1] * bary_u[2] / xy, xy);
×
390
      // to sky plane, all axis in parsec and parsec/yr
391
      Vec3d sky_orbit(0.);
×
392
      Vec3d sky_orbit_vel(0.);
×
393
      for (size_t i = 0; i < 3; ++i) {
×
394
         for (size_t j = 0; j < 3; ++j) {
×
395
               sky_orbit[i] += rot[i*3+j] * true_orbit[j];
×
396
               sky_orbit_vel[i] += rot[i*3+j] * true_orbit_vel[j];
×
397
         }
398
      }
399

400
      // swap the first two components of sky_orbit to match ra, dec axis
401
      double tmp = sky_orbit[0];
×
402
      sky_orbit[0] = sky_orbit[1];
×
403
      sky_orbit[1] = tmp;
×
404
      tmp = sky_orbit_vel[0];
×
405
      sky_orbit_vel[0] = sky_orbit_vel[1];
×
406
      sky_orbit_vel[1] = tmp;
×
407

408
      // compute on-sky separation and position angle
409
      sep = sqrt(sky_orbit[0] * sky_orbit[0] + sky_orbit[1] * sky_orbit[1]) / bary_distance / MAS2RAD / 1000.;  // in arcsecond
×
410
      pa = atan2(sky_orbit[0], sky_orbit[1]);
×
411
      if (pa < 0)
×
412
         pa += 2 * M_PI;
×
413

414
      if (bso.primary)
×
415
      {
416
         sky_orbit *= -mass_ratio;
×
417
         sky_orbit_vel *= -mass_ratio;
×
418
      }
419
      else
420
      {
421
         sky_orbit *= (1.0 - mass_ratio);
×
422
         sky_orbit_vel *= (1.0 - mass_ratio);
×
423
      }
424

425
      // sky_orbit is in parsec and sky_orbit_vel is in parsec/year, we want them arcsecond and arcsecond/year
426
      sky_orbit[0] /= bary_distance;
×
427
      sky_orbit[1] /= bary_distance;
×
428
      sky_orbit_vel *= 1.e-3 / MAS2RAD / bary_distance;
×
429

430
      // sky_orbit_vel is in arcsecond/year
431
      sky_orbit_vel.set(sky_orbit_vel[0] + bary_pmra / 1000., 
×
432
                        sky_orbit_vel[1] + bary_pmdec / 1000., 
×
433
                        sky_orbit_vel[2] + bary_rv * (JYEAR_SECONDS / AU) / bary_distance);
×
434

435
      sky_orbit_vel = p * sky_orbit_vel[0] + q * sky_orbit_vel[1] + r * sky_orbit_vel[2];  // arcsecond/year
×
436

437
      StelUtils::spheToRect(bary_ra + sky_orbit[0], 
×
438
                            bary_dec + sky_orbit[1], 
×
439
                            bary_distance + sky_orbit[2], 
×
440
                            sky_orbit);  // barycenter position in equatorial cartesian coordinate
441

442
      plx = 1000. / bary_distance * bary_f;
×
443
      RV  = sky_orbit_vel.dot(bary_u) * (1000./plx) * (AU / JYEAR_SECONDS);
×
444
      v = sky_orbit  - bary_r * bary_distance + bary_u * (1000. / plx);
×
445
      pmra = sky_orbit_vel.dot(p2) * 1000.;
×
446
      pmdec = sky_orbit_vel.dot(q2) * 1000.;
×
447
      StelUtils::rectToSphe(&ra, &dec, v);
×
448
   }
449
};
450

451
struct Star1 : public Star<Star1>
452
{
453
private:
454
   struct Data
455
   {
456
      qint64  gaia_id; // 8 bytes
457
      qint32  x0;      // 4 bytes, internal astrometric unit
458
      qint32  x1;      // 4 bytes, internal astrometric unit
459
      qint32  x2;      // 4 bytes, internal astrometric unit
460
      qint32  dx0;     // 4 bytes, uas/yr
461
      qint32  dx1;     // 4 bytes, uas/yr
462
      qint32  dx2;     // 4 bytes, uas/yr
463
      qint16  b_v;     // 2 bytea, B-V in milli-mag
464
      qint16  vmag;    // 2 bytes, V magnitude in milli-mag
465
      quint16 plx;     // 2 bytes, parallax in 20 uas
466
      quint16 plx_err; // 2 bytes, parallax error in 10 uas
467
      qint16  rv;      // 2 bytes, radial velocity in 100 m/s
468
      quint16 spInt;   // 2 bytes
469
      quint8  objtype; // 1 byte
470
      quint8  hip[3];  // 3 bytes, HIP number combined with component ID (A, B, ...)
471
   } d;
472

473
public:
474
   StelObjectP   createStelObject(const SpecialZoneArray<Star1> * a, const SpecialZoneData<Star1> * z) const;
475
   inline int    getMag() const { return d.vmag; } // in milli-mag
×
476
   inline int    getSpInt() const { return d.spInt; }
×
477
   inline double getX0() const { return d.x0 / 2.e9; }
12✔
478
   inline double getX1() const { return d.x1 / 2.e9; }
12✔
479
   inline double getX2() const { return d.x2 / 2.e9; }
24✔
480
   inline double getDx0() const { return d.dx0 / 1000.; }
12✔
481
   inline double getDx1() const { return d.dx1 / 1000.; }
12✔
482
   inline double getDx2() const { return d.dx2 / 1000.; }
12✔
483
   inline double getPlx() const { return d.plx * 0.02; }
12✔
484
   inline double getPlxErr() const { return d.plx_err / 100.; }
×
485
   inline double getPMTotal() const
×
486
   {
487
      // need to go through the calculation to get pmra and pmdec, use dyr = 0
488
      double RA, DE, Plx, pmra, pmdec, RV;
489
      getFull6DSolution(RA, DE, Plx, pmra, pmdec, RV, 0.);
×
490
      return sqrt(pmra * pmra + pmdec * pmdec);
×
491
   }
492
   inline double getRV() const { return d.rv / 10.; }
12✔
493
   inline bool   getPreciseAstrometricFlag() const
×
494
   {
495
      // Flag if the star should have time dependent astrometry computed
496
      // the star need to has parallax, proper motion, or radial velocity
497
      // use OR in each in case one of them is actually exactly 0
498
      // no point of doing proper propagation if any of them is missing
499
      return (getPlx() || getPlxErr()) && (getPlx() / getPlxErr() > 5) && (getDx0() || getDx1() || getDx2()) && getRV();
×
500
   }
501
   inline StarId getHip() const
×
502
   {
503
      // Combine the 3 bytes into a 24-bit integer (little-endian)
504
      quint32 combined_value = d.hip[0] | d.hip[1] << 8 | d.hip[2] << 16;
×
505
      // Extract the 17-bit ID (shift right by 5 bits)
506
      quint64  hip_id         = combined_value >> 5;
×
507
      return hip_id;
×
508
   }
509

510
   inline StarId  getGaia() const { return d.gaia_id; }
907,474✔
511
   inline int     getComponentIds() const
×
512
   {
513
      // Combine the 3 bytes into a 24-bit integer (little-endian)
514
      quint32 combined_value = d.hip[0] | d.hip[1] << 8 | d.hip[2] << 16;
×
515
      // Extract the 5-bit component ID
516
      quint8  letter_value   = combined_value & 0x1F; // 0x1F = 00011111 in binary mask
×
517
      return letter_value;
×
518
   }
519
   inline int getObjType() const { return d.objtype; }
×
520
   float      getBV(void) const { return static_cast<float>(d.b_v) / 1000.f; }
×
521
   bool       isVIP() const { return true; }
×
522
   bool       hasName() const { return getHip(); } // OR gaia??
×
523
   QString    getNameI18n(void) const;
524
   //! Retrieve the cultural screen label, translated version of the commonName (if withCommonNameI18n), or a designation.
525
   QString    getScreenNameI18n(const bool withCommonNameI18n) const;
526
   QString    getDesignation(void) const;
527
   int        hasComponentID(void) const;
528
};
529
static_assert(sizeof(Star1) == 48, "Size of Star1 must be 48 bytes");
530

531
struct Star2 : public Star<Star2>
532
{
533
private:
534
   struct Data
535
   {
536
      qint64  gaia_id; // 8 bytes
537
      qint32  x0;      // 4 bytes, RA in mas
538
      qint32  x1;      // 4 bytes, DEC in mas
539
      qint32  dx0;     // 4 bytes, pmra in uas/yr
540
      qint32  dx1;     // 4 bytes, pmdec in uas/yr
541
      qint16  b_v;     // 2 byte
542
      qint16  vmag;    // 2 bytes
543
      quint16 plx;     // 2 bytes, parallax in 10 uas
544
      quint16 plx_err; // 2 bytes, parallax error in 10 uas
545
   } d;
546

547
public:
548
   inline double getX0() const { return d.x0 * MAS2RAD; }
×
549
   inline double getX1() const { return d.x1 * MAS2RAD; }
×
550
   inline double getX2() const { return 0; }
×
551
   inline double getDx0() const { return d.dx0 / 1000.; }
×
552
   inline double getDx1() const { return d.dx1 / 1000.; }
×
553
   inline double getDx2() const { return 0.; }
×
UNCOV
554
   inline int    getMag() const { return d.vmag; } // in milli-mag
×
555
   inline double getPMTotal() const
556
   {
557
      return sqrt((getDx0() * cos(getX1()) * getDx0() * cos(getX1())) + (getDx1() * getDx1()));
558
   }
559
   StelObjectP    createStelObject(const SpecialZoneArray<Star2> * a, const SpecialZoneData<Star2> * z) const;
560
   StarId         getHip() const { return 0; }
×
561
   StarId         getGaia() const { return d.gaia_id; }
×
562
   float          getBV(void) const { return static_cast<float>(d.b_v) / 1000.f; }
×
563
   QString        getNameI18n(void) const { return QString(); }
×
UNCOV
564
   QString        getScreenNameI18n(const bool) const { return QString(); }
×
565
   QString        getDesignation(void) const { return QString(); }
566
   int            hasComponentID(void) const { return 0; }
×
567
   bool           isVIP() const { return false; }
×
568
   bool           hasName() const { return getGaia() != 0; }
×
569
   double         getPlx() const { return d.plx / 100.; }
×
570
   double         getPlxErr() const { return d.plx_err / 100.; }
×
571
   double         getRV() const { return 0.; }
×
UNCOV
572
   bool           getPreciseAstrometricFlag() const
×
573
   { // Flag if the star should have time dependent astrometry computed
UNCOV
574
      return false;
×
575
   }
576
   void print(void) const;
577
};
578
static_assert(sizeof(Star2) == 32, "Size of Star2 must be 32 bytes");
579

580
struct Star3 : public Star<Star3>
581
{
582
private:
583
   struct Data
584
   {
585
      qint64 gaia_id; // 8 bytes
586
      quint8 x0[3];   // 3 bytes, RA in 0.1 arcsecond
587
      quint8 x1[3];   // 3 bytes, DEC in 0.1 arcsecond (offset by +90 degree)
588
      quint8 b_v;     // 1 byte, B-V in 0.05 mag
589
      quint8 vmag;    // 1 bytes, V magnitude in 0.02 mag (offset by -16 mag)
590
   } d;
591

592
public:
593
   StelObjectP   createStelObject(const SpecialZoneArray<Star3> * a, const SpecialZoneData<Star3> * z) const;
UNCOV
594
   inline double getX0() const
×
595
   {
596
      quint32 x0 = d.x0[0] | (d.x0[1] << 8) | (d.x0[2] << 16);
×
UNCOV
597
      return static_cast<double>(x0) * 100. * MAS2RAD;
×
598
   }
UNCOV
599
   inline double getX1() const
×
600
   {
601
      quint32 x1 = d.x1[0] | (d.x1[1] << 8) | (d.x1[2] << 16);
×
UNCOV
602
      return (static_cast<double>(x1) - (90. * 36000.)) * 100. * MAS2RAD;
×
603
   }
604
   inline double  getX2() const { return 0.; }
×
605
   inline double  getDx0() const { return 0.; }
×
606
   inline double  getDx1() const { return 0.; }
×
UNCOV
607
   inline double  getDx2() const { return 0.; }
×
608
   inline double  getPMTotal() const { return 0.; }
UNCOV
609
   double         getPlx() const { return 0.; }
×
610
   double         getPlxErr() const { return 0.; }
611
   double         getRV() const { return 0.; }
×
612
   double         getBV() const { return (0.025 * d.b_v) - 1.; } // in mag
×
613
   double         getMag() const { return d.vmag * 20 + 16000; } // in milli-mag
×
614
   StarId         getHip() const { return 0; }
×
615
   StarId         getGaia() const { return d.gaia_id; }
×
616
   QString        getNameI18n() const { return QString(); }
×
UNCOV
617
   QString        getScreenNameI18n(const bool) const { return QString(); }
×
618
   QString        getDesignation() const { return QString(); }
619
   bool           isVIP() const { return false; }
×
620
   int            hasComponentID() const { return 0; }
×
621
   bool           hasName() const { return d.gaia_id != 0; }
×
UNCOV
622
   bool           getPreciseAstrometricFlag() const
×
623
   { // Flag if the star should have time dependent astrometry computed
UNCOV
624
      return false;
×
625
   }
626
};
627
static_assert(sizeof(Star3) == 16, "Size of Star3 must be 16 bytes");
628

629
#endif // STAR_HPP
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc