Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

stellarclass.cpp

Go to the documentation of this file.
00001 // stellarclass.cpp
00002 //
00003 // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 #include <cstring>
00011 #include <cstdio>
00012 #include <cassert>
00013 #include "celestia.h"
00014 #include "stellarclass.h"
00015 
00016 using namespace std;
00017 
00018 
00019 Color StellarClass::getApparentColor() const
00020 {
00021     return getApparentColor(getSpectralClass());
00022 }
00023 
00024 
00025 Color StellarClass::getApparentColor(StellarClass::SpectralClass sc) const
00026 {
00027     switch (sc)
00028     {
00029     case Spectral_O:
00030         return Color(0.7f, 0.8f, 1.0f);
00031     case Spectral_B:
00032         return Color(0.8f, 0.9f, 1.0f);
00033     case Spectral_A:
00034         return Color(1.0f, 1.0f, 1.0f);
00035     case Spectral_F:
00036         return Color(1.0f, 1.0f, 0.88f);
00037     case Spectral_G:
00038         return Color(1.0f, 1.0f, 0.75f);
00039     case StellarClass::Spectral_K:
00040         return Color(1.0f, 0.9f, 0.7f);
00041     case StellarClass::Spectral_M:
00042         return Color(1.0f, 0.7f, 0.7f);
00043     case StellarClass::Spectral_R:
00044     case StellarClass::Spectral_S:
00045     case StellarClass::Spectral_N:
00046     case StellarClass::Spectral_C:
00047         return Color(1.0f, 0.4f, 0.4f);
00048     case StellarClass::Spectral_L:
00049     case StellarClass::Spectral_T:
00050         return Color(0.75f, 0.2f, 0.2f);
00051     default:
00052         // TODO: Figure out reasonable colors for Wolf-Rayet stars,
00053         // white dwarfs, and other oddities
00054         return Color(1.0f, 1.0f, 1.0f);
00055     }
00056 }
00057 
00058 
00059 // The << method of converting the stellar class to a string is
00060 // preferred, but it's not always practical, especially when you've
00061 // got a completely broken implemtation of stringstreams to
00062 // deal with (*cough* gcc *cough*).
00063 //
00064 // Return the buffer if successful or NULL if not (the buffer wasn't
00065 // large enough.)
00066 char* StellarClass::str(char* buf, unsigned int buflen) const
00067 {
00068     StellarClass::StarType st = getStarType();
00069     char s0[3];
00070     char s1[2];
00071     const char* s2 = "";
00072     s0[0] = '\0';
00073     s1[0] = '\0';
00074 
00075     if (st == StellarClass::WhiteDwarf)
00076     {
00077         strcpy(s0, "WD");
00078     }
00079     else if (st == StellarClass::NeutronStar)
00080     {
00081         strcpy(s0, "Q");
00082     }
00083     else if (st == StellarClass::BlackHole)
00084     {
00085         strcpy(s0, "X");
00086     }
00087     else if (st == StellarClass::NormalStar)
00088     {
00089         s0[0] = "OBAFGKMRSNWW?LTC"[(unsigned int) getSpectralClass()];
00090         s0[1] = '\0';
00091         s1[0] = "0123456789"[getSubclass()];
00092         s1[1] = '\0';
00093         switch (getLuminosityClass())
00094         {
00095         case StellarClass::Lum_Ia0:
00096             s2 = " I-a0";
00097             break;
00098         case StellarClass::Lum_Ia:
00099             s2 = " I-a";
00100             break;
00101         case StellarClass::Lum_Ib:
00102             s2 = " I-b";
00103             break;
00104         case StellarClass::Lum_II:
00105             s2 = " II";
00106             break;
00107         case StellarClass::Lum_III:
00108             s2 = " III";
00109             break;
00110         case StellarClass::Lum_IV:
00111             s2 = " IV";
00112             break;
00113         case StellarClass::Lum_V:
00114             s2 = " V";
00115             break;
00116         case StellarClass::Lum_VI:
00117             s2 = " VI";
00118             break;
00119         }
00120     }
00121     else
00122     {
00123         strcpy(s0, "?");
00124     }
00125 
00126     if (strlen(s0) + strlen(s1) + strlen(s2) >= buflen)
00127     {
00128         return NULL;
00129     }
00130     else
00131     {
00132         sprintf(buf, "%s%s%s", s0, s1, s2);
00133         return buf;
00134     }
00135 }
00136 
00137 
00138 string StellarClass::str() const
00139 {
00140     char buf[20];
00141     str(buf, sizeof buf);
00142     return string(buf);
00143 }
00144 
00145 
00146 uint16
00147 StellarClass::pack() const
00148 {
00149     return (((uint16) starType << 12) |
00150             (((uint16) specClass & 0xf) << 8) |
00151             ((uint16) subclass << 4) |
00152             ((uint16) lumClass));
00153 }
00154 
00155 
00156 bool
00157 StellarClass::unpack(uint16 st)
00158 {
00159     starType = static_cast<StellarClass::StarType>(st >> 12);
00160 
00161     switch (starType)
00162     {
00163     case NormalStar:
00164         specClass = static_cast<SpectralClass>(st >> 8 & 0xf);
00165         subclass = st >> 4 & 0xf;
00166         lumClass = static_cast<LuminosityClass>(st & 0xf);
00167         break;
00168     case WhiteDwarf:
00169         if ((st >> 8 & 0xf) >= WDClassCount)
00170             return false;
00171         specClass = static_cast<SpectralClass>((st >> 8 & 0xf) + Spectral_DA);
00172         subclass = st >> 4 & 0xf;
00173         lumClass = Lum_Unknown;
00174         break;
00175     case NeutronStar:
00176     case BlackHole:
00177         specClass = Spectral_Unknown;
00178         subclass = Subclass_Unknown;
00179         lumClass = Lum_Unknown;
00180         break;
00181     default:
00182         return false;
00183     }
00184 
00185     return true;
00186 }
00187 
00188 
00189 ostream& operator<<(ostream& os, const StellarClass& sc)
00190 {
00191     char buf[20];
00192     char *scString = sc.str(buf, sizeof buf);
00193     assert(scString != NULL);
00194 
00195     os << scString;
00196 
00197     return os;
00198 }
00199 
00200 
00201 bool operator<(const StellarClass& sc0, const StellarClass& sc1)
00202 {
00203     return sc0.pack() < sc1.pack();
00204 }
00205 
00206 
00207 // The following code implements a state machine for parsing spectral
00208 // types.  It is a very forgiving parser, returning unknown for any of the
00209 // spectral type fields it can't find, and silently ignoring any extra
00210 // characters in the spectral type.  The parser is written this way because
00211 // the spectral type strings from the Hipparcos catalog are quite irregular.
00212 enum ParseState
00213 {
00214     BeginState,
00215     EndState,
00216     NormalStarState,
00217     WolfRayetTypeState,
00218     NormalStarClassState,
00219     NormalStarSubclassState,
00220     NormalStarSubclassDecimalState,
00221     NormalStarSubclassFinalState,
00222     LumClassBeginState,
00223     LumClassIState,
00224     LumClassIIState,
00225     LumClassVState,
00226     LumClassIdashState,
00227     LumClassIaState,
00228     WDTypeState,
00229     WDExtendedTypeState,
00230     WDSubclassState,
00231     SubdwarfPrefixState,
00232 };
00233 
00234 
00235 StellarClass
00236 StellarClass::parse(const string& st)
00237 {
00238     uint32 i = 0;
00239     ParseState state = BeginState;
00240     StellarClass::StarType starType = StellarClass::NormalStar;
00241     StellarClass::SpectralClass specClass = StellarClass::Spectral_Unknown;
00242     StellarClass::LuminosityClass lumClass = StellarClass::Lum_Unknown;
00243     unsigned int subclass = StellarClass::Subclass_Unknown;
00244 
00245     while (state != EndState)
00246     {
00247         char c;
00248         if (i < st.length())
00249             c = st[i];
00250         else
00251             c = '\0';
00252 
00253         switch (state)
00254         {
00255         case BeginState:
00256             switch (c)
00257             {
00258             case 'Q':
00259                 starType = StellarClass::NeutronStar;
00260                 state = EndState;
00261                 break;
00262             case 'X':
00263                 starType = StellarClass::BlackHole;
00264                 state = EndState;
00265                 break;
00266             case 'D':
00267                 starType = StellarClass::WhiteDwarf;
00268                 specClass = StellarClass::Spectral_D;
00269                 state = WDTypeState;
00270                 i++;
00271                 break;
00272             case 's':
00273                 // Hipparcos uses sd prefix for stars with luminosity
00274                 // class VI ('subdwarfs')
00275                 state = SubdwarfPrefixState;
00276                 i++;
00277                 break;
00278             case '?':
00279                 state = EndState;
00280                 break;
00281             default:
00282                 state = NormalStarClassState;
00283                 break;
00284             }
00285             break;
00286 
00287         case WolfRayetTypeState:
00288             switch (c)
00289             {
00290             case 'C':
00291                 specClass = StellarClass::Spectral_WC;
00292                 state = NormalStarSubclassState;
00293                 i++;
00294                 break;
00295             case 'N':
00296                 specClass = StellarClass::Spectral_WN;
00297                 state = NormalStarSubclassState;
00298                 i++;
00299                 break;
00300             default:
00301                 specClass = StellarClass::Spectral_WC;
00302                 state = NormalStarSubclassState;
00303                 break;
00304             }
00305             break;
00306 
00307         case SubdwarfPrefixState:
00308             if (c == 'd')
00309             {
00310                 lumClass = StellarClass::Lum_VI;
00311                 state = NormalStarClassState;
00312                 i++;
00313                 break;
00314             }
00315             else
00316             {
00317                 state = EndState;
00318             }
00319             break;
00320 
00321         case NormalStarClassState:
00322             switch (c)
00323             {
00324             case 'W':
00325                 state = WolfRayetTypeState;
00326                 break;
00327             case 'O':
00328                 specClass = StellarClass::Spectral_O;
00329                 state = NormalStarSubclassState;
00330                 break;               
00331             case 'B':
00332                 specClass = StellarClass::Spectral_B;
00333                 state = NormalStarSubclassState;
00334                 break;               
00335             case 'A':
00336                 specClass = StellarClass::Spectral_A;
00337                 state = NormalStarSubclassState;
00338                 break;
00339             case 'F':
00340                 specClass = StellarClass::Spectral_F;
00341                 state = NormalStarSubclassState;
00342                 break;
00343             case 'G':
00344                 specClass = StellarClass::Spectral_G;
00345                 state = NormalStarSubclassState;
00346                 break;
00347             case 'K':
00348                 specClass = StellarClass::Spectral_K;
00349                 state = NormalStarSubclassState;
00350                 break;
00351             case 'M':
00352                 specClass = StellarClass::Spectral_M;
00353                 state = NormalStarSubclassState;
00354                 break;
00355             case 'R':
00356                 specClass = StellarClass::Spectral_R;
00357                 state = NormalStarSubclassState;
00358                 break;
00359             case 'S':
00360                 specClass = StellarClass::Spectral_S;
00361                 state = NormalStarSubclassState;
00362                 break;
00363             case 'N':
00364                 specClass = StellarClass::Spectral_N;
00365                 state = NormalStarSubclassState;
00366                 break;
00367             case 'L':
00368                 specClass = StellarClass::Spectral_L;
00369                 state = NormalStarSubclassState;
00370                 break;
00371             case 'T':
00372                 specClass = StellarClass::Spectral_T;
00373                 state = NormalStarSubclassState;
00374                 break;
00375             case 'C':
00376                 specClass = StellarClass::Spectral_C;
00377                 state = NormalStarSubclassState;
00378                 break;
00379             default:
00380                 state = EndState;
00381                 break;
00382             }
00383             i++;
00384             break;
00385 
00386         case NormalStarSubclassState:
00387             if (isdigit(c))
00388             {
00389                 subclass = (unsigned int) c - (unsigned int) '0';
00390                 state = NormalStarSubclassDecimalState;
00391                 i++;
00392             }
00393             else
00394             {
00395                 state = LumClassBeginState;
00396             }
00397             break;
00398 
00399         case NormalStarSubclassDecimalState:
00400             if (c == '.')
00401             {
00402                 state = NormalStarSubclassFinalState;
00403                 i++;
00404             }
00405             else
00406             {
00407                 state = LumClassBeginState;
00408             }
00409             break;
00410 
00411         case NormalStarSubclassFinalState:
00412             if (isdigit(c))
00413                 state = LumClassBeginState;
00414             else
00415                 state = EndState;
00416             i++;
00417             break;
00418 
00419         case LumClassBeginState:
00420             switch (c)
00421             {
00422             case 'I':
00423                 state = LumClassIState;
00424                 break;
00425             case 'V':
00426                 state = LumClassVState;
00427                 break;
00428             default:
00429                 state = EndState;
00430                 break;
00431             }
00432             i++;
00433             break;
00434 
00435         case LumClassIState:
00436             switch (c)
00437             {
00438             case 'I':
00439                 state = LumClassIIState;
00440                 break;
00441             case 'V':
00442                 lumClass = StellarClass::Lum_IV;
00443                 state = EndState;
00444                 break;
00445             case 'a':
00446                 state = LumClassIaState;
00447                 break;
00448             case 'b':
00449                 lumClass = StellarClass::Lum_Ib;
00450                 state = EndState;
00451                 break;
00452             case '-':
00453                 state = LumClassIdashState;
00454                 break;
00455             default:
00456                 lumClass = StellarClass::Lum_Ib;
00457                 state = EndState;
00458                 break;
00459             }
00460             i++;
00461             break;
00462 
00463         case LumClassIIState:
00464             switch (c)
00465             {
00466             case 'I':
00467                 lumClass = StellarClass::Lum_III;
00468                 state = EndState;
00469                 break;
00470             default:
00471                 lumClass = StellarClass::Lum_II;
00472                 state = EndState;
00473                 break;
00474             }
00475             break;
00476 
00477         case LumClassIdashState:
00478             switch (c)
00479             {
00480             case 'a':
00481                 state = LumClassIaState;
00482                 break;
00483             case 'b':
00484                 lumClass = StellarClass::Lum_Ib;
00485                 state = EndState;
00486                 break;
00487             default:
00488                 lumClass = StellarClass::Lum_Ib;
00489                 state = EndState;
00490                 break;
00491             }
00492             break;
00493 
00494         case LumClassIaState:
00495             switch (c)
00496             {
00497             case '0':
00498                 lumClass = StellarClass::Lum_Ia0;
00499                 state = EndState;
00500                 break;
00501             default:
00502                 lumClass = StellarClass::Lum_Ia;
00503                 state = EndState;
00504                 break;
00505             }
00506             break;
00507 
00508         case LumClassVState:
00509             switch (c)
00510             {
00511             case 'I':
00512                 lumClass = StellarClass::Lum_VI;
00513                 state = EndState;
00514                 break;
00515             default:
00516                 lumClass = StellarClass::Lum_V;
00517                 state = EndState;
00518                 break;
00519             }
00520             break;
00521 
00522         case WDTypeState:
00523             switch (c)
00524             {
00525             case 'A':
00526                 specClass = StellarClass::Spectral_DA;
00527                 i++;
00528                 break;
00529             case 'B':
00530                 specClass = StellarClass::Spectral_DB;
00531                 i++;
00532                 break;
00533             case 'C':
00534                 specClass = StellarClass::Spectral_DC;
00535                 i++;
00536                 break;
00537             case 'O':
00538                 specClass = StellarClass::Spectral_DO;
00539                 i++;
00540                 break;
00541             case 'Q':
00542                 specClass = StellarClass::Spectral_DQ;
00543                 i++;
00544                 break;
00545             case 'X':
00546                 specClass = StellarClass::Spectral_DX;
00547                 i++;
00548                 break;
00549             case 'Z':
00550                 specClass = StellarClass::Spectral_DZ;
00551                 i++;
00552                 break;
00553             default:
00554                 specClass = StellarClass::Spectral_D;
00555                 break;
00556             }
00557             state = WDExtendedTypeState;
00558             break;
00559 
00560         case WDExtendedTypeState:
00561             switch (c)
00562             {
00563             case 'A':
00564             case 'B':
00565             case 'C':
00566             case 'O':
00567             case 'Q':
00568             case 'Z':
00569             case 'X':
00570             case 'V': // variable
00571             case 'P': // magnetic stars with polarized light
00572             case 'H': // magnetic stars without polarized light
00573             case 'E': // emission lines
00574                 i++;
00575                 break;
00576             default:
00577                 state = WDSubclassState;
00578                 break;
00579             }
00580             break;
00581 
00582         case WDSubclassState:
00583             if (isdigit(c))
00584             {
00585                 subclass = (unsigned int) c - (unsigned int) '0';
00586                 i++;
00587             }
00588             state = EndState;
00589             break;
00590 
00591         default:
00592             assert(0);
00593             state = EndState;
00594             break;
00595         }
00596     }
00597 
00598     return StellarClass(starType, specClass, subclass, lumClass);
00599 }

Generated on Sat Jan 14 22:30:29 2006 for Celestia by  doxygen 1.4.1