1 #include <clocale>
2 #include <cstdio>
3 #include <cstdlib>
4 #include <cstring>
5 #include <iostream>
6 #include <map>
7 #include <sstream>
8 #include <vector>
9 using namespace std;
10 
11 #include <sys/time.h>
12 #include <unistd.h>
13 
14 #include "config.h"
15 
16 #include "buildPlanetMap.h"
17 #include "findBodyXYZ.h"
18 #include "keywords.h"
19 #include "Options.h"
20 #include "PlanetProperties.h"
21 #include "readOriginFile.h"
22 #include "setPositions.h"
23 #include "xpUtil.h"
24 
25 #include "libannotate/libannotate.h"
26 #include "libdisplay/libdisplay.h"
27 #include "libdisplay/libtimer.h"
28 #include "libephemeris/ephemerisWrapper.h"
29 #include "libplanet/Planet.h"
30 #include "libmultiple/RayleighScattering.h"
31 
32 extern void
33 drawMultipleBodies(DisplayBase *display, Planet *target,
34                    const double upX, const double upY, const double upZ,
35                    map<double, Planet *> &planetsFromSunMap,
36                    PlanetProperties *planetProperties[]);
37 
38 extern void
39 drawProjection(DisplayBase *display, Planet *target,
40                const double upX, const double upY, const double upZ,
41                map<double, Planet *> &planetsFromSunMap,
42                PlanetProperties *planetProperties);
43 
44 extern void
45 readConfigFile(string configFile, PlanetProperties *planetProperties[]);
46 
47 extern void
48 setPositions(const vector<LBRPoint> &originVector,
49              const vector<LBRPoint>::iterator &iterOriginVector,
50              Planet *&target, map<double, Planet *> &planetMap,
51              PlanetProperties *planetProperties[]);
52 
53 int
main(int argc,char ** argv)54 main(int argc, char **argv)
55 {
56     if (setlocale(LC_ALL, "") == NULL)
57     {
58         ostringstream errMsg;
59         errMsg << "Warning: setlocale(LC_ALL, \"\") failed! "
60                << "Check your LANG environment variable "
61                << "(currently ";
62         char *lang = getenv("LANG");
63         if (lang == NULL)
64         {
65             errMsg << "NULL";
66         }
67         else
68         {
69             errMsg << "\"" << lang << "\"";
70         }
71         errMsg << "). Setting to \"C\".\n";
72         setlocale(LC_ALL, "C");
73         cerr << errMsg.str();
74     }
75 
76     Options *options = Options::getInstance();
77     options->parseArgs(argc, argv);
78 
79     if (options->Fork())
80     {
81         pid_t pid = fork();
82         switch (pid)
83         {
84         case 0:
85             // This is the child process
86             close(STDIN_FILENO);
87             close(STDOUT_FILENO);
88             close(STDERR_FILENO);
89             setsid();
90             break;
91         case -1:
92             xpExit("fork() failed!\n", __FILE__, __LINE__);
93             break;
94         default:
95             // This is the parent process
96             if (options->Verbosity() > 1)
97             {
98                 ostringstream msg;
99                 msg << "Forked child process, PID is " << pid << "\n";
100                 xpMsg(msg.str(), __FILE__, __LINE__);
101             }
102             return(EXIT_SUCCESS);
103         }
104     }
105 
106     if (options->RayleighFile().length() > 0)
107     {
108 	RayleighScattering rayleigh(options->RayleighFile());
109 	rayleigh.createTables();
110 	return(EXIT_SUCCESS);
111     }
112 
113     setUpEphemeris();
114 
115     PlanetProperties *planetProperties[RANDOM_BODY];
116     for (int i = 0; i < RANDOM_BODY; i++)
117         planetProperties[i] = new PlanetProperties((body) i);
118 
119     // Load the drawing info for each planet
120     readConfigFile(options->ConfigFile(), planetProperties);
121 
122 #ifdef HAVE_CSPICE
123     // Load any SPICE kernels
124     processSpiceKernels(true);
125 #endif
126 
127     // If an origin file has been specified, read it
128     const bool origin_file = !options->OriginFile().empty();
129     vector<LBRPoint> originVector;
130     if (origin_file)
131     {
132         readOriginFile(options->OriginFile(), originVector);
133         if (!options->InterpolateOriginFile())
134             options->NumTimes(originVector.size());
135     }
136 
137     vector<LBRPoint>::iterator iterOriginVector = originVector.begin();
138 
139     // Initialize the timer
140     Timer *timer = getTimer(options->getWait(), options->Hibernate(),
141                             options->IdleWait());
142 
143     int times_run = 0;
144 
145     while (1)
146     {
147         // Set the time for the next update
148         timer->Update();
149 
150         // Run any commands specified with -prev_command
151         if (!options->PrevCommand().empty())
152         {
153             if (system(options->PrevCommand().c_str()) != 0)
154             {
155                 ostringstream errStr;
156                 errStr << "Can't execute " << options->PrevCommand()
157                        << "\n";
158                 xpWarn(errStr.str(), __FILE__, __LINE__);
159             }
160         }
161 
162         // Load artificial satellite orbital elements
163         if (!planetProperties[EARTH]->SatelliteFiles().empty())
164             loadSatelliteVector(planetProperties[EARTH]);
165 
166         // delete the markerbounds file, since we'll create a new one
167         string markerBounds(options->MarkerBounds());
168         if (!markerBounds.empty())
169             unlinkFile(markerBounds.c_str());
170 
171         // Set the time to the current time, if desired
172         if (options->UseCurrentTime())
173         {
174             struct timeval time;
175             gettimeofday(&time, NULL);
176 
177             time_t t  = time.tv_sec;
178             int year  = gmtime(static_cast<time_t *> (&t))->tm_year + 1900;
179             int month = gmtime(static_cast<time_t *> (&t))->tm_mon + 1;
180             int day   = gmtime(static_cast<time_t *> (&t))->tm_mday;
181             int hour  = gmtime(static_cast<time_t *> (&t))->tm_hour;
182             int min   = gmtime(static_cast<time_t *> (&t))->tm_min;
183             int sec   = gmtime(static_cast<time_t *> (&t))->tm_sec;
184             const double julianDay = toJulian(year, month, day,
185                                               hour, min, sec);
186             options->setTime(julianDay);
187         }
188 
189         // Calculate the positions of the planets & moons.  The map
190         // container sorts on the key, so the bodies will be ordered
191         // by heliocentric distance.  This makes calculating shadows
192         // easier.
193         map<double, Planet *> planetsFromSunMap;
194         buildPlanetMap(options->JulianDay(), planetsFromSunMap);
195 
196         // set the observer and target XYZ positions
197         Planet *target;
198         setPositions(originVector, iterOriginVector, target, planetsFromSunMap,
199                      planetProperties);
200 
201         // Set the "up" vector.  This points to the top of the screen.
202         double upX, upY, upZ;
203         setUpXYZ(target, planetsFromSunMap, upX, upY, upZ);
204 
205         // Initialize display device
206         DisplayBase *display = getDisplay(times_run);
207 
208         if (options->ProjectionMode() == MULTIPLE)
209         {
210             drawMultipleBodies(display, target,
211                                upX, upY, upZ,
212                                planetsFromSunMap,
213                                planetProperties);
214         }
215         else
216         {
217             drawProjection(display, target,
218                            upX, upY, upZ,
219                            planetsFromSunMap,
220                            planetProperties[target->Index()]);
221         }
222 
223         display->renderImage(planetProperties);
224         delete display;
225 
226         destroyPlanetMap();
227 
228         times_run++;
229 
230         if (!options->PostCommand().empty())
231         {
232             if (system(options->PostCommand().c_str()) != 0)
233             {
234                 ostringstream errStr;
235                 errStr << "Can't execute " << options->PostCommand()
236                        << "\n";
237                 xpWarn(errStr.str(), __FILE__, __LINE__);
238             }
239         }
240 
241         if (options->NumTimes() > 0 && times_run >= options->NumTimes())
242             break;
243 
244         if (origin_file && !options->InterpolateOriginFile())
245         {
246             // If we've run through the origin file, break out of the
247             // while(1) loop.
248             iterOriginVector++;
249             if (iterOriginVector == originVector.end()) break;
250         }
251 
252         if (!options->UseCurrentTime())
253         {
254             // Set the time to the next update
255             options->incrementTime(options->getTimeWarp()
256                                    * options->getWait());
257         }
258 
259         // Sleep until the next update.  If Sleep() returns false,
260         // then quit.
261         if (!timer->Sleep()) break;
262     }
263 
264 #ifdef HAVE_CSPICE
265     // unload any SPICE kernels
266     processSpiceKernels(false);
267 #endif
268 
269     delete timer;
270 
271     for (int i = 0; i < RANDOM_BODY; i++) delete planetProperties[i];
272 
273     cleanUpEphemeris();
274 
275     return(EXIT_SUCCESS);
276 }
277