celestia/src/celestia/url.cpp

525 lines
15 KiB
C++
Raw Normal View History

/***************************************************************************
url.cpp - description
-------------------
begin : Wed Aug 7 2002
copyright : (C) 2002 by chris
email : chris@tux.teyssier.org
***************************************************************************/
/***************************************************************************
* *
* 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 <string>
#include <stdio.h>
#include "celestiacore.h"
#include "celengine/astro.h"
#include "url.h"
2007-01-11 12:30:04 -07:00
static const unsigned int CurrentCelestiaURLVersion = 2;
2005-07-19 15:31:04 -06:00
Url::Url()
{};
2002-11-07 22:28:42 -07:00
Url::Url(const std::string& str, CelestiaCore *core)
{
urlStr = str;
appCore = core;
std::string::size_type pos, endPrevious;
std::vector<Selection> bodies;
Simulation *sim = appCore->getSimulation();
std::map<std::string, std::string> params = parseUrlParams(urlStr);
2007-01-11 12:30:04 -07:00
2002-11-07 22:28:42 -07:00
if (urlStr.substr(0, 6) != "cel://")
{
urlStr = "";
return;
}
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 (!compareIgnoringCase(modeStr, std::string("Freeflight")))
2002-11-07 22:28:42 -07:00
{
mode = astro::Universal;
nbBodies = 0;
}
else if (!compareIgnoringCase(modeStr, std::string("Follow")))
2002-11-07 22:28:42 -07:00
{
mode = astro::Ecliptical;
nbBodies = 1;
}
else if (!compareIgnoringCase(modeStr, std::string("SyncOrbit")))
2002-11-07 22:28:42 -07:00
{
mode = astro::Geographic;
nbBodies = 1;
}
else if (!compareIgnoringCase(modeStr, std::string("Chase")))
2002-11-07 22:28:42 -07:00
{
mode = astro::Chase;
nbBodies = 1;
}
else if (!compareIgnoringCase(modeStr, std::string("PhaseLock")))
2002-11-07 22:28:42 -07:00
{
mode = astro::PhaseLock;
nbBodies = 2;
}
else if (!compareIgnoringCase(modeStr, std::string("Settings")))
2003-05-31 11:40:19 -06:00
{
type = Settings;
nbBodies = 0;
}
2002-11-07 22:28:42 -07:00
if (nbBodies == -1)
{
urlStr = "";
return; // Mode not recognized
}
2007-01-11 12:30:04 -07:00
// 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) {
std::string bodyName="";
pos = urlStr.find("/", endPrevious + 1);
if (pos == std::string::npos) pos = urlStr.find("?", endPrevious + 1);
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;
if (i==2) body2 = bodyName;
while(pos != std::string::npos) {
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 = FrameOfReference();
if (nbBodies == 1) ref = FrameOfReference(mode, bodies[0]);
if (nbBodies == 2) ref = FrameOfReference(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);
else time = urlStr.substr(endPrevious + 1, pos - endPrevious -1);
time = decode_string(time);
2003-05-31 11:40:19 -06:00
if (type != Settings)
{
if (params["dist"] != "")
type = Relative;
else
type = Absolute;
}
2003-05-31 11:40:19 -06:00
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"]));
2003-05-31 11:40:19 -06:00
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);
2003-05-31 11:40:19 -06:00
// 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);
}
2003-05-31 11:40:19 -06:00
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);
}
break;
case Settings:
break;
}
if (params["rf"] != "") {
sscanf(params["rf"].c_str(), "%d", &renderFlags);
}
if (params["lm"] != "") {
sscanf(params["lm"].c_str(), "%d", &labelMode);
}
evalName();
}
2007-01-11 12:30:04 -07:00
Url::Url(CelestiaCore* core, UrlType type)
{
appCore = core;
Simulation *sim = appCore->getSimulation();
Renderer *renderer = appCore->getRenderer();
2003-05-06 16:13:33 -06:00
this->type = type;
modeStr = getCoordSysName(sim->getFrame().coordSys);
2003-05-31 11:40:19 -06:00
if (type == Settings) modeStr = "Settings";
ref = sim->getFrame();
urlStr += "cel://" + modeStr;
2003-05-31 11:40:19 -06:00
if (type != Settings && sim->getFrame().coordSys != astro::Universal) {
body1 = getSelectionName(sim->getFrame().refObject);
urlStr += "/" + body1;
if (sim->getFrame().coordSys == astro::PhaseLock) {
body2 = getSelectionName(sim->getFrame().targetObject);
urlStr += "/" + body2;
}
}
char date_str[50];
date = astro::Date(sim->getTime());
char buff[255];
2003-05-06 16:13:33 -06:00
switch (type) {
2003-05-06 16:13:33 -06:00
case Absolute:
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);
coord = sim->getObserver().getPosition();
urlStr += std::string("/") + date_str + "?x=" + coord.x.toString();
urlStr += "&y=" + coord.y.toString();
urlStr += "&z=" + coord.z.toString();
2003-05-06 16:13:33 -06:00
orientation = sim->getObserver().getOrientation();
sprintf(buff, "&ow=%f&ox=%f&oy=%f&oz=%f", orientation.w, orientation.x, orientation.y, orientation.z);
urlStr += buff;
break;
2003-05-06 16:13:33 -06:00
case Relative:
sim->getSelectionLongLat(distance, longitude, latitude);
sprintf(buff, "dist=%f&long=%f&lat=%f", distance, longitude, latitude);
urlStr += std::string("/?") + buff;
break;
2003-05-31 11:40:19 -06:00
case Settings:
urlStr += std::string("/?");
break;
}
2003-05-06 16:13:33 -06:00
2003-05-31 11:40:19 -06:00
switch (type) {
case Absolute: // Intentional Fall-Through
case Relative:
tracked = sim->getTrackedObject();
trackedStr = getSelectionName(tracked);
if (trackedStr != "") urlStr += "&track=" + trackedStr;
selected = sim->getSelection();
selectedStr = getSelectionName(selected);
if (selectedStr != "") urlStr += "&select=" + selectedStr;
fieldOfView = radToDeg(sim->getActiveObserver()->getFOV());
2007-01-11 12:30:04 -07:00
timeScale = (float) sim->getTimeScale();
2003-05-31 11:40:19 -06:00
lightTimeDelay = appCore->getLightDelayActive();
sprintf(buff, "&fov=%f&ts=%f&ltd=%c&", fieldOfView,
timeScale, lightTimeDelay?'1':'0');
2003-05-31 11:40:19 -06:00
urlStr += buff;
2003-05-31 11:52:31 -06:00
case Settings: // Intentional Fall-Through
2003-05-31 11:40:19 -06:00
renderFlags = renderer->getRenderFlags();
labelMode = renderer->getLabelMode();
sprintf(buff, "rf=%d&lm=%d", renderFlags, labelMode);
urlStr += buff;
break;
}
2007-01-11 12:30:04 -07:00
// Append the Celestia URL version
{
char buf[32];
sprintf(buf, "&ver=%u", CurrentCelestiaURLVersion);
urlStr += buf;
}
evalName();
}
2007-01-11 12:30:04 -07:00
std::string Url::getAsString() const
{
return urlStr;
}
2007-01-11 12:30:04 -07:00
std::string Url::getName() const
{
return name;
}
2007-01-11 12:30:04 -07:00
void Url::evalName()
{
2003-05-31 11:40:19 -06:00
char buff[50];
double lo = longitude, la = latitude;
char los = 'E';
char las = 'N';
switch(type) {
case Absolute:
2005-07-19 15:31:04 -06:00
name = _(modeStr.c_str());
if (body1 != "") name += " " + std::string(_(getBodyShortName(body1).c_str()));
if (body2 != "") name += " " + std::string(_(getBodyShortName(body2).c_str()));
if (trackedStr != "") name += " -> " + std::string(_(getBodyShortName(trackedStr).c_str()));
if (selectedStr != "") name += " [" + std::string(_(getBodyShortName(selectedStr).c_str())) + "]";
break;
case Relative:
2005-07-19 15:31:04 -06:00
if (selectedStr != "") name = std::string(_(getBodyShortName(selectedStr).c_str())) + " ";
if (lo < 0) { lo = -lo; los = 'W'; }
if (la < 0) { la = -la; las = 'S'; }
2003-05-06 16:13:33 -06:00
sprintf(buff, "(%.1lf%c, %.1lf%c)", lo, los, la, las);
name += buff;
break;
2003-05-31 11:40:19 -06:00
case Settings:
2005-07-19 15:31:04 -06:00
name = _("Settings");
2003-05-31 11:40:19 -06:00
break;
}
}
2007-01-11 12:30:04 -07:00
std::string Url::getBodyShortName(const std::string& body) const
{
std::string::size_type pos;
if (body != "") {
pos = body.rfind(":");
if (pos != std::string::npos) return body.substr(pos+1);
else return body;
}
return "";
}
2007-01-11 12:30:04 -07:00
std::map<std::string, std::string> Url::parseUrlParams(const std::string& url) const
{
std::string::size_type pos, startName, startValue;
std::map<std::string, std::string> params;
pos = url.find("?");
while (pos != std::string::npos) {
startName = pos + 1;
startValue = url.find("=", startName);
pos = url.find("&", pos + 1);
if (startValue != std::string::npos) {
startValue++;
if (pos != std::string::npos)
params[url.substr(startName, startValue - startName -1)] = decode_string(url.substr(startValue, pos - startValue));
else
params[url.substr(startName, startValue - startName -1)] = decode_string(url.substr(startValue));
}
}
return params;
}
2007-01-11 12:30:04 -07:00
2002-11-07 22:28:42 -07:00
std::string Url::getCoordSysName(astro::CoordinateSystem mode) const
{
switch (mode)
{
case astro::Universal:
return "Freeflight";
case astro::Ecliptical:
2002-11-07 22:28:42 -07:00
return "Follow";
case astro::Geographic:
return "SyncOrbit";
case astro::Chase:
return "Chase";
case astro::PhaseLock:
return "PhaseLock";
case astro::Equatorial:
return "Unknown";
case astro::ObserverLocal:
return "Unknown";
}
return "Unknown";
}
2002-11-07 22:28:42 -07:00
std::string Url::getSelectionName(const Selection& selection) const
{
2005-07-19 15:31:04 -06:00
PlanetarySystem* parentSystem;
Body* parentBody;
Universe *universe = appCore->getSimulation()->getUniverse();
switch (selection.getType())
2002-11-07 22:28:42 -07:00
{
case Selection::Type_Body:
2002-11-07 22:28:42 -07:00
{
std::string name = selection.body()->getName();
2005-07-19 15:31:04 -06:00
parentSystem = selection.body()->getSystem();
if (parentSystem != NULL && (parentBody = parentSystem->getPrimaryBody()) != NULL)
2002-11-07 22:28:42 -07:00
{
2005-07-19 15:31:04 -06:00
while (parentSystem != NULL && parentBody != NULL)
{
2005-07-19 15:31:04 -06:00
name = parentSystem->getPrimaryBody()->getName() + ":" + name;
parentSystem = parentSystem->getPrimaryBody()->getSystem();
parentBody = parentSystem->getPrimaryBody();
}
if (selection.body()->getSystem()->getStar() != NULL)
{
name = universe->getStarCatalog()->getStarName(*(selection.body()->getSystem()->getStar())) + ":" + name;
}
}
return name;
}
case Selection::Type_Star:
return universe->getStarCatalog()->getStarName(*selection.star());
case Selection::Type_DeepSky:
return universe->getDSOCatalog()->getDSOName(selection.deepsky());
case Selection::Type_Location:
return "";
default:
return "";
}
}
2007-01-11 12:30:04 -07:00
2002-11-07 22:28:42 -07:00
void Url::goTo()
2007-01-11 12:30:04 -07:00
{
2003-05-31 11:40:19 -06:00
Selection sel;
2002-11-07 22:28:42 -07:00
if (urlStr == "")
return;
Simulation *sim = appCore->getSimulation();
Renderer *renderer = appCore->getRenderer();
std::string::size_type pos;
sim->update(0.0);
2003-05-31 11:40:19 -06:00
switch(type) {
case Absolute:// Intentional Fall-Through
case Relative:
sim->setFrame(ref);
sim->getActiveObserver()->setFOV(degToRad(fieldOfView));
2003-06-03 15:49:54 -06:00
appCore->setZoomFromFOV();
2003-05-31 11:40:19 -06:00
sim->setTimeScale(timeScale);
appCore->setLightDelayActive(lightTimeDelay);
pos = 0;
while(pos != std::string::npos)
{
pos = selectedStr.find(":", pos + 1);
if (pos != std::string::npos) selectedStr[pos]='/';
}
sel = sim->findObjectFromPath(selectedStr);
sim->setSelection(sel);
2003-05-31 11:40:19 -06:00
pos = 0;
while(pos != std::string::npos)
{
pos = trackedStr.find(":", pos + 1);
if (pos != std::string::npos) trackedStr[pos]='/';
}
sel = sim->findObjectFromPath(trackedStr);
sim->setTrackedObject(sel);
2003-05-31 11:40:19 -06:00
// Intentional Fall-Through
case Settings:
renderer->setRenderFlags(renderFlags);
renderer->setLabelMode(labelMode);
break;
}
switch(type) {
case Absolute:
sim->setTime((double) date);
sim->setObserverPosition(coord);
sim->setObserverOrientation(orientation);
break;
case Relative:
2007-01-11 12:30:04 -07:00
sim->gotoSelectionLongLat(0, astro::kilometersToLightYears(distance), (float) (longitude * PI / 180), (float) (latitude * PI / 180), Vec3f(0, 1, 0));
break;
2003-05-31 11:40:19 -06:00
case Settings:
break;
}
}
2007-01-11 12:30:04 -07:00
2002-11-07 22:28:42 -07:00
Url::~Url()
{
}
2007-01-11 12:30:04 -07:00
2002-11-07 22:28:42 -07:00
std::string Url::decode_string(const std::string& str)
{
std::string::size_type a=0, b;
std::string out = "";
2003-05-06 16:13:33 -06:00
b = str.find("%");
2002-11-07 22:28:42 -07:00
while (b != std::string::npos)
{
unsigned int c;
out += str.substr(a, b-a);
2003-05-06 16:13:33 -06:00
std::string c_code = str.substr(b+1, 2);
sscanf(c_code.c_str(), "%02x", &c);
out += c;
a = b + 3;
b = str.find("%", a);
}
out += str.substr(a);
return out;
}