1 // simulation.cpp
2 //
3 // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
4 //
5 // The core of Celestia--tracks an observer moving through a
6 // stars and their solar systems.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 
13 #include <algorithm>
14 #include "simulation.h"
15 
16 using namespace std;
17 
18 
Simulation(Universe * _universe)19 Simulation::Simulation(Universe* _universe) :
20     realTime(0.0),
21     timeScale(1.0),
22     storedTimeScale(1.0),
23     syncTime(true),
24     universe(_universe),
25     closestSolarSystem(NULL),
26     selection(),
27     faintestVisible(5.0f),
28     pauseState(false)
29 {
30     activeObserver = new Observer();
31     observers.insert(observers.end(), activeObserver);
32 }
33 
34 
~Simulation()35 Simulation::~Simulation()
36 {
37     for (vector<Observer*>::iterator iter = observers.begin();
38          iter != observers.end(); iter++)
39     {
40         delete *iter;
41     }
42 }
43 
44 
getSun(Body * body)45 static const Star* getSun(Body* body)
46 {
47     PlanetarySystem* system = body->getSystem();
48     if (system == NULL)
49         return NULL;
50     else
51         return system->getStar();
52 }
53 
54 
render(Renderer & renderer)55 void Simulation::render(Renderer& renderer)
56 {
57     renderer.render(*activeObserver,
58                     *universe,
59                     faintestVisible,
60                     selection);
61 }
62 
draw(Renderer & renderer)63 void Simulation::draw(Renderer& renderer)
64 {
65     renderer.draw(*activeObserver,
66                   *universe,
67                   faintestVisible,
68                   selection);
69 }
70 
71 
render(Renderer & renderer,Observer & observer)72 void Simulation::render(Renderer& renderer, Observer& observer)
73 {
74     renderer.render(observer,
75                     *universe,
76                     faintestVisible,
77                     selection);
78 }
79 
80 
getUniverse() const81 Universe* Simulation::getUniverse() const
82 {
83     return universe;
84 }
85 
86 
87 // Get the time (Julian date)
getTime() const88 double Simulation::getTime() const
89 {
90     return activeObserver->getTime();
91 }
92 
93 // Set the time to the specified Julian date
setTime(double jd)94 void Simulation::setTime(double jd)
95 {
96     if (syncTime)
97     {
98         for (vector<Observer*>::iterator iter = observers.begin();
99              iter != observers.end(); iter++)
100         {
101             (*iter)->setTime(jd);
102         }
103     }
104     else
105     {
106         activeObserver->setTime(jd);
107     }
108 }
109 
110 
111 // Get the clock time elapsed since the object was created
getRealTime() const112 double Simulation::getRealTime() const
113 {
114     return realTime;
115 }
116 
117 
getArrivalTime() const118 double Simulation::getArrivalTime() const
119 {
120     return activeObserver->getArrivalTime();
121 }
122 
123 
124 // Tick the simulation by dt seconds
update(double dt)125 void Simulation::update(double dt)
126 {
127     realTime += dt;
128 
129     for (vector<Observer*>::iterator iter = observers.begin();
130          iter != observers.end(); iter++)
131     {
132         (*iter)->update(dt, timeScale);
133     }
134 
135     // Find the closest solar system
136     closestSolarSystem = universe->getNearestSolarSystem(activeObserver->getPosition());
137 }
138 
139 
getSelection() const140 Selection Simulation::getSelection() const
141 {
142     return selection;
143 }
144 
145 
setSelection(const Selection & sel)146 void Simulation::setSelection(const Selection& sel)
147 {
148     selection = sel;
149 }
150 
151 
getTrackedObject() const152 Selection Simulation::getTrackedObject() const
153 {
154     return activeObserver->getTrackedObject();
155 }
156 
157 
setTrackedObject(const Selection & sel)158 void Simulation::setTrackedObject(const Selection& sel)
159 {
160     activeObserver->setTrackedObject(sel);
161 }
162 
163 
pickObject(Vec3f pickRay,int renderFlags,float tolerance)164 Selection Simulation::pickObject(Vec3f pickRay, int renderFlags, float tolerance)
165 {
166     return universe->pick(activeObserver->getPosition(),
167                           pickRay * activeObserver->getOrientationf().toMatrix4(),
168                           activeObserver->getTime(),
169                           renderFlags,
170                           faintestVisible,
171                           tolerance);
172 }
173 
reverseObserverOrientation()174 void Simulation::reverseObserverOrientation()
175 {
176     activeObserver->reverseOrientation();
177 }
178 
179 
getObserver()180 Observer& Simulation::getObserver()
181 {
182     return *activeObserver;
183 }
184 
185 
addObserver()186 Observer* Simulation::addObserver()
187 {
188     Observer* o = new Observer();
189     observers.insert(observers.end(), o);
190     return o;
191 }
192 
193 
removeObserver(Observer * o)194 void Simulation::removeObserver(Observer* o)
195 {
196     vector<Observer*>::iterator iter = find(observers.begin(), observers.end(), o);
197     if (iter != observers.end())
198         observers.erase(iter);
199 }
200 
201 
getActiveObserver()202 Observer* Simulation::getActiveObserver()
203 {
204     return activeObserver;
205 }
206 
207 
setActiveObserver(Observer * o)208 void Simulation::setActiveObserver(Observer* o)
209 {
210     vector<Observer*>::iterator iter= find(observers.begin(), observers.end(), o);
211     if (iter != observers.end())
212         activeObserver = o;
213 }
214 
215 
setObserverPosition(const UniversalCoord & pos)216 void Simulation::setObserverPosition(const UniversalCoord& pos)
217 {
218     activeObserver->setPosition(pos);
219 }
220 
setObserverOrientation(const Quatf & orientation)221 void Simulation::setObserverOrientation(const Quatf& orientation)
222 {
223     activeObserver->setOrientation(orientation);
224 }
225 
226 
getObserverMode() const227 Observer::ObserverMode Simulation::getObserverMode() const
228 {
229     return activeObserver->getMode();
230 }
231 
setObserverMode(Observer::ObserverMode mode)232 void Simulation::setObserverMode(Observer::ObserverMode mode)
233 {
234     activeObserver->setMode(mode);
235 }
236 
setFrame(ObserverFrame::CoordinateSystem coordSys,const Selection & refObject,const Selection & targetObject)237 void Simulation::setFrame(ObserverFrame::CoordinateSystem coordSys,
238                           const Selection& refObject,
239                           const Selection& targetObject)
240 {
241     activeObserver->setFrame(coordSys, refObject, targetObject);
242 }
243 
setFrame(ObserverFrame::CoordinateSystem coordSys,const Selection & refObject)244 void Simulation::setFrame(ObserverFrame::CoordinateSystem coordSys,
245                           const Selection& refObject)
246 {
247     activeObserver->setFrame(coordSys, refObject);
248 }
249 
getFrame() const250 const ObserverFrame* Simulation::getFrame() const
251 {
252     return activeObserver->getFrame();
253 }
254 
255 // Rotate the observer about its center.
rotate(Quatf q)256 void Simulation::rotate(Quatf q)
257 {
258     activeObserver->rotate(q);
259 }
260 
261 // Orbit around the selection (if there is one.)  This involves changing
262 // both the observer's position and orientation.
orbit(Quatf q)263 void Simulation::orbit(Quatf q)
264 {
265     activeObserver->orbit(selection, q);
266 }
267 
268 
269 // Exponential camera dolly--move toward or away from the selected object
270 // at a rate dependent on the observer's distance from the object.
changeOrbitDistance(float d)271 void Simulation::changeOrbitDistance(float d)
272 {
273     activeObserver->changeOrbitDistance(selection, d);
274 }
275 
276 
setTargetSpeed(float s)277 void Simulation::setTargetSpeed(float s)
278 {
279     activeObserver->setTargetSpeed(s);
280 }
281 
getTargetSpeed()282 float Simulation::getTargetSpeed()
283 {
284     return activeObserver->getTargetSpeed();
285 }
286 
gotoSelection(double gotoTime,Vec3f up,ObserverFrame::CoordinateSystem upFrame)287 void Simulation::gotoSelection(double gotoTime,
288                                Vec3f up,
289                                ObserverFrame::CoordinateSystem upFrame)
290 {
291     if (selection.getType() == Selection::Type_Location)
292     {
293         activeObserver->gotoSelectionGC(selection,
294                                         gotoTime, 0.0, 0.5,
295                                         up, upFrame);
296     }
297     else
298     {
299         activeObserver->gotoSelection(selection, gotoTime, up, upFrame);
300     }
301 }
302 
gotoSelection(double gotoTime,double distance,Vec3f up,ObserverFrame::CoordinateSystem upCoordSys)303 void Simulation::gotoSelection(double gotoTime,
304                                double distance,
305                                Vec3f up,
306                                ObserverFrame::CoordinateSystem upCoordSys)
307 {
308     activeObserver->gotoSelection(selection, gotoTime, distance, up, upCoordSys);
309 }
310 
gotoSelectionLongLat(double gotoTime,double distance,float longitude,float latitude,Vec3f up)311 void Simulation::gotoSelectionLongLat(double gotoTime,
312                                       double distance,
313                                       float longitude,
314                                       float latitude,
315                                       Vec3f up)
316 {
317     activeObserver->gotoSelectionLongLat(selection, gotoTime, distance,
318                                          longitude, latitude, up);
319 }
320 
321 
gotoLocation(const UniversalCoord & position,const Quatd & orientation,double duration)322 void Simulation::gotoLocation(const UniversalCoord& position,
323                               const Quatd& orientation,
324                               double duration)
325 {
326     activeObserver->gotoLocation(position, orientation, duration);
327 }
328 
329 
getSelectionLongLat(double & distance,double & longitude,double & latitude)330 void Simulation::getSelectionLongLat(double& distance,
331                                      double& longitude,
332                                      double& latitude)
333 {
334     activeObserver->getSelectionLongLat(selection, distance, longitude, latitude);
335 }
336 
337 
gotoSurface(double duration)338 void Simulation::gotoSurface(double duration)
339 {
340     activeObserver->gotoSurface(selection, duration);
341 };
342 
343 
cancelMotion()344 void Simulation::cancelMotion()
345 {
346     activeObserver->cancelMotion();
347 }
348 
centerSelection(double centerTime)349 void Simulation::centerSelection(double centerTime)
350 {
351     activeObserver->centerSelection(selection, centerTime);
352 }
353 
centerSelectionCO(double centerTime)354 void Simulation::centerSelectionCO(double centerTime)
355 {
356     activeObserver->centerSelectionCO(selection, centerTime);
357 }
358 
follow()359 void Simulation::follow()
360 {
361     activeObserver->follow(selection);
362 }
363 
geosynchronousFollow()364 void Simulation::geosynchronousFollow()
365 {
366     activeObserver->geosynchronousFollow(selection);
367 }
368 
phaseLock()369 void Simulation::phaseLock()
370 {
371     activeObserver->phaseLock(selection);
372 }
373 
chase()374 void Simulation::chase()
375 {
376     activeObserver->chase(selection);
377 }
378 
379 
380 // Choose a planet around a star given it's index in the planetary system.
381 // The planetary system is either the system of the selected object, or the
382 // nearest planetary system if no object is selected.  If index is less than
383 // zero, pick the star.  This function should probably be in celestiacore.cpp.
selectPlanet(int index)384 void Simulation::selectPlanet(int index)
385 {
386     if (index < 0)
387     {
388         if (selection.getType() == Selection::Type_Body)
389         {
390             PlanetarySystem* system = selection.body()->getSystem();
391             if (system != NULL)
392                 setSelection(system->getStar());
393         }
394     }
395     else
396     {
397         const Star* star = NULL;
398         if (selection.getType() == Selection::Type_Star)
399             star = selection.star();
400         else if (selection.getType() == Selection::Type_Body)
401             star = getSun(selection.body());
402 
403         SolarSystem* solarSystem = NULL;
404         if (star != NULL)
405             solarSystem = universe->getSolarSystem(star);
406         else
407             solarSystem = closestSolarSystem;
408 
409         if (solarSystem != NULL &&
410             index < solarSystem->getPlanets()->getSystemSize())
411         {
412             setSelection(Selection(solarSystem->getPlanets()->getBody(index)));
413         }
414     }
415 }
416 
417 
418 // Select an object by name, with the following priority:
419 //   1. Try to look up the name in the star database
420 //   2. Search the deep sky catalog for a matching name.
421 //   3. Search the planets and moons in the planetary system of the currently selected
422 //      star
423 //   4. Search the planets and moons in any 'nearby' (< 0.1 ly) planetary systems
findObject(string s,bool i18n)424 Selection Simulation::findObject(string s, bool i18n)
425 {
426     Selection path[2];
427     int nPathEntries = 0;
428 
429     if (!selection.empty())
430         path[nPathEntries++] = selection;
431 
432     if (closestSolarSystem != NULL)
433         path[nPathEntries++] = Selection(closestSolarSystem->getStar());
434 
435     return universe->find(s, path, nPathEntries, i18n);
436 }
437 
438 
439 // Find an object from a path, for example Sol/Earth/Moon or Upsilon And/b
440 // Currently, 'absolute' paths starting with a / are not supported nor are
441 // paths that contain galaxies.
findObjectFromPath(string s,bool i18n)442 Selection Simulation::findObjectFromPath(string s, bool i18n)
443 {
444     Selection path[2];
445     int nPathEntries = 0;
446 
447     if (!selection.empty())
448         path[nPathEntries++] = selection;
449 
450     if (closestSolarSystem != NULL)
451         path[nPathEntries++] = Selection(closestSolarSystem->getStar());
452 
453     return universe->findPath(s, path, nPathEntries, i18n);
454 }
455 
456 
getObjectCompletion(string s,bool withLocations)457 vector<std::string> Simulation::getObjectCompletion(string s, bool withLocations)
458 {
459     Selection path[2];
460     int nPathEntries = 0;
461 
462     if (!selection.empty()) {
463         if (selection.getType() == Selection::Type_Location)
464         {
465             path[nPathEntries++] = Selection(selection.location()->getParentBody());
466         }
467         else
468         {
469             path[nPathEntries++] = selection;
470         }
471     }
472 
473     if (closestSolarSystem != NULL &&
474         closestSolarSystem != universe->getSolarSystem(selection))
475     {
476         path[nPathEntries++] = Selection(closestSolarSystem->getStar());
477     }
478 
479     return universe->getCompletionPath(s, path, nPathEntries, withLocations);
480 }
481 
482 
getTimeScale() const483 double Simulation::getTimeScale() const
484 {
485     return pauseState?storedTimeScale:timeScale;
486 }
487 
setTimeScale(double _timeScale)488 void Simulation::setTimeScale(double _timeScale)
489 {
490     if (pauseState == true)
491     {
492         storedTimeScale = _timeScale;
493     }
494     else
495     {
496         timeScale = _timeScale;
497     }
498 }
499 
getSyncTime() const500 bool Simulation::getSyncTime() const
501 {
502     return syncTime;
503 }
504 
setSyncTime(bool sync)505 void Simulation::setSyncTime(bool sync)
506 {
507     syncTime = sync;
508 }
509 
getPauseState() const510 bool Simulation::getPauseState() const
511 {
512     return pauseState;
513 }
514 
setPauseState(bool state)515 void Simulation::setPauseState(bool state)
516 {
517     if (pauseState == state) return;
518 
519     pauseState = state;
520     if (pauseState == true)
521     {
522         storedTimeScale = timeScale;
523         timeScale = 0.0;
524     }
525     else
526     {
527         timeScale = storedTimeScale;
528     }
529 }
530 
531 // Synchronize all observers to active observer time
synchronizeTime()532 void Simulation::synchronizeTime()
533 {
534     for (vector<Observer*>::iterator iter = observers.begin();
535          iter != observers.end(); iter++)
536     {
537         (*iter)->setTime(activeObserver->getTime());
538     }
539 }
540 
541 
getFaintestVisible() const542 float Simulation::getFaintestVisible() const
543 {
544     return faintestVisible;
545 }
546 
547 
setFaintestVisible(float magnitude)548 void Simulation::setFaintestVisible(float magnitude)
549 {
550     faintestVisible = magnitude;
551 }
552 
553 
getNearestSolarSystem() const554 SolarSystem* Simulation::getNearestSolarSystem() const
555 {
556     return closestSolarSystem;
557 }
558