Added support for a new cel URL version that stores frame coordinates instead

of absolute coordinates and adds the time source option. Modified Qt4 front
end to create version 3 cel URLs. Added a time source option to the Qt4
Add Bookmark dialog.
ver1_6_1
Chris Laurel 2008-05-05 19:09:31 +00:00
parent 7987750092
commit d1139852b7
7 changed files with 738 additions and 297 deletions

View File

@ -8,75 +8,72 @@
<rect>
<x>0</x>
<y>0</y>
<width>412</width>
<height>175</height>
<width>360</width>
<height>188</height>
</rect>
</property>
<property name="windowTitle" >
<string>Bookmark Location</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="geometry" >
<rect>
<x>40</x>
<y>120</y>
<width>341</width>
<height>32</height>
</rect>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QLabel" name="label" >
<property name="geometry" >
<rect>
<x>30</x>
<y>20</y>
<width>191</width>
<height>18</height>
</rect>
</property>
<property name="text" >
<string>Bookmark name:</string>
</property>
</widget>
<widget class="QLabel" name="label_2" >
<property name="geometry" >
<rect>
<x>30</x>
<y>70</y>
<width>191</width>
<height>18</height>
</rect>
</property>
<property name="text" >
<string>Create in:</string>
</property>
</widget>
<widget class="QLineEdit" name="bookmarkNameEdit" >
<property name="geometry" >
<rect>
<x>190</x>
<y>20</y>
<width>181</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QComboBox" name="createInCombo" >
<property name="geometry" >
<rect>
<x>190</x>
<y>60</y>
<width>181</width>
<height>26</height>
</rect>
</property>
</widget>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Bookmark name:</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="bookmarkNameEdit" />
</item>
<item row="1" column="1" >
<widget class="QComboBox" name="createInCombo" />
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Create in:</string>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Time source:</string>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QComboBox" name="timeSourceCombo" />
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>24</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>

View File

@ -5,124 +5,106 @@
<rect>
<x>0</x>
<y>0</y>
<width>408</width>
<height>235</height>
<width>426</width>
<height>221</height>
</rect>
</property>
<property name="windowTitle" >
<string>New Folder</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="geometry" >
<rect>
<x>10</x>
<y>190</y>
<width>379</width>
<height>25</height>
</rect>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
<widget class="QLabel" name="label" >
<property name="geometry" >
<rect>
<x>12</x>
<y>23</y>
<width>57</width>
<height>16</height>
</rect>
</property>
<property name="text" >
<string>Name:</string>
</property>
</widget>
<widget class="QLineEdit" name="nameEdit" >
<property name="geometry" >
<rect>
<x>78</x>
<y>23</y>
<width>311</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_2" >
<property name="geometry" >
<rect>
<x>11</x>
<y>141</y>
<width>187</width>
<height>20</height>
</rect>
</property>
<property name="text" >
<string>Create in:</string>
</property>
</widget>
<widget class="QComboBox" name="createInCombo" >
<property name="geometry" >
<rect>
<x>80</x>
<y>140</y>
<width>186</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QWidget" name="" >
<property name="geometry" >
<rect>
<x>11</x>
<y>50</y>
<width>379</width>
<height>71</height>
</rect>
</property>
<layout class="QHBoxLayout" >
<item>
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Description:</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTextEdit" name="descriptionEdit" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<layout class="QVBoxLayout" name="verticalLayout_2" >
<item>
<layout class="QGridLayout" name="gridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Name:</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="nameEdit" />
</item>
<item row="1" column="1" >
<widget class="QTextEdit" name="descriptionEdit" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Create in:</string>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QComboBox" name="createInCombo" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="0" >
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Description:</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>20</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>399</width>
<height>13</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>

View File

