Index: celestia/qt/qtappwin.cpp =================================================================== --- celestia/qt/qtappwin.cpp (revision 4309) +++ celestia/qt/qtappwin.cpp (working copy) @@ -614,7 +614,10 @@ 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 @@ 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 @@ 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(); Index: celestia/qt/newbookmarkfolder.ui =================================================================== --- celestia/qt/newbookmarkfolder.ui (revision 4309) +++ celestia/qt/newbookmarkfolder.ui (working copy) @@ -5,124 +5,106 @@ 0 0 - 408 - 235 + 426 + 221 New Folder - - - - 10 - 190 - 379 - 25 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok - - - - - - 12 - 23 - 57 - 16 - - - - Name: - - - - - - 78 - 23 - 311 - 20 - - - - - - - 11 - 141 - 187 - 20 - - - - Create in: - - - - - - 80 - 140 - 186 - 20 - - - - - - - 11 - 50 - 379 - 71 - - - - - - - - - Description: - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - 0 - 0 - - - - false - - - - - + + + + + + + Name: + + + + + + + + + + + 0 + 0 + + + + false + + + + + + + Create in: + + + + + + + + 0 + 0 + + + + + + + + + + Description: + + + + + + + Qt::Vertical + + + + 20 + 13 + + + + + + + + + + + + Qt::Vertical + + + + 399 + 13 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + Index: celestia/qt/addbookmark.ui =================================================================== --- celestia/qt/addbookmark.ui (revision 4309) +++ celestia/qt/addbookmark.ui (working copy) @@ -8,75 +8,72 @@ 0 0 - 412 - 175 + 360 + 188 Bookmark Location - - - - 40 - 120 - 341 - 32 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 30 - 20 - 191 - 18 - - - - Bookmark name: - - - - - - 30 - 70 - 191 - 18 - - - - Create in: - - - - - - 190 - 20 - 181 - 22 - - - - - - - 190 - 60 - 181 - 26 - - - + + + + + + + Bookmark name: + + + + + + + + + + + + + Create in: + + + + + + + Time source: + + + + + + + + + + + + Qt::Vertical + + + + 20 + 24 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + Index: celestia/qt/qtbookmark.cpp =================================================================== --- celestia/qt/qtbookmark.cpp (revision 4309) +++ celestia/qt/qtbookmark.cpp (working copy) @@ -19,6 +19,7 @@ #include #include #include "xbel.h" +#include "celestia/url.h" BookmarkItem::BookmarkItem(Type type, BookmarkItem* parent) : @@ -804,13 +805,15 @@ }; +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 @@ 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 @@ 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)))); Index: celestia/qt/qtbookmark.h =================================================================== --- celestia/qt/qtbookmark.h (revision 4309) +++ celestia/qt/qtbookmark.h (working copy) @@ -26,6 +26,7 @@ class QSortFilterProxyModel; class QMenu; +class CelestiaState; class BookmarkItem { @@ -180,7 +181,7 @@ public: AddBookmarkDialog(BookmarkManager* manager, QString defaultTitle, - QString url, + const CelestiaState& appState, const QImage& iconImage); public slots: @@ -189,8 +190,10 @@ private: BookmarkManager* m_manager; QSortFilterProxyModel* m_filterModel; - QString m_url; + const CelestiaState& m_appState; QImage m_iconImage; + + static int m_lastTimeSourceIndex; }; Index: celestia/url.cpp =================================================================== --- celestia/url.cpp (revision 4309) +++ celestia/url.cpp (working copy) @@ -18,39 +18,189 @@ #include #include #include +#include #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 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() {}; 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 bodies; Simulation *sim = appCore->getSimulation(); std::map 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) + 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) + modeStr = urlStr.substr(6); + else + modeStr = decode_string(urlStr.substr(6, pos - 6)); - if (!compareIgnoringCase(modeStr, std::string("Freeflight"))) { mode = ObserverFrame::Universal; @@ -81,21 +231,13 @@ 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 @@ 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,99 +256,44 @@ 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; + default: + urlStr = ""; + return; } - if (params["rf"] != "") { - sscanf(params["rf"].c_str(), "%d", &renderFlags); - } - if (params["lm"] != "") { - sscanf(params["lm"].c_str(), "%d", &labelMode); - } - evalName(); } @@ -214,6 +301,9 @@ Url::Url(CelestiaCore* core, UrlType type) { appCore = core; + version = 2; + timeSource = UseUrlTime; + Simulation *sim = appCore->getSimulation(); Renderer *renderer = appCore->getRenderer(); @@ -232,8 +322,10 @@ } } + 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 @@ // Append the Celestia URL version { char buf[32]; - sprintf(buf, "&ver=%u", CurrentCelestiaURLVersion); + sprintf(buf, "&ver=%u", version); urlStr += buf; } @@ -297,6 +389,232 @@ } +/*! 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 << "<d=" << (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& 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& 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 @@ return "Unknown"; case ObserverFrame::ObserverLocal: return "Unknown"; + default: + return "Unknown"; } - return "Unknown"; } @@ -518,18 +837,47 @@ 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 @@ } - - - +// 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 ""; + } +} Index: celestia/url.h =================================================================== --- celestia/url.h (revision 4309) +++ celestia/url.h (working copy) @@ -18,10 +18,12 @@ #define _URL_H_ #include +#include #include "celestiacore.h" #include "celengine/astro.h" class CelestiaCore; +class CelestiaState; class Url { @@ -32,23 +34,43 @@ 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& params, const std::string& timeString); + void initVersion3(std::map& 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 @@ bool fromString; UrlType type; + TimeSource timeSource; + unsigned int version; void evalName(); @@ -85,4 +109,44 @@ 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& params); + void saveState(std::map& 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