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