@ -614,7 +614,10 @@ void CelestiaAppWindow::slotCopyImage()
void CelestiaAppWindow::slotCopyURL()
{
Url url(m_appCore);
CelestiaState appState;
appState.captureState(m_appCore);
Url url(appState, 3);
QApplication::clipboard()->setText(url.getAsString().c_str());
m_appCore->flash(tr("Copied URL").toUtf8().data());
}
@ -792,10 +795,9 @@ void CelestiaAppWindow::slotAddBookmark()
if (defaultTitle.isEmpty())
defaultTitle = tr("New bookmark");
Url url(m_appCore);
QString urlText(url.getAsString().c_str());
CelestiaState appState;
appState.captureState(m_appCore);
// Capture the current frame buffer to use as a bookmark icon.
QImage grabbedImage = glWidget->grabFrameBuffer();
int width = grabbedImage.width();
@ -808,7 +810,7 @@ void CelestiaAppWindow::slotAddBookmark()
else
iconImage = grabbedImage.copy(0, (height - width) / 2, width, width);
AddBookmarkDialog dialog(m_bookmarkManager, defaultTitle, urlText, iconImage);
AddBookmarkDialog dialog(m_bookmarkManager, defaultTitle, appState, iconImage);
dialog.exec();
populateBookmarkMenu();

View File

