00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <string>
00019 #include <stdio.h>
00020 #include "celestiacore.h"
00021 #include "celengine/astro.h"
00022 #include "url.h"
00023
00024 Url::Url()
00025 {};
00026
00027 Url::Url(const std::string& str, CelestiaCore *core)
00028 {
00029 urlStr = str;
00030 appCore = core;
00031 std::string::size_type pos, endPrevious;
00032 std::vector<Selection> bodies;
00033 Simulation *sim = appCore->getSimulation();
00034 std::map<std::string, std::string> params = parseUrlParams(urlStr);
00035
00036 if (urlStr.substr(0, 6) != "cel://")
00037 {
00038 urlStr = "";
00039 return;
00040 }
00041
00042 pos = urlStr.find("/", 6);
00043 if (pos == std::string::npos) pos = urlStr.find("?", 6);
00044
00045 if (pos == std::string::npos) modeStr = urlStr.substr(6);
00046 else modeStr = decode_string(urlStr.substr(6, pos - 6));
00047
00048
00049 if (!compareIgnoringCase(modeStr, std::string("Freeflight")))
00050 {
00051 mode = astro::Universal;
00052 nbBodies = 0;
00053 }
00054 else if (!compareIgnoringCase(modeStr, std::string("Follow")))
00055 {
00056 mode = astro::Ecliptical;
00057 nbBodies = 1;
00058 }
00059 else if (!compareIgnoringCase(modeStr, std::string("SyncOrbit")))
00060 {
00061 mode = astro::Geographic;
00062 nbBodies = 1;
00063 }
00064 else if (!compareIgnoringCase(modeStr, std::string("Chase")))
00065 {
00066 mode = astro::Chase;
00067 nbBodies = 1;
00068 }
00069 else if (!compareIgnoringCase(modeStr, std::string("PhaseLock")))
00070 {
00071 mode = astro::PhaseLock;
00072 nbBodies = 2;
00073 }
00074 else if (!compareIgnoringCase(modeStr, std::string("Settings")))
00075 {
00076 type = Settings;
00077 nbBodies = 0;
00078 }
00079
00080 if (nbBodies == -1)
00081 {
00082 urlStr = "";
00083 return;
00084 }
00085
00086 endPrevious = pos;
00087 int nb = nbBodies, i=1;
00088 while (nb != 0 && endPrevious != std::string::npos) {
00089 std::string bodyName="";
00090 pos = urlStr.find("/", endPrevious + 1);
00091 if (pos == std::string::npos) pos = urlStr.find("?", endPrevious + 1);
00092 if (pos == std::string::npos) bodyName = urlStr.substr(endPrevious + 1);
00093 else bodyName = urlStr.substr(endPrevious + 1, pos - endPrevious - 1);
00094 endPrevious = pos;
00095
00096 bodyName = decode_string(bodyName);
00097 pos = 0;
00098 if (i==1) body1 = bodyName;
00099 if (i==2) body2 = bodyName;
00100 while(pos != std::string::npos) {
00101 pos = bodyName.find(":", pos + 1);
00102 if (pos != std::string::npos) bodyName[pos]='/';
00103 }
00104
00105 bodies.push_back(sim->findObjectFromPath(bodyName));
00106
00107 nb--;
00108 i++;
00109 }
00110
00111 if (nb != 0) {
00112 urlStr = "";
00113 return;
00114 }
00115
00116 if (nbBodies == 0) ref = FrameOfReference();
00117 if (nbBodies == 1) ref = FrameOfReference(mode, bodies[0]);
00118 if (nbBodies == 2) ref = FrameOfReference(mode, bodies[0], bodies[1]);
00119 fromString = true;
00120
00121 std::string time="";
00122 pos = urlStr.find("?", endPrevious + 1);
00123 if (pos == std::string::npos) time = urlStr.substr(endPrevious + 1);
00124 else time = urlStr.substr(endPrevious + 1, pos - endPrevious -1);
00125 time = decode_string(time);
00126
00127 if (type != Settings)
00128 {
00129 if (params["dist"] != "")
00130 type = Relative;
00131 else
00132 type = Absolute;
00133 }
00134
00135 switch (type) {
00136 case Absolute:
00137 date = astro::Date(0.0);
00138 sscanf(time.c_str(), "%d-%d-%dT%d:%d:%lf",
00139 &date.year, &date.month, &date.day,
00140 &date.hour, &date.minute, &date.seconds);
00141
00142 coord = UniversalCoord(BigFix(params["x"]),
00143 BigFix(params["y"]),
00144 BigFix(params["z"]));
00145
00146 float ow, ox, oy, oz;
00147 sscanf(params["ow"].c_str(), "%f", &ow);
00148 sscanf(params["ox"].c_str(), "%f", &ox);
00149 sscanf(params["oy"].c_str(), "%f", &oy);
00150 sscanf(params["oz"].c_str(), "%f", &oz);
00151
00152 orientation = Quatf(ow, ox, oy, oz);
00153
00154
00155 case Relative:
00156 if (params["dist"] != "") {
00157 sscanf(params["dist"].c_str(), "%lf", &distance);
00158 }
00159 if (params["long"] != "") {
00160 sscanf(params["long"].c_str(), "%lf", &longitude);
00161 }
00162 if (params["lat"] != "") {
00163 sscanf(params["lat"].c_str(), "%lf", &latitude);
00164 }
00165 if (params["select"] != "") {
00166 selectedStr = params["select"];
00167 }
00168 if (params["track"] != "") {
00169 trackedStr = params["track"];
00170 }
00171 if (params["ltd"] != "") {
00172 lightTimeDelay = (strcmp(params["ltd"].c_str(), "1") == 0);
00173 } else {
00174 lightTimeDelay = false;
00175 }
00176 if (params["fov"] != "") {
00177 sscanf(params["fov"].c_str(), "%f", &fieldOfView);
00178 }
00179 if (params["ts"] != "") {
00180 sscanf(params["ts"].c_str(), "%f", &timeScale);
00181 }
00182 break;
00183 case Settings:
00184 break;
00185 }
00186
00187 if (params["rf"] != "") {
00188 sscanf(params["rf"].c_str(), "%d", &renderFlags);
00189 }
00190 if (params["lm"] != "") {
00191 sscanf(params["lm"].c_str(), "%d", &labelMode);
00192 }
00193
00194 evalName();
00195 }
00196
00197 Url::Url(CelestiaCore* core, UrlType type)
00198 {
00199 appCore = core;
00200 Simulation *sim = appCore->getSimulation();
00201 Renderer *renderer = appCore->getRenderer();
00202
00203 this->type = type;
00204
00205 modeStr = getCoordSysName(sim->getFrame().coordSys);
00206 if (type == Settings) modeStr = "Settings";
00207 ref = sim->getFrame();
00208 urlStr += "cel://" + modeStr;
00209 if (type != Settings && sim->getFrame().coordSys != astro::Universal) {
00210 body1 = getSelectionName(sim->getFrame().refObject);
00211 urlStr += "/" + body1;
00212 if (sim->getFrame().coordSys == astro::PhaseLock) {
00213 body2 = getSelectionName(sim->getFrame().targetObject);
00214 urlStr += "/" + body2;
00215 }
00216 }
00217
00218 char date_str[30];
00219 date = astro::Date(sim->getTime());
00220 char buff[255];
00221
00222 switch (type) {
00223 case Absolute:
00224 sprintf(date_str, "%04d-%02d-%02dT%02d:%02d:%08.5f",
00225 date.year, date.month, date.day, date.hour, date.minute, date.seconds);
00226
00227 coord = sim->getObserver().getPosition();
00228 urlStr += std::string("/") + date_str + "?x=" + coord.x.toString();
00229 urlStr += "&y=" + coord.y.toString();
00230 urlStr += "&z=" + coord.z.toString();
00231
00232 orientation = sim->getObserver().getOrientation();
00233 sprintf(buff, "&ow=%f&ox=%f&oy=%f&oz=%f", orientation.w, orientation.x, orientation.y, orientation.z);
00234 urlStr += buff;
00235 break;
00236 case Relative:
00237 sim->getSelectionLongLat(distance, longitude, latitude);
00238 sprintf(buff, "dist=%f&long=%f&lat=%f", distance, longitude, latitude);
00239 urlStr += std::string("/?") + buff;
00240 break;
00241 case Settings:
00242 urlStr += std::string("/?");
00243 break;
00244 }
00245
00246 switch (type) {
00247 case Absolute:
00248 case Relative:
00249 tracked = sim->getTrackedObject();
00250 trackedStr = getSelectionName(tracked);
00251 if (trackedStr != "") urlStr += "&track=" + trackedStr;
00252
00253 selected = sim->getSelection();
00254 selectedStr = getSelectionName(selected);
00255 if (selectedStr != "") urlStr += "&select=" + selectedStr;
00256
00257 fieldOfView = radToDeg(sim->getActiveObserver()->getFOV());
00258 timeScale = sim->getTimeScale();
00259 lightTimeDelay = appCore->getLightDelayActive();
00260 sprintf(buff, "&fov=%f&ts=%f<d=%c&", fieldOfView,
00261 timeScale, lightTimeDelay?'1':'0');
00262 urlStr += buff;
00263 case Settings:
00264 renderFlags = renderer->getRenderFlags();
00265 labelMode = renderer->getLabelMode();
00266 sprintf(buff, "rf=%d&lm=%d", renderFlags, labelMode);
00267 urlStr += buff;
00268 break;
00269 }
00270
00271 evalName();
00272 }
00273
00274 std::string Url::getAsString() const {
00275 return urlStr;
00276 }
00277
00278 std::string Url::getName() const {
00279 return name;
00280 }
00281
00282 void Url::evalName() {
00283 char buff[50];
00284 double lo = longitude, la = latitude;
00285 char los = 'E';
00286 char las = 'N';
00287 switch(type) {
00288 case Absolute:
00289 name = _(modeStr.c_str());
00290 if (body1 != "") name += " " + std::string(_(getBodyShortName(body1).c_str()));
00291 if (body2 != "") name += " " + std::string(_(getBodyShortName(body2).c_str()));
00292 if (trackedStr != "") name += " -> " + std::string(_(getBodyShortName(trackedStr).c_str()));
00293 if (selectedStr != "") name += " [" + std::string(_(getBodyShortName(selectedStr).c_str())) + "]";
00294 break;
00295 case Relative:
00296 if (selectedStr != "") name = std::string(_(getBodyShortName(selectedStr).c_str())) + " ";
00297 if (lo < 0) { lo = -lo; los = 'W'; }
00298 if (la < 0) { la = -la; las = 'S'; }
00299 sprintf(buff, "(%.1lf%c, %.1lf%c)", lo, los, la, las);
00300 name += buff;
00301 break;
00302 case Settings:
00303 name = _("Settings");
00304 break;
00305 }
00306 }
00307
00308 std::string Url::getBodyShortName(const std::string& body) const {
00309 std::string::size_type pos;
00310 if (body != "") {
00311 pos = body.rfind(":");
00312 if (pos != std::string::npos) return body.substr(pos+1);
00313 else return body;
00314 }
00315 return "";
00316 }
00317
00318 std::map<std::string, std::string> Url::parseUrlParams(const std::string& url) const{
00319 std::string::size_type pos, startName, startValue;
00320 std::map<std::string, std::string> params;
00321
00322 pos = url.find("?");
00323 while (pos != std::string::npos) {
00324 startName = pos + 1;
00325 startValue = url.find("=", startName);
00326 pos = url.find("&", pos + 1);
00327 if (startValue != std::string::npos) {
00328 startValue++;
00329 if (pos != std::string::npos)
00330 params[url.substr(startName, startValue - startName -1)] = decode_string(url.substr(startValue, pos - startValue));
00331 else
00332 params[url.substr(startName, startValue - startName -1)] = decode_string(url.substr(startValue));
00333 }
00334 }
00335
00336 return params;
00337 }
00338
00339 std::string Url::getCoordSysName(astro::CoordinateSystem mode) const
00340 {
00341 switch (mode)
00342 {
00343 case astro::Universal:
00344 return "Freeflight";
00345 case astro::Ecliptical:
00346 return "Follow";
00347 case astro::Geographic:
00348 return "SyncOrbit";
00349 case astro::Chase:
00350 return "Chase";
00351 case astro::PhaseLock:
00352 return "PhaseLock";
00353 case astro::Equatorial:
00354 return "Unknown";
00355 case astro::ObserverLocal:
00356 return "Unknown";
00357 }
00358 return "Unknown";
00359 }
00360
00361
00362 std::string Url::getSelectionName(const Selection& selection) const
00363 {
00364 PlanetarySystem* parentSystem;
00365 Body* parentBody;
00366 Universe *universe = appCore->getSimulation()->getUniverse();
00367
00368 switch (selection.getType())
00369 {
00370 case Selection::Type_Body:
00371 {
00372 std::string name = selection.body()->getName();
00373 parentSystem = selection.body()->getSystem();
00374 if (parentSystem != NULL && (parentBody = parentSystem->getPrimaryBody()) != NULL)
00375 {
00376 while (parentSystem != NULL && parentBody != NULL)
00377 {
00378 name = parentSystem->getPrimaryBody()->getName() + ":" + name;
00379 parentSystem = parentSystem->getPrimaryBody()->getSystem();
00380 parentBody = parentSystem->getPrimaryBody();
00381 }
00382 if (selection.body()->getSystem()->getStar() != NULL)
00383 {
00384 name = universe->getStarCatalog()->getStarName(*(selection.body()->getSystem()->getStar())) + ":" + name;
00385 }
00386 }
00387 return name;
00388 }
00389
00390 case Selection::Type_Star:
00391 return universe->getStarCatalog()->getStarName(*selection.star());
00392
00393 case Selection::Type_DeepSky:
00394 return universe->getDSOCatalog()->getDSOName(selection.deepsky());
00395
00396 case Selection::Type_Location:
00397 return "";
00398
00399 default:
00400 return "";
00401 }
00402 }
00403
00404 void Url::goTo()
00405 {
00406 Selection sel;
00407
00408 if (urlStr == "")
00409 return;
00410 Simulation *sim = appCore->getSimulation();
00411 Renderer *renderer = appCore->getRenderer();
00412 std::string::size_type pos;
00413
00414 sim->update(0.0);
00415
00416 switch(type) {
00417 case Absolute:
00418 case Relative:
00419 sim->setFrame(ref);
00420 sim->getActiveObserver()->setFOV(degToRad(fieldOfView));
00421 appCore->setZoomFromFOV();
00422 sim->setTimeScale(timeScale);
00423 appCore->setLightDelayActive(lightTimeDelay);
00424
00425 pos = 0;
00426 while(pos != std::string::npos)
00427 {
00428 pos = selectedStr.find(":", pos + 1);
00429 if (pos != std::string::npos) selectedStr[pos]='/';
00430 }
00431 sel = sim->findObjectFromPath(selectedStr);
00432 sim->setSelection(sel);
00433
00434 pos = 0;
00435 while(pos != std::string::npos)
00436 {
00437 pos = trackedStr.find(":", pos + 1);
00438 if (pos != std::string::npos) trackedStr[pos]='/';
00439 }
00440 sel = sim->findObjectFromPath(trackedStr);
00441 sim->setTrackedObject(sel);
00442
00443 case Settings:
00444 renderer->setRenderFlags(renderFlags);
00445 renderer->setLabelMode(labelMode);
00446 break;
00447 }
00448
00449 switch(type) {
00450 case Absolute:
00451 sim->setTime((double) date);
00452 sim->setObserverPosition(coord);
00453 sim->setObserverOrientation(orientation);
00454 break;
00455 case Relative:
00456 sim->gotoSelectionLongLat(0, astro::kilometersToLightYears(distance), longitude * PI / 180, latitude * PI / 180, Vec3f(0, 1, 0));
00457 break;
00458 case Settings:
00459 break;
00460 }
00461 }
00462
00463 Url::~Url()
00464 {
00465 }
00466
00467 std::string Url::decode_string(const std::string& str)
00468 {
00469 std::string::size_type a=0, b;
00470 std::string out = "";
00471
00472 b = str.find("%");
00473 while (b != std::string::npos)
00474 {
00475 unsigned int c;
00476 out += str.substr(a, b-a);
00477 std::string c_code = str.substr(b+1, 2);
00478 sscanf(c_code.c_str(), "%02x", &c);
00479 out += c;
00480 a = b + 3;
00481 b = str.find("%", a);
00482 }
00483 out += str.substr(a);
00484
00485 return out;
00486 }
00487
00488
00489
00490
00491