#include #include #include #include #include #include #include #include using namespace std; #include "findFile.h" #include "keywords.h" #include "Options.h" #include "parse.h" #include "PlanetProperties.h" #include "Satellite.h" #include "sphericalToPixel.h" #include "View.h" #include "xpUtil.h" #include "drawArc.h" #include "drawCircle.h" #include "libannotate/libannotate.h" #include "libplanet/Planet.h" #include "libprojection/ProjectionBase.h" static vector satelliteVector; bool calculateSatellitePosition(time_t tv_sec, const int id, double &lat, double &lon, double &rad) { Options *options = Options::getInstance(); if (options->LightTime()) { double tX, tY, tZ; double jd = options->JulianDay(); Planet earth(jd, EARTH); earth.calcHeliocentricEquatorial(); earth.getPosition(tX, tY, tZ); double oX, oY, oZ; options->getOrigin(oX, oY, oZ); // Now get the position relative to the origin double dX = tX - oX; double dY = tY - oY; double dZ = tZ - oZ; double dist = sqrt(dX*dX + dY*dY + dZ*dZ); double light_time = dist * AU_to_km / 299792.458; tv_sec -= static_cast (light_time); } for (unsigned int i = 0; i < satelliteVector.size(); i++) { if (id == satelliteVector[i].getID()) { satelliteVector[i].loadTLE(); satelliteVector[i].getSpherical(tv_sec, lat, lon, rad); return(true); } } ostringstream msg; msg << "Can't find satellite # " << id << ".\n"; xpMsg(msg.str(), __FILE__, __LINE__); return(false); } static void readSatelliteFile(const char *line, Planet *planet, View *view, ProjectionBase *projection, PlanetProperties *planetProperties, multimap &annotationMap) { int i = 0; while (isDelimiter(line[i])) { i++; if (static_cast (i) > strlen(line)) return; } if (isEndOfLine(line[i])) return; Options *options = Options::getInstance(); unsigned char color[3]; memcpy(color, planetProperties->MarkerColor(), 3); int align = RIGHT; vector altcirc; string font(""); int fontSize = -1; string image; string name(""); Satellite *satellite = NULL; int symbolSize = 2; double spacing = 0.1; bool syntaxError = false; string timezone; int trailType = ORBIT; int trailStart = 0; int trailEnd = 0; int trailInterval = 1; bool transparency = false; unsigned char transparent_pixel[3]; while (static_cast (i) < strlen(line)) { char *returnString = NULL; int val = parse(i, line, returnString); switch (val) { case ALIGN: if (returnString == NULL) break; switch (returnString[0]) { case 'r': case 'R': align = RIGHT; break; case 'l': case 'L': align = LEFT; break; case 'a': case 'A': align = ABOVE; break; case 'b': case 'B': align = BELOW; break; case 'c': case 'C': align = CENTER; break; default: xpWarn("Unrecognized option for align in satellite file\n", __FILE__, __LINE__); syntaxError = true; break; } break; case CIRCLE: { checkLocale(LC_NUMERIC, "C"); double angle; sscanf(returnString, "%lf", &angle); if (angle < 0) angle *= -1; if (angle > 90) angle = 90; angle = 90 - angle; altcirc.push_back(angle * deg_to_rad); checkLocale(LC_NUMERIC, ""); } break; case COLOR: { int r, g, b; if (sscanf(returnString, "%d,%d,%d", &r, &g, &b) == 3) { color[0] = static_cast (r & 0xff); color[1] = static_cast (g & 0xff); color[2] = static_cast (b & 0xff); } else { xpWarn("need three values for color\n", __FILE__, __LINE__); syntaxError = true; } } break; case FONT: font.assign(returnString); break; case FONTSIZE: sscanf(returnString, "%d", &fontSize); if (fontSize <= 0) { xpWarn("fontSize must be positive.\n", __FILE__, __LINE__); syntaxError = true; } break; case IMAGE: image.assign(returnString); break; case LATLON: { int id; sscanf(returnString, "%d", &id); vector::iterator ii = satelliteVector.begin(); while (ii != satelliteVector.end()) { if (ii->getID() == id) { satellite = &(*ii); if (name.empty()) name.assign(satellite->getName()); if (options->Verbosity() > 3) { ostringstream msg; msg << "Found satellite # " << id << " (" << satellite->getName() << ")\n"; xpMsg(msg.str(), __FILE__, __LINE__); } break; } ii++; } } break; case NAME: name.assign(returnString); break; case SPACING: checkLocale(LC_NUMERIC, "C"); sscanf(returnString, "%lf", &spacing); if (spacing < 0) { xpWarn("spacing must be positive\n", __FILE__, __LINE__); spacing = 0.1; syntaxError = true; } checkLocale(LC_NUMERIC, ""); break; case TRAIL: { char *ptr = returnString; while (ptr[0] != ',') { if (ptr[0] == '\0') { syntaxError = true; break; } ptr++; } if (syntaxError) break; if (!sscanf(++ptr, "%d,%d,%d", &trailStart, &trailEnd, &trailInterval) == 3) { xpWarn("Need four values for trail{}!\n", __FILE__, __LINE__); syntaxError = true; } else { switch (returnString[0]) { case 'g': case 'G': trailType = GROUND; break; case 'o': case 'O': trailType = ORBIT; break; default: xpWarn("Unknown type of orbit trail!\n", __FILE__, __LINE__); syntaxError = true; break; } if (trailInterval < 1) trailInterval = 1; } } break; case TRANSPARENT: { int r, g, b; if (sscanf(returnString, "%d,%d,%d", &r, &g, &b) == 3) { transparent_pixel[0] = static_cast (r & 0xff); transparent_pixel[1] = static_cast (g & 0xff); transparent_pixel[2] = static_cast (b & 0xff); } else { xpWarn("Need three values for transparency pixel!\n", __FILE__, __LINE__); syntaxError = true; } transparency = true; } break; case UNKNOWN: syntaxError = true; default: case DELIMITER: break; } if (val != DELIMITER && options->Verbosity() > 3) { ostringstream msg; msg << "value is " << keyWordString[val - '?']; if (returnString != NULL) msg << ", returnString is " << returnString; msg << endl; xpMsg(msg.str(), __FILE__, __LINE__); } delete [] returnString; if (syntaxError) { ostringstream errStr; errStr << "Syntax error in satellite file\n"; errStr << "line is \"" << line << "\"" << endl; xpWarn(errStr.str(), __FILE__, __LINE__); return; } if (val == ENDOFLINE) break; } if (satellite == NULL) { ostringstream errStr; errStr << "No satellite found for \"" << line << "\"" << endl; xpWarn(errStr.str(), __FILE__, __LINE__); return; } // Load TLE data here since select_ephemeris() in libsgp4sdp4 // changes it. This is in case the user wants to have two entries // with the same satellite. satellite->loadTLE(); time_t startTime = static_cast (options->TVSec() + trailStart * 60); time_t endTime = static_cast (options->TVSec() + trailEnd * 60); time_t interval = static_cast (trailInterval * 60); if (startTime > endTime) { time_t tmp = startTime; startTime = endTime; endTime = tmp; } double lat, lon, rad; satellite->getSpherical(startTime, lat, lon, rad); for (time_t t = startTime + interval; t <= endTime; t += interval) { const double prevLat = lat; const double prevLon = lon; double prevRad = rad; satellite->getSpherical(t, lat, lon, rad); if (trailType == GROUND) { rad = 1; prevRad = 1; } drawArc(prevLat, prevLon, prevRad, lat, lon, rad, color, spacing * deg_to_rad, planetProperties->Magnify(), planet, view, projection, annotationMap); } satellite->getSpherical(options->TVSec(), lat, lon, rad); if (trailType == GROUND) rad = 1; double X, Y, Z; if (sphericalToPixel(lat, lon, rad * planetProperties->Magnify(), X, Y, Z, planet, view, projection)) { const int ix = static_cast (floor(X + 0.5)); const int iy = static_cast (floor(Y + 0.5)); int xOffset = 0; int yOffset = 0; if (image.empty()) { Symbol *sym = new Symbol(color, ix, iy, symbolSize); annotationMap.insert(pair(Z, sym)); xOffset = symbolSize; yOffset = symbolSize; } else if (image.compare("none") != 0) { unsigned char *transparent = (transparency ? transparent_pixel : NULL); Icon *icon = new Icon(ix, iy, image, transparent); annotationMap.insert(pair(Z, icon)); xOffset = icon->Width() / 2; yOffset = icon->Height() / 2; } if (!name.empty()) { Text *t = new Text(color, ix, iy, xOffset, yOffset, align, name); if (!font.empty()) t->Font(font); if (fontSize > 0) t->FontSize(fontSize); annotationMap.insert(pair(Z, t)); } } vector::iterator a = altcirc.begin(); while (a != altcirc.end()) { // Given the angle of the spacecraft above the horizon, // compute the great arc distance from the sub-spacecraft // point const double r = *a - asin(sin(*a)/rad); drawCircle(lat, lon, r, color, spacing * deg_to_rad, planetProperties->Magnify(), planet, view, projection, annotationMap); a++; } } void loadSatelliteVector(PlanetProperties *planetProperties) { vector satfiles = planetProperties->SatelliteFiles(); vector::iterator ii = satfiles.begin(); while (ii != satfiles.end()) { string tleFile = *ii + ".tle"; const bool foundFile = findFile(tleFile, "satellites"); if (foundFile) { ifstream inFile(tleFile.c_str()); char lines[3][80]; while (inFile.getline(lines[0], 80) != NULL) { if ((inFile.getline(lines[1], 80) == NULL) || (inFile.getline(lines[2], 80) == NULL)) { ostringstream errStr; errStr << "Malformed TLE file (" << tleFile << ")?\n"; xpWarn(errStr.str(), __FILE__, __LINE__); break; } Satellite sat(lines); if (!sat.isGoodData()) { ostringstream errStr; errStr << "Bad TLE data in " << tleFile << endl; xpWarn(errStr.str(), __FILE__, __LINE__); continue; } satelliteVector.push_back(sat); } inFile.close(); } else { ostringstream errStr; errStr << "Can't load satellite TLE file " << tleFile << endl; xpWarn(errStr.str(), __FILE__, __LINE__); } ii++; } } void addSatellites(PlanetProperties *planetProperties, Planet *planet, View *view, ProjectionBase *projection, multimap &annotationMap) { if (planet->Index() != EARTH) return; vector satfiles = planetProperties->SatelliteFiles(); vector::iterator ii = satfiles.begin(); while (ii != satfiles.end()) { string satFile(*ii); bool foundFile = findFile(satFile, "satellites"); if (foundFile) { ifstream inFile(satFile.c_str()); char *line = new char[MAX_LINE_LENGTH]; while (inFile.getline (line, MAX_LINE_LENGTH, '\n') != NULL) readSatelliteFile(line, planet, view, projection, planetProperties, annotationMap); inFile.close(); delete [] line; } else { ostringstream errStr; errStr << "Can't load satellite file " << satFile << endl; xpWarn(errStr.str(), __FILE__, __LINE__); } ii++; } }