@ -19,6 +19,7 @@
#include <QStringList>
#include <QMenu>
#include "xbel.h"
#include "celestia/url.h"
BookmarkItem::BookmarkItem(Type type, BookmarkItem* parent) :
@ -804,13 +805,15 @@ public:
};
int AddBookmarkDialog::m_lastTimeSourceIndex = 0;
AddBookmarkDialog::AddBookmarkDialog(BookmarkManager* manager,
QString defaultTitle,
QString url,
const CelestiaState& appState,
const QImage& iconImage) :
m_manager(manager),
m_filterModel(NULL),
m_url(url),
m_appState(appState),
m_iconImage(iconImage)
{
setupUi(this);
@ -833,6 +836,11 @@ AddBookmarkDialog::AddBookmarkDialog(BookmarkManager* manager,
createInCombo->setModel(m_filterModel);
view->show();
createInCombo->setView(view);
timeSourceCombo->addItem(tr("Current simulation time"), (int) Url::UseUrlTime);
timeSourceCombo->addItem(tr("Simulation time at activation"), (int) Url::UseSimulationTime);
timeSourceCombo->addItem(tr("System time at activation"), (int) Url::UseSystemTime);
timeSourceCombo->setCurrentIndex(m_lastTimeSourceIndex);
// Initialize to first index
QModelIndex firstItemIndex = m_filterModel->index(0, 0, QModelIndex());
@ -848,10 +856,20 @@ AddBookmarkDialog::accept()
index = m_filterModel->mapToSource(index);
if (index.isValid())
{
// Preserve the last used time source index
m_lastTimeSourceIndex = timeSourceCombo->currentIndex();
QVariant itemData = timeSourceCombo->itemData(timeSourceCombo->currentIndex());
Url::TimeSource timeSource = (Url::TimeSource) itemData.toInt();
Q_ASSERT(timeSource >= 0 && timeSource < Url::TimeSourceCount);
// Get the URL string
Url url(m_appState, Url::CurrentVersion, timeSource);
BookmarkItem* folder = m_manager->model()->getItem(index);
BookmarkItem* newItem = new BookmarkItem(BookmarkItem::Bookmark, folder);
newItem->setTitle(bookmarkNameEdit->text());
newItem->setUrl(m_url);
newItem->setUrl(QString::fromUtf8(url.getAsString().c_str()));
newItem->setIcon(QIcon(QPixmap::fromImage(m_iconImage.scaled(BookmarkItem::ICON_SIZE, BookmarkItem::ICON_SIZE,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation))));

View File

@ -26,6 +26,7 @@
class QSortFilterProxyModel;
class QMenu;
class CelestiaState;
class BookmarkItem
{
@ -180,7 +181,7 @@ class AddBookmarkDialog : public QDialog, Ui_addBookmarkDialog
public:
AddBookmarkDialog(BookmarkManager* manager,
QString defaultTitle,
QString url,
const CelestiaState& appState,
const QImage& iconImage);
public slots:
@ -189,8 +190,10 @@ public slots:
private:
BookmarkManager* m_manager;
QSortFilterProxyModel* m_filterModel;
QString m_url;
const CelestiaState& m_appState;
QImage m_iconImage;
static int m_lastTimeSourceIndex;
};

View File

@ -18,11 +18,147 @@
#include <string>
#include <cstdio>
#include <cassert>
#include <sstream>
#include "celestiacore.h"
#include "celengine/astro.h"
#include "url.h"
static const unsigned int CurrentCelestiaURLVersion = 2;
using namespace std;
const unsigned int Url::CurrentVersion = 3;
static string getSelectionName(const Selection& sel, CelestiaCore* appCore);
CelestiaState::CelestiaState() :
coordSys(ObserverFrame::Universal),
observerPosition(0.0, 0.0, 0.0),
observerOrientation(1.0f),
fieldOfView(45.0f),
tdb(0.0),
timeScale(1.0f),
pauseState(false),
lightTimeDelay(false),
labelMode(0),
renderFlags(0)
{
}
void
CelestiaState::captureState(CelestiaCore* appCore)
{
Simulation *sim = appCore->getSimulation();
Renderer *renderer = appCore->getRenderer();
const ObserverFrame* frame = sim->getFrame();
coordSys = frame->getCoordinateSystem();
if (coordSys != ObserverFrame::Universal)
{
refBodyName = getSelectionName(frame->getRefObject(), appCore);
if (coordSys == ObserverFrame::PhaseLock)
{
targetBodyName = getSelectionName(frame->getTargetObject(), appCore);
}
}
tdb = sim->getTime();
// Store the position and orientation of the observer in the current
// frame.
observerPosition = sim->getObserver().getPosition();
observerPosition = frame->convertFromUniversal(observerPosition, tdb);
Quatd q = sim->getObserver().getOrientation();
q = frame->convertFromUniversal(q, tdb);
observerOrientation = Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z);
Selection tracked = sim->getTrackedObject();
trackedBodyName = getSelectionName(tracked, appCore);
Selection selected = sim->getSelection();
selectedBodyName = getSelectionName(selected, appCore);
fieldOfView = radToDeg(sim->getActiveObserver()->getFOV());
timeScale = (float) sim->getTimeScale();
pauseState = sim->getPauseState();
lightTimeDelay = appCore->getLightDelayActive();
renderFlags = renderer->getRenderFlags();
labelMode = renderer->getLabelMode();
}
#if 0
bool CelestiaState::loadState(std::map<std::string, std::string> params)
{
sscanf(timeString.c_str(), "%d-%d-%dT%d:%d:%lf",
&date.year, &date.month, &date.day,
&date.hour, &date.minute, &date.seconds);
observerPosition = UniversalCoord(BigFix(params["x"]),
BigFix(params["y"]),
BigFix(params["z"]));
float ow = 0.0f;
float ox = 0.0f;
float oy = 0.0f;
float oz = 0.0f;
if (sscanf(params["ow"].c_str(), "%f", &ow) != 1 ||
sscanf(params["ox"].c_str(), "%f", &ox) != 1 ||
sscanf(params["oy"].c_str(), "%f", &oy) != 1 ||
sscanf(params["oz"].c_str(), "%f", &oz) != 1)
{
return false;
}
orientation = Quatf(ow, ox, oy, oz);
if (params["select"] != "")
selectedBodyName = params["select"];
if (params["track"] != "")
trackedBodyName = params["track"];
if (params["ltd"] != "")
lightTimeDelay = (strcmp(params["ltd"].c_str(), "1") == 0);
else
lightTimeDelay = false;
if (params["fov"] != "")
{
if (sscanf(params["fov"].c_str(), "%f", &fieldOfView) != 1.0f)
return false;
}
if (params["ts"] != "")
{
if (sscanf(params["ts"].c_str(), "%f", &timeScale) != 1.0f)
return false;
}
int paused = 0;
if (params["p"] != "")
{
if (sscanf(params["p"].c_str(), "%d", &paused) != 1)
return false;
if (paused != 0 && paused != 1)
return false;
pauseState = paused == 1;
}
// Render settings
if (params["rf"] != "")
{
if (sscanf(params["rf"].c_str(), "%d", &renderFlags) != 1)
return false;
}
if (params["lm"] != "")
{
if (sscanf(params["lm"].c_str(), "%d", &labelMode) != 1)
return false;
}
}
#endif
Url::Url()
{};
@ -30,26 +166,40 @@ Url::Url()
Url::Url(const std::string& str, CelestiaCore *core):
urlStr(str),
appCore(core),
pauseState(false)
pauseState(false),
timeSource(UseUrlTime),
version(2)
{
std::string::size_type pos, endPrevious;
std::vector<Selection> bodies;
Simulation *sim = appCore->getSimulation();
std::map<std::string, std::string> params = parseUrlParams(urlStr);
if (urlStr.substr(0, 6) != "cel://")
{
urlStr = "";
return;
}
// Version labelling of cel URLs was only added in Celestia 1.5, cel URL
// version 2. Assume any URL without a version is version 1.
if (params["ver"] != "")
{
sscanf(params["ver"].c_str(), "%u", &version);
}
else
{
version = 1;
}
pos = urlStr.find("/", 6);
if (pos == std::string::npos) pos = urlStr.find("?", 6);
if (pos == std::string::npos) modeStr = urlStr.substr(6);
else modeStr = decode_string(urlStr.substr(6, pos - 6));
if (pos == std::string::npos)
pos = urlStr.find("?", 6);
if (pos == std::string::npos)
modeStr = urlStr.substr(6);
else
modeStr = decode_string(urlStr.substr(6, pos - 6));
if (!compareIgnoringCase(modeStr, std::string("Freeflight")))
{
@ -81,21 +231,13 @@ Url::Url(const std::string& str, CelestiaCore *core):
type = Settings;
nbBodies = 0;
}
if (nbBodies == -1)
{
urlStr = "";
return; // Mode not recognized
}
// Version labelling of cel URLs was only added in Celestia 1.5, cel URL
// version 2. Assume any URL without a version is version 1.
unsigned int version = 1;
if (params["ver"] != "")
{
sscanf(params["ver"].c_str(), "%u", &version);
}
endPrevious = pos;
int nb = nbBodies, i=1;
while (nb != 0 && endPrevious != std::string::npos) {
@ -105,7 +247,7 @@ Url::Url(const std::string& str, CelestiaCore *core):
if (pos == std::string::npos) bodyName = urlStr.substr(endPrevious + 1);
else bodyName = urlStr.substr(endPrevious + 1, pos - endPrevious - 1);
endPrevious = pos;
bodyName = decode_string(bodyName);
pos = 0;
if (i==1) body1 = bodyName;
@ -114,97 +256,42 @@ Url::Url(const std::string& str, CelestiaCore *core):
pos = bodyName.find(":", pos + 1);
if (pos != std::string::npos) bodyName[pos]='/';
}
bodies.push_back(sim->findObjectFromPath(bodyName));
nb--;
i++;
}
if (nb != 0) {
urlStr = "";
return; // Number of bodies in Url doesn't match Mode
}
if (nbBodies == 0) ref = ObserverFrame();
if (nbBodies == 1) ref = ObserverFrame(mode, bodies[0]);
if (nbBodies == 2) ref = ObserverFrame(mode, bodies[0], bodies[1]);
fromString = true;
std::string time="";
pos = urlStr.find("?", endPrevious + 1);
if (pos == std::string::npos) time = urlStr.substr(endPrevious + 1);
if (pos == std::string::npos)
time = urlStr.substr(endPrevious + 1);
else time = urlStr.substr(endPrevious + 1, pos - endPrevious -1);
time = decode_string(time);
if (type != Settings)
time = decode_string(time);
switch (version)
{
if (params["dist"] != "")
type = Relative;
else
type = Absolute;
}
switch (type) {
case Absolute:
date = astro::Date(0.0);
sscanf(time.c_str(), "%d-%d-%dT%d:%d:%lf",
&date.year, &date.month, &date.day,
&date.hour, &date.minute, &date.seconds);
coord = UniversalCoord(BigFix(params["x"]),
BigFix(params["y"]),
BigFix(params["z"]));
float ow, ox, oy, oz;
sscanf(params["ow"].c_str(), "%f", &ow);
sscanf(params["ox"].c_str(), "%f", &ox);
sscanf(params["oy"].c_str(), "%f", &oy);
sscanf(params["oz"].c_str(), "%f", &oz);
orientation = Quatf(ow, ox, oy, oz);
// Intentional Fall-Through
case Relative:
if (params["dist"] != "") {
sscanf(params["dist"].c_str(), "%lf", &distance);
}
if (params["long"] != "") {
sscanf(params["long"].c_str(), "%lf", &longitude);
}
if (params["lat"] != "") {
sscanf(params["lat"].c_str(), "%lf", &latitude);
}
if (params["select"] != "") {
selectedStr = params["select"];
}
if (params["track"] != "") {
trackedStr = params["track"];
}
if (params["ltd"] != "") {
lightTimeDelay = (strcmp(params["ltd"].c_str(), "1") == 0);
} else {
lightTimeDelay = false;
}
if (params["fov"] != "") {
sscanf(params["fov"].c_str(), "%f", &fieldOfView);
}
if (params["ts"] != "") {
sscanf(params["ts"].c_str(), "%f", &timeScale);
}
if (params["p"] != "") {
sscanf(params["p"].c_str(), "%d", &pauseState);
}
case 1:
case 2:
initVersion2(params, time);
break;
case Settings:
case 3:
initVersion3(params, time);
break;
}
if (params["rf"] != "") {
sscanf(params["rf"].c_str(), "%d", &renderFlags);
}
if (params["lm"] != "") {
sscanf(params["lm"].c_str(), "%d", &labelMode);
default:
urlStr = "";
return;
}
evalName();
@ -214,6 +301,9 @@ Url::Url(const std::string& str, CelestiaCore *core):
Url::Url(CelestiaCore* core, UrlType type)
{
appCore = core;
version = 2;
timeSource = UseUrlTime;
Simulation *sim = appCore->getSimulation();
Renderer *renderer = appCore->getRenderer();
@ -232,8 +322,10 @@ Url::Url(CelestiaCore* core, UrlType type)
}
}
double simTime = sim->getTime();
char date_str[50];
date = astro::Date(sim->getTime());
date = astro::Date(simTime);
char buff[255];
switch (type) {
@ -289,7 +381,7 @@ Url::Url(CelestiaCore* core, UrlType type)
// Append the Celestia URL version
{
char buf[32];
sprintf(buf, "&ver=%u", CurrentCelestiaURLVersion);
sprintf(buf, "&ver=%u", version);
urlStr += buf;
}
@ -297,6 +389,232 @@ Url::Url(CelestiaCore* core, UrlType type)
}
/*! Construct a new cel URL from a saved CelestiaState object. This method may
* may only be called to create a version 3 or later url.
*/
Url::Url(const CelestiaState& appState, unsigned int _version, TimeSource _timeSource)
{
ostringstream u;
appCore = NULL;
assert(_version >= 3);
version = _version;
timeSource = _timeSource;
type = Absolute;
modeStr = getCoordSysName(appState.coordSys);
body1 = appState.refBodyName;
body2 = appState.targetBodyName;
selectedStr = appState.selectedBodyName;
trackedStr = appState.trackedBodyName;
coord = appState.observerPosition;
orientation = appState.observerOrientation;
//ref =
//selected =
//tracked =
nbBodies = 1;
if (appState.coordSys == ObserverFrame::Universal)
nbBodies = 0;
else if (appState.coordSys == ObserverFrame::PhaseLock)
nbBodies = 2;
fieldOfView = appState.fieldOfView;
renderFlags = appState.renderFlags;
labelMode = appState.labelMode;
date = astro::Date(appState.tdb);
timeScale = appState.timeScale;
pauseState = appState.pauseState;
lightTimeDelay = appState.lightTimeDelay;
u << "cel://" << modeStr;
if (appState.coordSys != ObserverFrame::Universal)
{
u << "/" << appState.refBodyName;
if (appState.coordSys == ObserverFrame::PhaseLock)
{
u << "/" << appState.targetBodyName;
}
}
char date_str[50];
snprintf(date_str, sizeof(date_str), "%04d-%02d-%02dT%02d:%02d:%08.5f",
date.year, date.month, date.day, date.hour, date.minute, date.seconds);
u << "/" << date_str;
// observer position
u << "?x=" << coord.x.toString() << "&y=" << coord.y.toString() << "&z=" << coord.z.toString();
// observer orientation
u << "&ow=" << orientation.w
<< "&ox=" << orientation.x
<< "&oy=" << orientation.y
<< "&oz=" << orientation.z;
if (trackedStr != "")
u << "&track=" << trackedStr;
if (selectedStr != "")
u << "&select=" << selectedStr;
u << "&fov=" << fieldOfView;
u << "&ts=" << timeScale;
u << "&ltd=" << (lightTimeDelay ? 1 : 0);
u << "&p=" << (pauseState ? 1 : 0);
u << "&rf=" << renderFlags;
u << "&lm=" << labelMode;
// Append the url settings: time source and version
u << "&tsrc=" << (int) timeSource;
u << "&ver=" << version;
urlStr = u.str();
evalName();
}
void Url::initVersion2(std::map<std::string, std::string>& params,
const std::string& timeString)
{
if (type != Settings)
{
if (params["dist"] != "")
type = Relative;
else
type = Absolute;
}
switch (type) {
case Absolute:
date = astro::Date(0.0);
sscanf(timeString.c_str(), "%d-%d-%dT%d:%d:%lf",
&date.year, &date.month, &date.day,
&date.hour, &date.minute, &date.seconds);
coord = UniversalCoord(BigFix(params["x"]),
BigFix(params["y"]),
BigFix(params["z"]));
float ow, ox, oy, oz;
sscanf(params["ow"].c_str(), "%f", &ow);
sscanf(params["ox"].c_str(), "%f", &ox);
sscanf(params["oy"].c_str(), "%f", &oy);
sscanf(params["oz"].c_str(), "%f", &oz);
orientation = Quatf(ow, ox, oy, oz);
// Intentional Fall-Through
case Relative:
if (params["dist"] != "") {
sscanf(params["dist"].c_str(), "%lf", &distance);
}
if (params["long"] != "") {
sscanf(params["long"].c_str(), "%lf", &longitude);
}
if (params["lat"] != "") {
sscanf(params["lat"].c_str(), "%lf", &latitude);
}
if (params["select"] != "") {
selectedStr = params["select"];
}
if (params["track"] != "") {
trackedStr = params["track"];
}
if (params["ltd"] != "") {
lightTimeDelay = (strcmp(params["ltd"].c_str(), "1") == 0);
} else {
lightTimeDelay = false;
}
if (params["fov"] != "") {
sscanf(params["fov"].c_str(), "%f", &fieldOfView);
}
if (params["ts"] != "") {
sscanf(params["ts"].c_str(), "%f", &timeScale);
}
if (params["p"] != "") {
int pauseInt = 0;
sscanf(params["p"].c_str(), "%d", &pauseInt);
pauseState = pauseInt == 1;
}
break;
case Settings:
break;
}
if (params["rf"] != "") {
sscanf(params["rf"].c_str(), "%d", &renderFlags);
}
if (params["lm"] != "") {
sscanf(params["lm"].c_str(), "%d", &labelMode);
}
}
void Url::initVersion3(std::map<std::string, std::string>& params,
const std::string& timeString)
{
// Type field not used for version 3 urls; position is always relative
// to the frame center. Time setting is controlled by the time source.
type = Absolute;
date = astro::Date(0.0);
sscanf(timeString.c_str(), "%d-%d-%dT%d:%d:%lf",
&date.year, &date.month, &date.day,
&date.hour, &date.minute, &date.seconds);
coord = UniversalCoord(BigFix(params["x"]),
BigFix(params["y"]),
BigFix(params["z"]));
float ow, ox, oy, oz;
sscanf(params["ow"].c_str(), "%f", &ow);
sscanf(params["ox"].c_str(), "%f", &ox);
sscanf(params["oy"].c_str(), "%f", &oy);
sscanf(params["oz"].c_str(), "%f", &oz);
orientation = Quatf(ow, ox, oy, oz);
if (params["select"] != "")
selectedStr = params["select"];
if (params["track"] != "")
trackedStr = params["track"];
if (params["ltd"] != "")
lightTimeDelay = (strcmp(params["ltd"].c_str(), "1") == 0);
else
lightTimeDelay = false;
if (params["fov"] != "")
sscanf(params["fov"].c_str(), "%f", &fieldOfView);
if (params["ts"] != "")
sscanf(params["ts"].c_str(), "%f", &timeScale);
int paused = 0;
if (params["p"] != "")
sscanf(params["p"].c_str(), "%d", &paused);
pauseState = paused == 1;
// Render settings
if (params["rf"] != "")
sscanf(params["rf"].c_str(), "%d", &renderFlags);
if (params["lm"] != "")
sscanf(params["lm"].c_str(), "%d", &labelMode);
int timeSourceInt = 0;
if (params["tsrc"] != "")
sscanf(params["tsrc"].c_str(), "%d", &timeSourceInt);
if (timeSourceInt >= 0 && timeSourceInt < TimeSourceCount)
timeSource = (TimeSource) timeSourceInt;
else
timeSource = UseUrlTime;
}
std::string Url::getAsString() const
{
return urlStr;
@ -390,8 +708,9 @@ std::string Url::getCoordSysName(ObserverFrame::CoordinateSystem mode) const
return "Unknown";
case ObserverFrame::ObserverLocal:
return "Unknown";
default:
return "Unknown";
}
return "Unknown";
}
@ -518,17 +837,46 @@ void Url::goTo()
break;
}
switch(type) {
case Absolute:
sim->setTime((double) date);
if (version >= 3)
{
switch (timeSource)
{
case UseUrlTime:
sim->setTime((double) date);
break;
case UseSimulationTime:
// Leave the current simulation time unmodified
break;
case UseSystemTime:
sim->setTime(astro::UTCtoTDB(astro::Date::systemDate()));
break;
default:
break;
}
// Position and orientation stored in frame coordinates; convert them
// to universal and set the observer position.
double tdb = sim->getTime();
coord = sim->getObserver().getFrame()->convertToUniversal(coord, tdb);
Quatd q(orientation.w, orientation.x, orientation.y, orientation.z);
q = sim->getObserver().getFrame()->convertToUniversal(q, tdb);
sim->setObserverPosition(coord);
sim->setObserverOrientation(orientation);
break;
case Relative:
sim->gotoSelectionLongLat(0, astro::kilometersToLightYears(distance), (float) (longitude * PI / 180), (float) (latitude * PI / 180), Vec3f(0, 1, 0));
break;
case Settings:
break;
sim->setObserverOrientation(Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z));
}
else
{
switch(type) {
case Absolute:
sim->setTime((double) date);
sim->setObserverPosition(coord);
sim->setObserverOrientation(orientation);
break;
case Relative:
sim->gotoSelectionLongLat(0, astro::kilometersToLightYears(distance), (float) (longitude * PI / 180), (float) (latitude * PI / 180), Vec3f(0, 1, 0));
break;
case Settings:
break;
}
}
}
@ -560,6 +908,33 @@ std::string Url::decode_string(const std::string& str)
}
// Utility function that returns the complete path for a selection.
string
getSelectionName(const Selection& selection, CelestiaCore* appCore)
{
Universe *universe = appCore->getSimulation()->getUniverse();
switch (selection.getType())
{
case Selection::Type_Body:
return getBodyName(universe, selection.body());
case Selection::Type_Star:
return universe->getStarCatalog()->getStarName(*selection.star());
case Selection::Type_DeepSky:
return universe->getDSOCatalog()->getDSOName(selection.deepsky());
case Selection::Type_Location:
{
std::string name = selection.location()->getName();
Body* parentBody = selection.location()->getParentBody();
if (parentBody != NULL)
name = getBodyName(universe, parentBody) + ":" + name;
return name;
}
default:
return "";
}
}

