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