celestia/src/celengine/simulation.cpp

550 lines
12 KiB
C++

// simulation.cpp
//
// Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
//
// The core of Celestia--tracks an observer moving through a
// stars and their solar systems.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <algorithm>
#include <celutil/strnatcmp.h>
#include "render.h"
#include "simulation.h"
using namespace Eigen;
using namespace std;
Simulation::Simulation(Universe* _universe) :
universe(_universe)
{
activeObserver = new Observer();
observers.push_back(activeObserver);
}
Simulation::~Simulation()
{
for (const auto observer : observers)
delete observer;
}
static const Star* getSun(Body* body)
{
PlanetarySystem* system = body->getSystem();
return system ? system->getStar() : nullptr;
}
void Simulation::render(Renderer& renderer)
{
renderer.render(*activeObserver,
*universe,
faintestVisible,
selection);
}
void Simulation::draw(Renderer& renderer)
{
renderer.draw(*activeObserver,
*universe,
faintestVisible,
selection);
}
void Simulation::render(Renderer& renderer, Observer& observer)
{
renderer.render(observer,
*universe,
faintestVisible,
selection);
}
Universe* Simulation::getUniverse() const
{
return universe;
}
// Get the time (Julian date)
double Simulation::getTime() const
{
return activeObserver->getTime();
}
// Set the time to the specified Julian date
void Simulation::setTime(double jd)
{
if (syncTime)
{
for (const auto observer : observers)
{
observer->setTime(jd);
}
}
else
{
activeObserver->setTime(jd);
}
}
// Get the clock time elapsed since the object was created
double Simulation::getRealTime() const
{
return realTime;
}
double Simulation::getArrivalTime() const
{
return activeObserver->getArrivalTime();
}
// Tick the simulation by dt seconds
void Simulation::update(double dt)
{
realTime += dt;
for (const auto observer : observers)
{
observer->update(dt, timeScale);
}
// Find the closest solar system
closestSolarSystem = universe->getNearestSolarSystem(activeObserver->getPosition());
}
Selection Simulation::getSelection() const
{
return selection;
}
void Simulation::setSelection(const Selection& sel)
{
selection = sel;
}
Selection Simulation::getTrackedObject() const
{
return activeObserver->getTrackedObject();
}
void Simulation::setTrackedObject(const Selection& sel)
{
activeObserver->setTrackedObject(sel);
}
Selection Simulation::pickObject(const Vector3f& pickRay, uint64_t renderFlags, float tolerance)
{
return universe->pick(activeObserver->getPosition(),
activeObserver->getOrientationf().conjugate() * pickRay,
activeObserver->getTime(),
renderFlags,
faintestVisible,
tolerance);
}
void Simulation::reverseObserverOrientation()
{
activeObserver->reverseOrientation();
}
Observer& Simulation::getObserver()
{
return *activeObserver;
}
Observer* Simulation::addObserver()
{
Observer* o = new Observer();
observers.push_back(o);
return o;
}
void Simulation::removeObserver(Observer* o)
{
auto iter = find(observers.begin(), observers.end(), o);
if (iter != observers.end())
observers.erase(iter);
}
Observer* Simulation::getActiveObserver()
{
return activeObserver;
}
void Simulation::setActiveObserver(Observer* o)
{
auto iter = find(observers.begin(), observers.end(), o);
if (iter != observers.end())
activeObserver = o;
}
void Simulation::setObserverPosition(const UniversalCoord& pos)
{
activeObserver->setPosition(pos);
}
void Simulation::setObserverOrientation(const Quaternionf& orientation)
{
activeObserver->setOrientation(orientation);
}
Observer::ObserverMode Simulation::getObserverMode() const
{
return activeObserver->getMode();
}
void Simulation::setObserverMode(Observer::ObserverMode mode)
{
activeObserver->setMode(mode);
}
void Simulation::setFrame(ObserverFrame::CoordinateSystem coordSys,
const Selection& refObject,
const Selection& targetObject)
{
activeObserver->setFrame(coordSys, refObject, targetObject);
}
void Simulation::setFrame(ObserverFrame::CoordinateSystem coordSys,
const Selection& refObject)
{
activeObserver->setFrame(coordSys, refObject);
}
const ObserverFrame::SharedConstPtr& Simulation::getFrame() const
{
return activeObserver->getFrame();
}
// Rotate the observer about its center.
void Simulation::rotate(const Quaternionf& q)
{
activeObserver->rotate(q);
}
// Orbit around the selection (if there is one.) This involves changing
// both the observer's position and orientation.
void Simulation::orbit(const Quaternionf& q)
{
activeObserver->orbit(selection, q);
}
// Exponential camera dolly--move toward or away from the selected object
// at a rate dependent on the observer's distance from the object.
void Simulation::changeOrbitDistance(float d)
{
activeObserver->changeOrbitDistance(selection, d);
}
void Simulation::setTargetSpeed(float s)
{
activeObserver->setTargetSpeed(s);
}
float Simulation::getTargetSpeed()
{
return activeObserver->getTargetSpeed();
}
void Simulation::gotoSelection(double gotoTime,
const Vector3f& up,
ObserverFrame::CoordinateSystem upFrame)
{
if (selection.getType() == Selection::Type_Location)
{
activeObserver->gotoSelectionGC(selection,
gotoTime,
up, upFrame);
}
else
{
activeObserver->gotoSelection(selection, gotoTime, up, upFrame);
}
}
void Simulation::gotoSelection(double gotoTime,
double distance,
const Vector3f& up,
ObserverFrame::CoordinateSystem upCoordSys)
{
activeObserver->gotoSelection(selection, gotoTime, distance, up, upCoordSys);
}
void Simulation::gotoSelectionLongLat(double gotoTime,
double distance,
float longitude,
float latitude,
const Vector3f& up)
{
activeObserver->gotoSelectionLongLat(selection, gotoTime, distance,
longitude, latitude, up);
}
void Simulation::gotoLocation(const UniversalCoord& position,
const Quaterniond& orientation,
double duration)
{
activeObserver->gotoLocation(position, orientation, duration);
}
void Simulation::getSelectionLongLat(double& distance,
double& longitude,
double& latitude)
{
activeObserver->getSelectionLongLat(selection, distance, longitude, latitude);
}
void Simulation::gotoSurface(double duration)
{
activeObserver->gotoSurface(selection, duration);
}
void Simulation::cancelMotion()
{
activeObserver->cancelMotion();
}
void Simulation::centerSelection(double centerTime)
{
activeObserver->centerSelection(selection, centerTime);
}
void Simulation::centerSelectionCO(double centerTime)
{
activeObserver->centerSelectionCO(selection, centerTime);
}
void Simulation::follow()
{
activeObserver->follow(selection);
}
void Simulation::geosynchronousFollow()
{
activeObserver->geosynchronousFollow(selection);
}
void Simulation::phaseLock()
{
activeObserver->phaseLock(selection);
}
void Simulation::chase()
{
activeObserver->chase(selection);
}
// Choose a planet around a star given it's index in the planetary system.
// The planetary system is either the system of the selected object, or the
// nearest planetary system if no object is selected. If index is less than
// zero, pick the star. This function should probably be in celestiacore.cpp.
void Simulation::selectPlanet(int index)
{
if (index < 0)
{
if (selection.getType() == Selection::Type_Body)
{
PlanetarySystem* system = selection.body()->getSystem();
if (system != nullptr)
setSelection(system->getStar());
}
}
else
{
const Star* star = nullptr;
if (selection.getType() == Selection::Type_Star)
star = selection.star();
else if (selection.getType() == Selection::Type_Body)
star = getSun(selection.body());
SolarSystem* solarSystem = nullptr;
if (star != nullptr)
solarSystem = universe->getSolarSystem(star);
else
solarSystem = closestSolarSystem;
if (solarSystem != nullptr &&
index < solarSystem->getPlanets()->getSystemSize())
{
setSelection(Selection(solarSystem->getPlanets()->getBody(index)));
}
}
}
// Select an object by name, with the following priority:
// 1. Try to look up the name in the star database
// 2. Search the deep sky catalog for a matching name.
// 3. Search the planets and moons in the planetary system of the currently selected
// star
// 4. Search the planets and moons in any 'nearby' (< 0.1 ly) planetary systems
Selection Simulation::findObject(string s, bool i18n)
{
Selection path[2];
int nPathEntries = 0;
if (!selection.empty())
path[nPathEntries++] = selection;
if (closestSolarSystem != nullptr)
path[nPathEntries++] = Selection(closestSolarSystem->getStar());
return universe->find(s, path, nPathEntries, i18n);
}
// Find an object from a path, for example Sol/Earth/Moon or Upsilon And/b
// Currently, 'absolute' paths starting with a / are not supported nor are
// paths that contain galaxies.
Selection Simulation::findObjectFromPath(string s, bool i18n)
{
Selection path[2];
int nPathEntries = 0;
if (!selection.empty())
path[nPathEntries++] = selection;
if (closestSolarSystem != nullptr)
path[nPathEntries++] = Selection(closestSolarSystem->getStar());
return universe->findPath(s, path, nPathEntries, i18n);
}
vector<std::string> Simulation::getObjectCompletion(string s, bool i18n, bool withLocations)
{
Selection path[2];
int nPathEntries = 0;
if (!selection.empty())
{
if (selection.getType() == Selection::Type_Location)
{
path[nPathEntries++] = Selection(selection.location()->getParentBody());
}
else
{
path[nPathEntries++] = selection;
}
}
if (closestSolarSystem != nullptr &&
closestSolarSystem != universe->getSolarSystem(selection))
{
path[nPathEntries++] = Selection(closestSolarSystem->getStar());
}
auto completion = universe->getCompletionPath(s, i18n, path, nPathEntries, withLocations);
sort(begin(completion), end(completion),
[](const string &s1, const string &s2) { return strnatcmp(s1, s2) < 0; });
return completion;
}
double Simulation::getTimeScale() const
{
return pauseState?storedTimeScale:timeScale;
}
void Simulation::setTimeScale(double _timeScale)
{
if (pauseState)
{
storedTimeScale = _timeScale;
}
else
{
timeScale = _timeScale;
}
}
bool Simulation::getSyncTime() const
{
return syncTime;
}
void Simulation::setSyncTime(bool sync)
{
syncTime = sync;
}
bool Simulation::getPauseState() const
{
return pauseState;
}
void Simulation::setPauseState(bool state)
{
if (pauseState == state) return;
pauseState = state;
if (pauseState)
{
storedTimeScale = timeScale;
timeScale = 0.0;
}
else
{
timeScale = storedTimeScale;
}
}
// Synchronize all observers to active observer time
void Simulation::synchronizeTime()
{
for (const auto observer : observers)
{
observer->setTime(activeObserver->getTime());
}
}
float Simulation::getFaintestVisible() const
{
return faintestVisible;
}
void Simulation::setFaintestVisible(float magnitude)
{
faintestVisible = magnitude;
}
SolarSystem* Simulation::getNearestSolarSystem() const
{
return closestSolarSystem;
}