View File

@ -18,10 +18,12 @@
#define _URL_H_
#include <string>
#include <map>
#include "celestiacore.h"
#include "celengine/astro.h"
class CelestiaCore;
class CelestiaState;
class Url
{
@ -32,23 +34,43 @@ public:
Settings = 2,
};
enum TimeSource
{
UseUrlTime = 0,
UseSimulationTime = 1,
UseSystemTime = 2,
TimeSourceCount = 3,
};
Url();
// parses str
Url(const std::string& str, CelestiaCore *core);
// current url of appCore
Url(CelestiaCore* appCore, UrlType type = Absolute);
Url(const CelestiaState& appState,
unsigned int version = CurrentVersion,
TimeSource _timeSource = UseUrlTime);
~Url();
std::string getAsString() const;
std::string getName() const;
void goTo();
static const unsigned int CurrentVersion;
private:
std::string urlStr, name;
void initVersion2(std::map<std::string, std::string>& params, const std::string& timeString);
void initVersion3(std::map<std::string, std::string>& params, const std::string& timeString);
private:
std::string urlStr;
std::string name;
std::string modeStr;
std::string body1, body2, selectedStr, trackedStr;
std::string body1;
std::string body2;
std::string selectedStr;
std::string trackedStr;
CelestiaCore *appCore;
@ -73,6 +95,8 @@ private:
bool fromString;
UrlType type;
TimeSource timeSource;
unsigned int version;
void evalName();
@ -85,4 +109,44 @@ private:
double distance, longitude, latitude;
};
/*! The CelestiaState class holds the current observer position, orientation,
* frame, time, and render settings. It is designed to be serialized as a cel
* URL, thus strings are stored for bodies instead of Selections.
*
* Some information is *not* stored in cel URLs, including the current
* lists of reference marks and markers. Such lists can be arbitrarily long,
* and thus not practical to store in a URL.
*/
class CelestiaState
{
public:
CelestiaState();
bool loadState(std::map<std::string, std::string>& params);
void saveState(std::map<std::string, std::string>& params);
void captureState(CelestiaCore* appCore);
// Observer frame, position, and orientation. For multiview, there needs
// be one instance of these parameters per view saved.
ObserverFrame::CoordinateSystem coordSys;
string refBodyName;
string targetBodyName;
string trackedBodyName;
UniversalCoord observerPosition;
Quatf observerOrientation;
float fieldOfView;
// Time parameters
double tdb;
float timeScale;
bool pauseState;
bool lightTimeDelay;
string selectedBodyName;
int labelMode;
int renderFlags;
};
#endif