star.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:32k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // star.cpp
  2. //
  3. // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include <celmath/mathlib.h>
  10. #include <cstring>
  11. #include <cassert>
  12. #include "celestia.h"
  13. #include "astro.h"
  14. #include "orbit.h"
  15. #include "star.h"
  16. #include "texmanager.h"
  17. using namespace std;
  18. // The value of the temperature of the sun is actually 5780, but the
  19. // stellar class tables list the temperature of a G2V star as 5860.  We
  20. // use the latter value so that the radius of the sun is computed correctly
  21. // as one times SOLAR_RADIUS . . .  the high metallicity of the Sun is
  22. // probably what accounts for the discrepancy in temperature.
  23. // #define SOLAR_TEMPERATURE    5780.0f
  24. #define SOLAR_TEMPERATURE    5860.0f
  25. #define SOLAR_RADIUS         696000
  26. struct SpectralTypeInfo
  27. {
  28.     char* name;
  29.     float temperature;
  30.     float rotationPeriod;
  31. };
  32. static StarDetails** normalStarDetails = NULL;
  33. static StarDetails** whiteDwarfDetails = NULL;
  34. static StarDetails*  neutronStarDetails = NULL;
  35. static StarDetails*  blackHoleDetails = NULL;
  36. static StarDetails*  barycenterDetails = NULL;
  37. static string DEFAULT_INFO_URL("");
  38. StarDetails::StarTextureSet StarDetails::starTextures;
  39. // Star temperature data from Lang's _Astrophysical Data: Planets and Stars_
  40. // Temperatures from missing (and typically not used) types in those
  41. // tables were just interpolated.
  42. static float tempO[3][10] =
  43. {
  44.     { 52500, 52500, 52500, 52500, 48000, 44500, 41000, 38000, 35800, 33000 },
  45.     { 50000, 50000, 50000, 50000, 45500, 42500, 39500, 37000, 34700, 32000 },
  46.     { 47300, 47300, 47300, 47300, 44100, 42500, 39500, 37000, 34700, 32000 },
  47. };
  48. static float tempB[3][10] =
  49. {
  50.     { 30000, 25400, 22000, 18700, 17000, 15400, 14000, 13000, 11900, 10500 },
  51.     { 29000, 24000, 20300, 17100, 16000, 15000, 14100, 13200, 12400, 11000 },
  52.     { 26000, 20800, 18500, 16200, 15100, 13600, 13000, 12200, 11200, 10300 },
  53. };
  54. static float tempA[3][10] =
  55. {
  56.     {  9520, 9230, 8970, 8720, 8460, 8200, 8020, 7850, 7580, 7390 },
  57.     { 10100, 9480, 9000, 8600, 8300, 8100, 7850, 7650, 7450, 7250 },
  58.     {  9730, 9230, 9080, 8770, 8610, 8510, 8310, 8150, 7950, 7800 },
  59. };
  60. static float tempF[3][10] =
  61. {
  62.     { 7200, 7050, 6890, 6740, 6590, 6440, 6360, 6280, 6200, 6110 },
  63.     { 7150, 7000, 6870, 6720, 6570, 6470, 6350, 6250, 6150, 6080 },
  64.     { 7700, 7500, 7350, 7150, 7000, 6900, 6500, 6300, 6100, 5800 },
  65. };
  66. static float tempG[3][10] =
  67. {
  68.     { 6030, 5940, 5860, 5830, 5800, 5770, 5700, 5630, 5570, 5410 },
  69.     { 5850, 5650, 5450, 5350, 5250, 5150, 5050, 5070, 4900, 4820 },
  70.     { 5550, 5350, 5200, 5050, 4950, 4850, 4750, 4660, 4600, 4500 },
  71. };
  72. static float tempK[3][10] =
  73. {
  74.     { 5250, 5080, 4900, 4730, 4590, 4350, 4200, 4060, 3990, 3920 },
  75.     { 4750, 4600, 4420, 4200, 4000, 3950, 3900, 3850, 3830, 3810 },
  76.     { 4420, 4330, 4250, 4080, 3950, 3850, 3760, 3700, 3680, 3660 },
  77. };
  78. static float tempM[3][10] =
  79. {
  80.     { 3850, 3720, 3580, 3470, 3370, 3240, 3050, 2940, 2640, 2000 },
  81.     { 3800, 3720, 3620, 3530, 3430, 3330, 3240, 3240, 3240, 3240 },
  82.     { 3650, 3550, 3450, 3200, 2980, 2800, 2600, 2600, 2600, 2600 },
  83. };
  84. // Wolf-Rayet temperatures.  From Lang's Astrophysical Data: Planets and
  85. // Stars.
  86. static float tempWN[10] =
  87. {
  88.     50000, 50000, 50000, 50000, 47000, 43000, 39000, 32000, 29000, 29000
  89. };
  90. static float tempWC[10] =
  91. {
  92.     60000, 60000, 60000, 60000, 60000, 60000, 60000, 54000, 46000, 38000
  93. };
  94. // Brown dwarf temperatures
  95. static float tempL[10] =
  96. {
  97.     1960, 1930, 1900, 1850, 1800, 1740, 1680, 1620, 1560, 1500
  98. };
  99. static float tempT[10] =
  100. {
  101.     1425, 1350, 1275, 1200, 1140, 1080, 1020, 900, 800, 750
  102. };
  103. // White dwarf temperaturs
  104. static float tempWD[10] =
  105. {
  106.     100000.0f, 50400.0f, 25200.0f, 16800.0f, 12600.0f,
  107.     10080.0f, 8400.0f, 7200.0f, 6300.0f, 5600.0f,
  108. };
  109. // Tables with adjustments for estimating absolute bolometric magnitude from
  110. // visual magnitude, from Lang's "Astrophysical Data: Planets and Stars".
  111. // Gaps in the tables from unused spectral classes were filled in with linear
  112. // interpolation--not accurate, but these shouldn't appear in real catalog
  113. // data anyway.
  114. static float bmag_correctionO[3][10] =
  115. {
  116.     // Lum class V (main sequence)
  117.     {
  118.         -4.75f, -4.75f, -4.75f, -4.75f, -4.45f,
  119.         -4.40f, -3.93f, -3.68f, -3.54f, -3.33f,
  120.     },
  121.     // Lum class III
  122.     {
  123.         -4.58f, -4.58f, -4.58f, -4.58f, -4.28f,
  124.         -4.05f, -3.80f, -3.58f, -3.39f, -3.13f,
  125.     },
  126.     // Lum class I
  127.     {
  128.         -4.41f, -4.41f, -4.41f, -4.41f, -4.17f,
  129.         -3.87f, -3.74f, -3.48f, -3.35f, -3.18f,
  130.     }
  131. };
  132. static float bmag_correctionB[3][10] =
  133. {
  134.     // Lum class V (main sequence)
  135.     {
  136.         -3.16f, -2.70f, -2.35f, -1.94f, -1.70f,
  137.         -1.46f, -1.21f, -1.02f, -0.80f, -0.51f,
  138.     },
  139.     // Lum class III
  140.     {
  141.         -2.88f, -2.43f, -2.02f, -1.60f, -1.45f,
  142.         -1.30f, -1.13f, -0.97f, -0.82f, -0.71f,
  143.     },
  144.     // Lum class I
  145.     {
  146.         -2.49f, -1.87f, -1.58f, -1.26f, -1.11f,
  147.         -0.95f, -0.88f, -0.78f, -0.66f, -0.52f,
  148.     }
  149. };
  150. static float bmag_correctionA[3][10] =
  151. {
  152.     // Lum class V (main sequence)
  153.     {
  154.         -0.30f, -0.23f, -0.20f, -0.17f, -0.16f,
  155.         -0.15f, -0.13f, -0.12f, -0.10f, -0.09f,
  156.     },
  157.     // Lum class III
  158.     {
  159.         -0.42f, -0.29f, -0.20f, -0.17f, -0.15f,
  160.         -0.14f, -0.12f, -0.10f, -0.10f, -0.10f,
  161.     },
  162.     // Lum class I
  163.     {
  164.         -0.41f, -0.32f, -0.28f, -0.21f, -0.17f,
  165.         -0.13f, -0.09f, -0.06f, -0.03f, -0.02f,
  166.     }
  167. };
  168. static float bmag_correctionF[3][10] =
  169. {
  170.     // Lum class V (main sequence)
  171.     {
  172.         -0.09f, -0.10f, -0.11f, -0.12f, -0.13f,
  173.         -0.14f, -0.14f, -0.15f, -0.16f, -0.17f,
  174.     },
  175.     // Lum class III
  176.     {
  177.         -0.11f, -0.11f, -0.11f, -0.12f, -0.13f,
  178.         -0.13f, -0.15f, -0.15f, -0.16f, -0.18f,
  179.     },
  180.     // Lum class I
  181.     {
  182.         -0.01f,  0.00f,  0.00f, -0.01f, -0.02f,
  183.         -0.03f, -0.05f, -0.07f, -0.09f, -0.12f,
  184.     }
  185. };
  186. static float bmag_correctionG[3][10] =
  187. {
  188.     // Lum class V (main sequence)
  189.     {
  190.         -0.18f, -0.19f, -0.20f, -0.20f, -0.21f,
  191.         -0.21f, -0.27f, -0.33f, -0.40f, -0.36f,
  192.     },
  193.     // Lum class III
  194.     {
  195.         -0.20f, -0.24f, -0.27f, -0.29f, -0.32f,
  196.         -0.34f, -0.37f, -0.40f, -0.42f, -0.46f,
  197.     },
  198.     // Lum class I
  199.     {
  200.         -0.15f, -0.18f, -0.21f, -0.25f, -0.29f,
  201.         -0.33f, -0.36f, -0.39f, -0.42f, -0.46f,
  202.     }
  203. };
  204. static float bmag_correctionK[3][10] =
  205. {
  206.     // Lum class V (main sequence)
  207.     {
  208.         -0.31f, -0.37f, -0.42f, -0.50f, -0.55f,
  209.         -0.72f, -0.89f, -1.01f, -1.13f, -1.26f,
  210.     },
  211.     // Lum class III
  212.     {
  213.         -0.50f, -0.55f, -0.61f, -0.76f, -0.94f,
  214.         -1.02f, -1.09f, -1.17f, -1.20f, -1.22f,
  215.     },
  216.     // Lum class I
  217.     {
  218.         -0.50f, -0.56f, -0.61f, -0.75f, -0.90f,
  219.         -1.01f, -1.10f, -1.20f, -1.23f, -1.26f,
  220.     }
  221. };
  222. static float bmag_correctionM[3][10] =
  223. {
  224.     // Lum class V (main sequence)
  225.     {
  226.         -1.38f, -1.62f, -1.89f, -2.15f, -2.38f,
  227.         -2.73f, -3.21f, -3.46f, -4.10f, -4.40f,
  228.     },
  229.     // Lum class III
  230.     {
  231.         -1.25f, -1.44f, -1.62f, -1.87f, -2.22f,
  232.         -2.48f, -2.73f, -2.73f, -2.73f, -2.73f,
  233.     },
  234.     // Lum class I
  235.     {
  236.         -1.29f, -1.38f, -1.62f, -2.13f, -2.75f,
  237.         -3.47f, -3.90f, -3.90f, -3.90f, -3.90f,
  238.     }
  239. };
  240. // Brown dwarf data from Grant Hutchison
  241. static float bmag_correctionL[10] =
  242. {
  243.     -4.6f, -4.9f, -5.0f, -5.2f, -5.4f, -5.9f, -6.1f, -6.7f, -7.4f, -8.2f,
  244. };
  245. static float bmag_correctionT[10] =
  246. {
  247.     -8.9f, -9.6f, -10.8f, -11.9f, -13.1f, -14.4f, -16.1f, -17.9f, -19.6f, -19.6f,
  248. };
  249. // White dwarf data from Grant Hutchison; value for hypothetical
  250. // 0 subclass is just duplicated from subclass 1.
  251. static float bmag_correctionWD[10] =
  252. {
  253.     -4.15f, -4.15f, -2.22f, -1.24f, -0.67f,
  254.     -0.32f, -0.13f, -0.04f, -0.03f, -0.09f,
  255. };
  256. // Stellar rotation by spectral and luminosity class.
  257. // Tables from Grant Hutchison:
  258. // "Most data are from Lang's _Astrophysical Data: Planets and Stars_ (I
  259. // calculated from theoretical radii and observed rotation velocities), but
  260. // with some additional information gleaned from elsewhere.
  261. // A big scatter in rotation periods, of course, particularly in the K and
  262. // early M dwarfs. I'm not hugely happy with the supergiant and giant rotation
  263. // periods for K and M, either - they may be considerably slower yet, but it's
  264. // obviously difficult to come by the data when the rotation velocity is too
  265. // slow to obviously affect the spectra."
  266. //
  267. // I add missing values by interpolating linearly--certainly not the best
  268. // technique, but adequate for our purposes.  The rotation rate of the Sun
  269. // was used for spectral class G2.
  270. static float rotperiod_O[3][10] =
  271. {
  272.     { 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f },
  273.     { 6.3f, 6.3f, 6.3f, 6.3f, 6.3f, 6.3f, 6.3f, 6.3f, 6.3f, 6.3f },
  274.     { 15.0f, 15.0f, 15.0f, 15.0f, 15.0f, 15.0f, 15.0f, 15.0f, 15.0f, 15.0f },
  275. };
  276. static float rotperiod_B[3][10] =
  277. {
  278.     { 2.0f, 1.8f, 1.6f, 1.4f, 1.1f, 0.8f, 0.8f, 0.8f, 0.8f, 0.7f },
  279.     { 6.3f, 5.6f, 5.0f, 4.3f, 3.7f, 3.1f, 2.9f, 2.8f, 2.7f, 2.6f },
  280.     { 15.0f, 24.0f, 33.0f, 42.0f, 52.0f, 63.0f, 65.0f, 67.0f, 70.0f, 72.0f },
  281. };
  282. static float rotperiod_A[3][10] =
  283. {
  284.     { 0.7f, 0.7f, 0.6f, 0.6f, 0.5f, 0.5f, 0.5f, 0.6f, 0.6f, 0.7f },
  285.     { 2.5f, 2.3f, 2.1f, 1.9f, 1.7f, 1.6f, 1.6f, 1.7f, 1.7f, 1.8f },
  286.     { 75.0f, 77.0f, 80.0f, 82.0f, 85.0f, 87.0f, 95.0f, 104.0f, 115.0f, 125.0f },
  287. };
  288. static float rotperiod_F[3][10] =
  289. {
  290.     { 0.7f, 0.7f, 0.6f, 0.6f, 0.5f, 0.5f, 0.5f, 0.6f, 0.6f, 0.7f },
  291.     { 1.9f, 2.5f, 3.0f, 3.5f, 4.0f, 4.6f, 5.6f, 6.7f, 7.8f, 8.9f },
  292.     { 135.0f, 141.0f, 148.0f, 155.0f, 162.0f, 169.0f, 175.0f, 182.0f, 188.0f, 195.0f },
  293. };
  294. static float rotperiod_G[3][10] =
  295. {
  296.     { 11.1f, 18.2f, 25.4f, 24.7f, 24.0f, 23.3f, 23.0f, 22.7f, 22.3f, 21.9f },
  297.     { 10.0f, 13.0f, 16.0f, 19.0f, 22.0f, 25.0f, 28.0f, 31.0f, 33.0f, 35.0f },
  298.     { 202.0f, 222.0f, 242.0f, 262.0f, 282.0f,
  299.       303.0f, 323.0f, 343.0f, 364.0f, 384.0f },
  300. };
  301. static float rotperiod_K[3][10] =
  302. {
  303.     { 21.5f, 20.8f, 20.2f, 19.4f, 18.8f, 18.2f, 17.6f, 17.0f, 16.4f, 15.8f },
  304.     { 38.0f, 43.0f, 48.0f, 53.0f, 58.0f, 63.0f, 71.0f, 78.0f, 86.0f, 93.0f },
  305.     { 405.0f, 526.0f, 648.0f, 769.0f, 891.0f,
  306.       1012.0f, 1063.0f, 1103.0f, 1154.0f, 1204.0f },
  307. };
  308. static float rotperiod_M[3][10] =
  309. {
  310.     { 15.2f, 12.4f, 9.6f, 6.8f, 4.0f, 1.3f, 1.0f, 0.7f, 0.4f, 0.2f },
  311.     { 101.0f, 101.0f, 101.0f, 101.0f, 101.0f, 101.0f, 101.0f, 101.0f, 101.0f, 101.0f },
  312.     { 1265.0f, 1265.0f, 1265.0f, 1265.0f, 1265.0f,
  313.       1265.0f, 1265.0f, 1265.0f, 1265.0f, 1265.0f },
  314. };
  315. const char* LumClassNames[StellarClass::Lum_Count] = {
  316.     "I-a0", "I-a", "I-b", "II", "III", "IV", "V", "VI", ""
  317. };
  318. const char* SubclassNames[11] = {
  319.     "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ""
  320. };
  321. const char* SpectralClassNames[StellarClass::NormalClassCount] = {
  322.     "O", "B", "A", "F", "G", "K", "M", "R",
  323.     "S", "N", "WC", "WN", "?", "L", "T", "C",
  324. };
  325. const char* WDSpectralClassNames[StellarClass::WDClassCount] = {
  326.     "DA", "DB", "DC", "DO", "DQ", "DZ", "D", "DX",
  327. };
  328. StarDetails*
  329. StarDetails::GetStarDetails(const StellarClass& sc)
  330. {
  331.     switch (sc.getStarType())
  332.     {
  333.     case StellarClass::NormalStar:
  334.         return GetNormalStarDetails(sc.getSpectralClass(),
  335.                                     sc.getSubclass(),
  336.                                     sc.getLuminosityClass());
  337.     case StellarClass::WhiteDwarf:
  338.         return GetWhiteDwarfDetails(sc.getSpectralClass(),
  339.                                     sc.getSubclass());
  340.     case StellarClass::NeutronStar:
  341.         return GetNeutronStarDetails();
  342.     case StellarClass::BlackHole:
  343.         return GetBlackHoleDetails();
  344.     default:
  345.         return NULL;
  346.     }
  347. }
  348. StarDetails*
  349. StarDetails::CreateStandardStarType(const std::string& specTypeName,
  350.                                     float _temperature,
  351.                                     float _rotationPeriod)
  352. {
  353.     StarDetails* details = new StarDetails();
  354.     details->setTemperature(_temperature);
  355.     details->setSpectralType(specTypeName);
  356.     details->setRotationModel(new UniformRotationModel(_rotationPeriod,
  357.                                                        0.0f,
  358.                                                        astro::J2000,
  359.                                                        0.0f,
  360.                                                        0.0f));
  361.     return details;
  362. }
  363. StarDetails*
  364. StarDetails::GetNormalStarDetails(StellarClass::SpectralClass specClass,
  365.                                   unsigned int subclass,
  366.                                   StellarClass::LuminosityClass lumClass)
  367. {
  368.     if (normalStarDetails == NULL)
  369.     {
  370.         unsigned int nTypes = StellarClass::Spectral_Count * 11 *
  371.             StellarClass::Lum_Count;
  372.         normalStarDetails = new StarDetails*[nTypes];
  373.         for (unsigned int i = 0; i < nTypes; i++)
  374.             normalStarDetails[i] = NULL;
  375.     }
  376.     if (subclass > StellarClass::Subclass_Unknown)
  377.         subclass = StellarClass::Subclass_Unknown;
  378.     uint index = subclass + (specClass + lumClass * StellarClass::Spectral_Count) * 11;
  379.     if (normalStarDetails[index] == NULL)
  380.     {
  381.         char name[16];
  382.         if ((lumClass == StellarClass::Lum_VI) &&
  383.             (specClass >= StellarClass::Spectral_O) && (specClass <= StellarClass::Spectral_A))
  384.         {
  385.             // Hot subdwarfs are prefixed with "sd", while cool subdwarfs use
  386.             // luminosity class VI, per recommendations in arXiv:0805.2567v1
  387.             sprintf(name, "sd%s%s",
  388.                     SpectralClassNames[specClass],
  389.                     SubclassNames[subclass]);
  390.         }
  391.         else
  392.         {
  393.             sprintf(name, "%s%s%s",
  394.                     SpectralClassNames[specClass],
  395.                     SubclassNames[subclass],
  396.                     LumClassNames[lumClass]);
  397.         }
  398.         
  399.         // Use the same properties for an unknown subclass as for subclass 5
  400.         if (subclass == StellarClass::Subclass_Unknown)
  401.         {
  402.             // Since early O and Wolf-Rayet stars are exceedingly rare,
  403.             // use temperature of the more common late types when the subclass
  404.             // is unspecified in the spectral type.  For other stars, default
  405.             // to subclass 5.
  406.             switch (specClass)
  407.             {
  408.             case StellarClass::Spectral_O:
  409.             case StellarClass::Spectral_WN:
  410.             case StellarClass::Spectral_WC:
  411.                 subclass = 9;
  412.                 break;
  413.             default:
  414.                 subclass = 5;
  415.                 break;
  416.             }
  417.         }
  418.         unsigned int lumIndex = 0;
  419.         switch (lumClass)
  420.         {
  421.         case StellarClass::Lum_Ia0:
  422.         case StellarClass::Lum_Ia:
  423.         case StellarClass::Lum_Ib:
  424.         case StellarClass::Lum_II:
  425.             lumIndex = 2;
  426.             break;
  427.         case StellarClass::Lum_III:
  428.         case StellarClass::Lum_IV:
  429.             lumIndex = 1;
  430.             break;
  431.         case StellarClass::Lum_V:
  432.         case StellarClass::Lum_VI:
  433.         case StellarClass::Lum_Unknown:
  434.             lumIndex = 0;
  435.             break;
  436.         default: break;  // Do nothing, but prevent GCC4 warnings (Beware: potentially dangerous)
  437.         }
  438.         float temp = 0.0f;
  439.         switch (specClass)
  440.         {
  441.         case StellarClass::Spectral_O:
  442.             temp = tempO[lumIndex][subclass];
  443.             break;
  444.         case StellarClass::Spectral_B:
  445.             temp = tempB[lumIndex][subclass];
  446.             break;
  447.         case StellarClass::Spectral_Unknown:
  448.         case StellarClass::Spectral_A:
  449.             temp = tempA[lumIndex][subclass];
  450.             break;
  451.         case StellarClass::Spectral_F:
  452.             temp = tempF[lumIndex][subclass];
  453.             break;
  454.         case StellarClass::Spectral_G:
  455.             temp = tempG[lumIndex][subclass];
  456.             break;
  457.         case StellarClass::Spectral_K:
  458.             temp = tempK[lumIndex][subclass];
  459.             break;
  460.         case StellarClass::Spectral_M:
  461.             temp = tempM[lumIndex][subclass];
  462.             break;
  463.         case StellarClass::Spectral_R:
  464.             temp = tempK[lumIndex][subclass];
  465.             break;
  466.         case StellarClass::Spectral_S:
  467.             temp = tempM[lumIndex][subclass];
  468.             break;
  469.         case StellarClass::Spectral_N:
  470.             temp = tempM[lumIndex][subclass];
  471.             break;
  472.         case StellarClass::Spectral_C:
  473.             temp = tempM[lumIndex][subclass];
  474.             break;
  475.         case StellarClass::Spectral_WN:
  476.             temp = tempWN[subclass];
  477.             break;
  478.         case StellarClass::Spectral_WC:
  479.             temp = tempWC[subclass];
  480.             break;
  481.         case StellarClass::Spectral_L:
  482.             temp = tempL[subclass];
  483.             break;
  484.         case StellarClass::Spectral_T:
  485.             temp = tempT[subclass];
  486.             break;
  487.         default: break;  // Do nothing, but prevent GCC4 warnings (Beware: potentially dangerous)
  488.         }
  489.         float bmagCorrection = 0.0f;
  490.         float period = 1.0f;
  491.         switch (specClass)
  492.         {
  493.         case StellarClass::Spectral_O:
  494.             period = rotperiod_O[lumIndex][subclass];
  495.             bmagCorrection = bmag_correctionO[lumIndex][subclass];
  496.             break;
  497.         case StellarClass::Spectral_B:
  498.             period = rotperiod_B[lumIndex][subclass];
  499.             bmagCorrection = bmag_correctionB[lumIndex][subclass];
  500.             break;
  501.         case StellarClass::Spectral_Unknown:
  502.         case StellarClass::Spectral_A:
  503.             period = rotperiod_A[lumIndex][subclass];
  504.             bmagCorrection = bmag_correctionA[lumIndex][subclass];
  505.             break;
  506.         case StellarClass::Spectral_F:
  507.             period = rotperiod_F[lumIndex][subclass];
  508.             bmagCorrection = bmag_correctionF[lumIndex][subclass];
  509.             break;
  510.         case StellarClass::Spectral_G:
  511.             period = rotperiod_G[lumIndex][subclass];
  512.             bmagCorrection = bmag_correctionG[lumIndex][subclass];
  513.             break;
  514.         case StellarClass::Spectral_K:
  515.             period = rotperiod_K[lumIndex][subclass];
  516.             bmagCorrection = bmag_correctionK[lumIndex][subclass];
  517.             break;
  518.         case StellarClass::Spectral_M:
  519.             period = rotperiod_M[lumIndex][subclass];
  520.             bmagCorrection = bmag_correctionM[lumIndex][subclass];
  521.             break;
  522.         case StellarClass::Spectral_R:
  523.         case StellarClass::Spectral_S:
  524.         case StellarClass::Spectral_N:
  525.         case StellarClass::Spectral_C:
  526.             period = rotperiod_M[lumIndex][subclass];
  527.             bmagCorrection = bmag_correctionM[lumIndex][subclass];
  528.             break;
  529.         case StellarClass::Spectral_WC:
  530.         case StellarClass::Spectral_WN:
  531.             period = rotperiod_O[lumIndex][subclass];
  532.             bmagCorrection = bmag_correctionO[lumIndex][subclass];
  533.             break;
  534.         case StellarClass::Spectral_L:
  535.             // Assume that brown dwarfs are fast rotators like late M dwarfs
  536.             period = 0.2f;
  537.             bmagCorrection = bmag_correctionL[subclass];
  538.             break;
  539.         case StellarClass::Spectral_T:
  540.             // Assume that brown dwarfs are fast rotators like late M dwarfs
  541.             period = 0.2f;
  542.             bmagCorrection = bmag_correctionT[subclass];
  543.             break;
  544.         default: break;  // Do nothing, but prevent GCC4 warnings (Beware: potentially dangerous)
  545.         }
  546.         normalStarDetails[index] = CreateStandardStarType(name, temp, period);
  547.         normalStarDetails[index]->setBolometricCorrection(bmagCorrection);
  548.         MultiResTexture starTex = starTextures.starTex[specClass];
  549.         if (!starTex.isValid())
  550.             starTex = starTextures.defaultTex;
  551.         normalStarDetails[index]->setTexture(starTex);
  552.     }
  553.     return normalStarDetails[index];
  554. }
  555. StarDetails*
  556. StarDetails::GetWhiteDwarfDetails(StellarClass::SpectralClass specClass,
  557.                                   unsigned int subclass)
  558. {
  559.     // Hack assumes all WD types are consecutive
  560.     unsigned int scIndex = static_cast<unsigned int>(specClass) -
  561.         StellarClass::FirstWDClass;
  562.     if (whiteDwarfDetails == NULL)
  563.     {
  564.         unsigned int nTypes =
  565.             StellarClass::WDClassCount * StellarClass::SubclassCount;
  566.         whiteDwarfDetails = new StarDetails*[nTypes];
  567.         for (unsigned int i = 0; i < nTypes; i++)
  568.             whiteDwarfDetails[i] = NULL;
  569.     }
  570.     if (subclass > StellarClass::Subclass_Unknown)
  571.         subclass = StellarClass::Subclass_Unknown;
  572.     uint index = subclass + (scIndex * StellarClass::SubclassCount);
  573.     if (whiteDwarfDetails[index] == NULL)
  574.     {
  575.         char name[16];
  576.         sprintf(name, "%s%s",
  577.                 WDSpectralClassNames[scIndex],
  578.                 SubclassNames[subclass]);
  579.         float temp;
  580.         float bmagCorrection;
  581.         // subclass is always >= 0:
  582.         if (subclass <= 9)
  583.         {
  584.             temp = tempWD[subclass];
  585.             bmagCorrection = bmag_correctionWD[subclass];
  586.         }
  587.         else
  588.         {
  589.             // Treat unknown as subclass 5
  590.             temp = tempWD[5];
  591.             bmagCorrection = bmag_correctionWD[5];
  592.         }
  593.         // Assign white dwarfs a rotation period of half an hour; very
  594.         // rough, as white rotation rates vary a lot.
  595.         float period = 1.0f / 48.0f;
  596.         whiteDwarfDetails[index] = CreateStandardStarType(name, temp, period);
  597.         MultiResTexture starTex = starTextures.starTex[StellarClass::Spectral_D];
  598.         if (!starTex.isValid())
  599.             starTex = starTextures.defaultTex;
  600.         whiteDwarfDetails[index]->setTexture(starTex);
  601.         whiteDwarfDetails[index]->setBolometricCorrection(bmagCorrection);
  602.     }
  603.     return whiteDwarfDetails[index];
  604. }
  605. StarDetails*
  606. StarDetails::GetNeutronStarDetails()
  607. {
  608.     if (neutronStarDetails == NULL)
  609.     {
  610.         // The default neutron star has a rotation period of one second,
  611.         // surface temperature of five million K.
  612.         neutronStarDetails = CreateStandardStarType("Q", 5000000.0f,
  613.                                                     1.0f / 86400.0f);
  614.         neutronStarDetails->setRadius(10.0f);
  615.         neutronStarDetails->addKnowledge(KnowRadius);
  616.         MultiResTexture starTex = starTextures.neutronStarTex;
  617.         if (!starTex.isValid())
  618.             starTex = starTextures.defaultTex;
  619.         neutronStarDetails->setTexture(starTex);
  620.     }
  621.     return neutronStarDetails;
  622. }
  623. StarDetails*
  624. StarDetails::GetBlackHoleDetails()
  625. {
  626.     if (blackHoleDetails == NULL)
  627.     {
  628.         // Default black hole parameters are based on a one solar mass
  629.         // black hole.
  630.         // The temperature is computed from the equation:
  631.         //      T=h_bar c^3/(8 pi G k m)
  632.         blackHoleDetails = CreateStandardStarType("X", 6.15e-8f,
  633.                                                   1.0f / 86400.0f);
  634.         blackHoleDetails->setRadius(2.9f);
  635.         blackHoleDetails->addKnowledge(KnowRadius);
  636.     }
  637.     return blackHoleDetails;
  638. }
  639. StarDetails*
  640. StarDetails::GetBarycenterDetails()
  641. {
  642.     if (barycenterDetails == NULL)
  643.     {
  644.         barycenterDetails = CreateStandardStarType("Bary", 1.0f, 1.0f);
  645.         barycenterDetails->setRadius(0.001f);
  646.         barycenterDetails->addKnowledge(KnowRadius);
  647.         barycenterDetails->setVisibility(false);
  648.     }
  649.     return barycenterDetails;
  650. }
  651. void
  652. StarDetails::SetStarTextures(const StarTextureSet& _starTextures)
  653. {
  654.     starTextures = _starTextures;
  655. }
  656. StarDetails::StarDetails() :
  657.     radius(0.0f),
  658.     temperature(0.0f),
  659.     bolometricCorrection(0.0f),
  660.     knowledge(0u),
  661.     visible(true),
  662.     texture(texture),
  663.     geometry(InvalidResource),
  664.     orbit(NULL),
  665.     orbitalRadius(0.0f),
  666.     barycenter(NULL),
  667.     rotationModel(NULL),
  668.     semiAxes(1.0f, 1.0f, 1.0f),
  669.     infoURL(NULL),
  670.     orbitingStars(NULL),
  671.     isShared(true)
  672. {
  673.     spectralType[0] = '';
  674. }
  675. StarDetails::StarDetails(const StarDetails& sd) :
  676.     radius(sd.radius),
  677.     temperature(sd.temperature),
  678.     bolometricCorrection(sd.bolometricCorrection),
  679.     knowledge(sd.knowledge),
  680.     visible(sd.visible),
  681.     texture(sd.texture),
  682.     geometry(sd.geometry),
  683.     orbit(sd.orbit),
  684.     orbitalRadius(sd.orbitalRadius),
  685.     barycenter(sd.barycenter),
  686.     rotationModel(sd.rotationModel),
  687.     semiAxes(sd.semiAxes),
  688.     infoURL(NULL),
  689.     orbitingStars(NULL),
  690.     isShared(false)
  691. {
  692.     assert(sd.isShared);
  693.     memcpy(spectralType, sd.spectralType, sizeof(spectralType));
  694.     if (sd.infoURL != NULL)
  695.         infoURL = new string(*sd.infoURL);
  696. }
  697. StarDetails::~StarDetails()
  698. {
  699.     delete orbitingStars;
  700.     delete infoURL;
  701. }
  702. /*! Return the InfoURL. If the InfoURL has not been set, this method
  703.  *  returns an empty string.
  704.  */
  705. const std::string&
  706. StarDetails::getInfoURL() const
  707. {
  708.     if (infoURL != NULL)
  709.         return *infoURL;
  710.     else
  711.         return DEFAULT_INFO_URL;
  712. }
  713. void
  714. StarDetails::setRadius(float _radius)
  715. {
  716.     radius = _radius;
  717. }
  718. void
  719. StarDetails::setTemperature(float _temperature)
  720. {
  721.     temperature = _temperature;
  722. }
  723. void
  724. StarDetails::setSpectralType(const std::string& s)
  725. {
  726.     strncpy(spectralType, s.c_str(), sizeof(spectralType));
  727.     spectralType[sizeof(spectralType) - 1] = '';
  728. }
  729. void
  730. StarDetails::setKnowledge(uint32 _knowledge)
  731. {
  732.     knowledge = _knowledge;
  733. }
  734. void
  735. StarDetails::addKnowledge(uint32 _knowledge)
  736. {
  737.     knowledge |= _knowledge;
  738. }
  739. void
  740. StarDetails::setBolometricCorrection(float correction)
  741. {
  742.     bolometricCorrection = correction;
  743. }
  744. void
  745. StarDetails::setTexture(const MultiResTexture& tex)
  746. {
  747.     texture = tex;
  748. }
  749. void
  750. StarDetails::setGeometry(ResourceHandle rh)
  751. {
  752.     geometry = rh;
  753. }
  754. void
  755. StarDetails::setOrbit(Orbit* o)
  756. {
  757.     orbit = o;
  758.     computeOrbitalRadius();
  759. }
  760. void
  761. StarDetails::setOrbitBarycenter(Star* bc)
  762. {
  763.     barycenter = bc;
  764.     computeOrbitalRadius();
  765. }
  766. void
  767. StarDetails::setOrbitalRadius(float r)
  768. {
  769.     if (orbit != NULL)
  770.         orbitalRadius = r;
  771. }
  772. void
  773. StarDetails::computeOrbitalRadius()
  774. {
  775.     if (orbit == NULL)
  776.     {
  777.         orbitalRadius = 0.0f;
  778.     }
  779.     else
  780.     {
  781.         orbitalRadius = (float) astro::kilometersToLightYears(orbit->getBoundingRadius());
  782.         if (barycenter != NULL)
  783.             orbitalRadius += barycenter->getOrbitalRadius();
  784.     }
  785. }
  786. void
  787. StarDetails::setVisibility(bool b)
  788. {
  789.     visible = b;
  790. }
  791. void
  792. StarDetails::setRotationModel(const RotationModel* rm)
  793. {
  794.     rotationModel = rm;
  795. }
  796. /*! Set the InfoURL for this star.
  797. */
  798. void
  799. StarDetails::setInfoURL(const string& _infoURL)
  800. {
  801.     if (_infoURL.empty())
  802.     {
  803.         // Save space in the common case--no InfoURL--by not
  804.         // allocating a string.
  805.         delete infoURL;
  806.         infoURL = NULL;
  807.     }
  808.     else
  809.     {
  810.         // Allocate the new string before freeing the old one, so we don't crash
  811.         // in the event the caller does something like:
  812.         // star->setInfoURL(star->getInfoURL());
  813.         string* oldURL = infoURL;
  814.         infoURL = new string(_infoURL);
  815.         delete oldURL;
  816.     }
  817. }
  818. Star::~Star()
  819. {
  820.     // TODO: Implement reference counting for StarDetails objects so that
  821.     // we can enable this.
  822. #if 0
  823.     if (!details->shared())
  824.         delete details;
  825. #endif
  826. }
  827. // Return the radius of the star in kilometers
  828. float Star::getRadius() const
  829. {
  830.     if (details->getKnowledge(StarDetails::KnowRadius))
  831.         return details->getRadius();
  832. #ifdef NO_BOLOMETRIC_MAGNITUDE_CORRECTION
  833.     // Use the Stefan-Boltzmann law to estimate the radius of a
  834.     // star from surface temperature and luminosity
  835.     return SOLAR_RADIUS * (float) sqrt(getLuminosity()) *
  836.         square(SOLAR_TEMPERATURE / getTemperature());
  837. #else
  838.     // Calculate the luminosity of the star from the bolometric, not the
  839.     // visual magnitude of the star.
  840.     float solarBMag = SOLAR_ABSMAG + bmag_correctionG[0][2];
  841.     float bmag = getBolometricMagnitude();
  842.     float boloLum = (float) exp((solarBMag - bmag) / LN_MAG);
  843.     // Use the Stefan-Boltzmann law to estimate the radius of a
  844.     // star from surface temperature and luminosity
  845.     return SOLAR_RADIUS * (float) sqrt(boloLum) *
  846.         square(SOLAR_TEMPERATURE / getTemperature());
  847. #endif
  848. }
  849. void
  850. StarDetails::setEllipsoidSemiAxes(const Vec3f& v)
  851. {
  852.     semiAxes = v;
  853. }
  854. bool
  855. StarDetails::shared() const
  856. {
  857.     return isShared;
  858. }
  859. void
  860. StarDetails::addOrbitingStar(Star* star)
  861. {
  862.     assert(!shared());
  863.     if (orbitingStars == NULL)
  864.         orbitingStars = new vector<Star*>();
  865.     orbitingStars->push_back(star);
  866. }
  867. /*! Get the position of the star in the universal coordinate system.
  868.  */
  869. UniversalCoord
  870. Star::getPosition(double t) const
  871. {
  872.     const Orbit* orbit = getOrbit();
  873.     if (!orbit)
  874.     {
  875.         return UniversalCoord(position.x * 1.0e6,
  876.                               position.y * 1.0e6,
  877.                               position.z * 1.0e6);
  878.     }
  879.     else
  880.     {
  881.         const Star* barycenter = getOrbitBarycenter();
  882.         if (barycenter == NULL)
  883.         {
  884.             Point3d barycenterPos(position.x * 1.0e6,
  885.                                   position.y * 1.0e6,
  886.                                   position.z * 1.0e6);
  887.             return UniversalCoord(barycenterPos) +
  888.                 ((orbit->positionAtTime(t) - Point3d(0.0, 0.0, 0.0)) *
  889.                  astro::kilometersToMicroLightYears(1.0));
  890.         }
  891.         else
  892.         {
  893.             return barycenter->getPosition(t) +
  894.                 ((orbit->positionAtTime(t) - Point3d(0.0, 0.0, 0.0)) *
  895.                  astro::kilometersToMicroLightYears(1.0));
  896.         }
  897.     }
  898. }
  899. UniversalCoord
  900. Star::getOrbitBarycenterPosition(double t) const
  901. {
  902.     const Star* barycenter = getOrbitBarycenter();
  903.     if (barycenter == NULL)
  904.     {
  905.         Point3d barycenterPos(position.x * 1.0e6,
  906.                               position.y * 1.0e6,
  907.                               position.z * 1.0e6);
  908.         return UniversalCoord(barycenterPos);
  909.     }
  910.     else
  911.     {
  912.         return barycenter->getPosition(t);
  913.     }
  914. }
  915. /*! Get the velocity of the star in the universal coordinate system.
  916.  */
  917. Vec3d
  918. Star::getVelocity(double t) const
  919. {
  920.     const Orbit* orbit = getOrbit();
  921.     if (!orbit)
  922.     {
  923. // The star doesn't have a defined orbit, so the velocity is just
  924. // zero. (This will change when stellar proper motion is implemented.)
  925. return Vec3d(0.0, 0.0, 0.0);
  926.     }
  927.     else
  928.     {
  929.         const Star* barycenter = getOrbitBarycenter();
  930.         if (barycenter == NULL)
  931.         {
  932. // Star orbit is defined around a fixed point, so the total velocity
  933. // is just the star's orbit velocity.
  934. return orbit->velocityAtTime(t);
  935.         }
  936.         else
  937.         {
  938. // Sum the star's orbital velocity and the velocity of the barycenter.
  939.             return barycenter->getVelocity(t) + orbit->velocityAtTime(t);
  940.         }
  941.     }
  942. }
  943. MultiResTexture
  944. Star::getTexture() const
  945. {
  946.     return details->getTexture();
  947. }
  948. ResourceHandle
  949. Star::getGeometry() const
  950. {
  951.     return details->getGeometry();
  952. }
  953. /*! Return the InfoURL. If the InfoURL has not been set, this method
  954. *  returns an empty string.
  955. */
  956. const string&
  957. Star::getInfoURL() const
  958. {
  959.     return details->getInfoURL();
  960. }
  961. void Star::setCatalogNumber(uint32 n)
  962. {
  963.     catalogNumber = n;
  964. }
  965. void Star::setPosition(float x, float y, float z)
  966. {
  967.     position = Point3f(x, y, z);
  968. }
  969. void Star::setPosition(Point3f p)
  970. {
  971.     position = p;
  972. }
  973. void Star::setAbsoluteMagnitude(float mag)
  974. {
  975.     absMag = mag;
  976. }
  977. float Star::getApparentMagnitude(float ly) const
  978. {
  979.     return astro::absToAppMag(absMag, ly);
  980. }
  981. float Star::getLuminosity() const
  982. {
  983.     return astro::absMagToLum(absMag);
  984. }
  985. void Star::setLuminosity(float lum)
  986. {
  987.     absMag = astro::lumToAbsMag(lum);
  988. }
  989. StarDetails* Star::getDetails() const
  990. {
  991.     return details;
  992. }
  993. void Star::setDetails(StarDetails* sd)
  994. {
  995.     // TODO: delete existing details if they aren't shared
  996.     details = sd;
  997. }
  998. void Star::setOrbitBarycenter(Star* s)
  999. {
  1000.     if (details->shared())
  1001.         details = new StarDetails(*details);
  1002.     details->setOrbitBarycenter(s);
  1003. }
  1004. void Star::computeOrbitalRadius()
  1005. {
  1006.     details->computeOrbitalRadius();
  1007. }
  1008. void
  1009. Star::setRotationModel(const RotationModel* rm)
  1010. {
  1011.     details->setRotationModel(rm);
  1012. }
  1013. void
  1014. Star::addOrbitingStar(Star* star)
  1015. {
  1016.     if (details->shared())
  1017.         details = new StarDetails(*details);
  1018.     details->addOrbitingStar(star);
  1019. }