#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <sstream>
using namespace std;
#include <sys/time.h>
#include "config.h"
#include "xpDefines.h"
#include "xpUtil.h"
#ifndef _GETOPT_H
#include "xpGetopt.h"
#endif
#ifdef HAVE_LIBX11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#else
#include "ParseGeom.h"
extern "C" {
extern int
XParseGeometry(const char *string, int *x, int *y, unsigned int *width,
unsigned int *height);
}
#endif
#include "keywords.h"
#include "findBodyXYZ.h"
#include "Options.h"
#include "parseColor.h"
#include "PlanetProperties.h"
#include "libannotate/libannotate.h"
#include "libplanet/Planet.h"
#include "libprojection/libprojection.h"
extern void
printVersion();
Options* Options::instance_ = NULL;
Options*
Options::getInstance()
{
if (instance_ == NULL) instance_ = new Options;
return(instance_);
}
Options::~Options()
{
// delete instance_;
}
Options::Options() :
arcSpacing_(0.1),
background_(""),
baseMag_(10.0),
centerSelected_(false),
configFile_(defaultConfigFile),
dateFormat_("%c %Z"),
displayMode_(ROOT),
drawLabel_(false),
drawUTCLabel_(false),
dynamicOrigin_(""),
font_(defaultFont),
fontSize_(12),
fork_(false),
fov_(-1),
fovMode_(RADIUS),
geometryMask_(NoValue),
geometrySelected_(false),
glare_(28),
grsLon_(94),
grsSet_(false),
hibernate_(0),
idleWait_(0),
interpolateOriginFile_(false),
jplFile_(""),
labelMask_(XNegative),
labelX_(-15),
labelY_(15),
labelString_(""),
latitude_(0),
lightTime_(false),
localTime_(-1),
logMagStep_(0.4),
longitude_(0),
makeCloudMaps_(false),
markerBounds_(""),
north_(BODY),
numTimes_(0),
oppositeSide_(false),
origin_(SUN),
originFile_(""),
originID_(0),
originMode_(LBR),
originSet_(false),
outputBase_(""),
outputExt_(defaultMapExt),
outputStartIndex_(0),
oX_(0),
oY_(0),
oZ_(0),
pango_(false),
pathRelativeTo_(SUN),
pathRelativeToID_(-1),
post_command_(""),
prev_command_(""),
primary_(SUN),
printEphemeris_(false),
projection_(MULTIPLE),
projectionMode_(MULTIPLE),
quality_(80),
radius_(0.45),
random_(false),
rangeSpecified_(false),
range_(1000),
rotate_(0),
rotate0_(0),
saveDesktopFile_(false),
starFreq_(0.001),
star_map(defaultStarMap),
sunLat_(0),
sunLon_(0),
target_(EARTH),
targetID_(0),
targetMode_(BODY),
targetSet_(false),
timewarp(1),
tmpDir_(""),
transparency_(false),
transpng_(false),
tX_(0),
tY_(0),
tZ_(0),
universalTime_(true),
useCurrentTime_(true),
verbosity_(0),
virtual_root(false),
wait(300),
width(512),
height(512),
windowX_(0),
windowY_(0),
windowTitle_(""),
xid_(0)
{
memset(color_, 0, 3);
color_[0] = 255; // default label color is red
searchdir.push_back(DATADIR);
#if defined(HAVE_AQUA) || defined(HAVE_LIBX11)
char *homeDir = getenv("HOME");
if (homeDir != NULL)
{
ostringstream xplanetDir;
#ifdef HAVE_AQUA
xplanetDir << homeDir << "/Library/Xplanet";
#else
xplanetDir << homeDir << "/.xplanet";
#endif
searchdir.push_back(xplanetDir.str());
}
#endif
searchdir.push_back("xplanet");
struct timeval time;
gettimeofday(&time, NULL);
time_t t = time.tv_sec;
julianDay_ = toJulian(gmtime(static_cast<time_t *> (&t))->tm_year + 1900,
gmtime(static_cast<time_t *> (&t))->tm_mon + 1,
gmtime(static_cast<time_t *> (&t))->tm_mday,
gmtime(static_cast<time_t *> (&t))->tm_hour,
gmtime(static_cast<time_t *> (&t))->tm_min,
gmtime(static_cast<time_t *> (&t))->tm_sec);
tv_sec = get_tv_sec(julianDay_);
srandom((unsigned int) tv_sec);
}
void
Options::parseArgs(int argc, char **argv)
{
static struct option long_options[] =
{
{"arc_file", required_argument, NULL, ARC_FILE},
{"arc_spacing", required_argument, NULL, ARC_SPACING},
{"background", required_argument, NULL, BACKGROUND},
{"base_magnitude", required_argument, NULL, BASEMAG},
{"body", required_argument, NULL, TARGET},
{"center", required_argument, NULL, CENTER},
{"color", required_argument, NULL, COLOR},
{"config", required_argument, NULL, CONFIG_FILE},
{"date", required_argument, NULL, DATE},
{"date_format", required_argument, NULL, DATE_FORMAT},
{"dynamic_origin", required_argument, NULL, DYNAMIC_ORIGIN},
{"ephemeris_file", required_argument, NULL, JPL_FILE},
{"font", required_argument, NULL, FONT},
{"fontsize", required_argument, NULL, FONTSIZE},
{"fork", no_argument, NULL, FORK},
{"fov", required_argument, NULL, FOV},
{"geometry", required_argument, NULL, GEOMETRY},
{"glare", required_argument, NULL, GLARE},
{"gmtlabel", no_argument, NULL, UTCLABEL},
{"grs_longitude", required_argument, NULL, GRS_LON},
{"hibernate", required_argument, NULL, HIBERNATE},
{"idlewait", required_argument, NULL, IDLEWAIT},
{"interpolate_origin_file", no_argument, NULL, INTERPOLATE_ORIGIN_FILE},
{"jdate", required_argument, NULL, JDATE},
{"label", no_argument, NULL, LABEL},
{"labelpos", required_argument, NULL, LABELPOS},
{"label_string", required_argument, NULL, LABEL_STRING},
{"latitude", required_argument, NULL, LATITUDE},
{"light_time", no_argument, NULL, LIGHT_TIME},
{"localtime", required_argument, NULL, LOCALTIME},
{"log_magstep", required_argument, NULL, LOGMAGSTEP},
{"longitude", required_argument, NULL, LONGITUDE},
{"make_cloud_maps",no_argument, NULL, MAKECLOUDMAPS},
{"marker_file", required_argument, NULL, MARKER_FILE},
{"markerbounds", required_argument, NULL, MARKER_BOUNDS},
{"north", required_argument, NULL, NORTH},
{"num_times", required_argument, NULL, NUM_TIMES},
{"origin", required_argument, NULL, ORIGIN},
{"origin_file", required_argument, NULL, ORIGINFILE},
{"output", required_argument, NULL, OUTPUT},
{"output_start_index",required_argument,NULL,OUTPUT_START_INDEX},
{"pango", no_argument, NULL, PANGO},
{"path_relative_to", required_argument, NULL, PATH_RELATIVE_TO},
{"post_command", required_argument, NULL, POST_COMMAND},
{"prev_command", required_argument, NULL, PREV_COMMAND},
{"print_ephemeris",no_argument, NULL, EPHEMERIS},
{"projection", required_argument, NULL, PROJECTION},
{"proj_param", required_argument, NULL, PROJECTIONPARAMETER},
{"quality", required_argument, NULL, QUALITY},
{"radius", required_argument, NULL, RADIUS},
{"random", no_argument, NULL, RANDOM},
{"range", required_argument, NULL, RANGE},
{"rotate", required_argument, NULL, ROTATE},
{"save_desktop_file", no_argument, NULL, SAVE_DESKTOP_FILE},
{"searchdir", required_argument, NULL, SEARCHDIR},
{"spice_ephemeris", required_argument, NULL, SPICE_EPHEMERIS},
{"spice_file", required_argument, NULL, SPICE_FILE},
{"starfreq", required_argument, NULL, STARFREQ},
{"starmap", required_argument, NULL, STARMAP},
{"target", required_argument, NULL, TARGET},
{"tt", no_argument, NULL, TERRESTRIAL},
{"timewarp", required_argument, NULL, TIMEWARP},
{"tmpdir", required_argument, NULL, TMPDIR},
{"transparency", no_argument, NULL, TRANSPARENT},
{"transpng", required_argument, NULL, TRANSPNG},
{"utclabel", no_argument, NULL, UTCLABEL},
{"verbosity", required_argument, NULL, VERBOSITY},
{"version", no_argument, NULL, VERSIONNUMBER},
{"vroot", no_argument, NULL, VROOT},
{"wait", required_argument, NULL, WAIT},
{"window", no_argument, NULL, WINDOW},
{"window-id", required_argument, NULL, XWINID},
{"window_title", required_argument, NULL, WINDOWTITLE},
{"XID", required_argument, NULL, XWINID},
{"xscreensaver", no_argument, NULL, VROOT},
{NULL, 0, NULL, 0}
};
int this_option;
int option_index = 0;
while((this_option = getopt_long_only(argc, argv, "+", long_options,
&option_index)) >= 0)
{
switch (this_option)
{
case ARC_FILE:
arcFiles_.push_back(optarg);
break;
case ARC_SPACING:
sscanf(optarg, "%lf", &arcSpacing_);
if (arcSpacing_ < 0)
{
ostringstream errMsg;
errMsg << "Arc spacing must be > 0\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
arcSpacing_ = 0.1;
}
break;
case BACKGROUND:
background_ = optarg;
break;
case BASEMAG:
sscanf(optarg, "%lf", &baseMag_);
break;
case CENTER:
{
unsigned int w, h;
int x, y;
int mask = XParseGeometry(optarg, &x, &y, &w, &h);
centerSelected_ = ((mask & XValue) && (mask & YValue));
centerX_ = x;
centerY_ = y;
}
break;
case COLOR:
parseColor(optarg, color_);
break;
case CONFIG_FILE:
configFile_ = optarg;
break;
case DATE:
{
long int yyyymmdd, hhmmss;
sscanf(optarg, "%ld.%ld", &yyyymmdd, &hhmmss);
int yyyymm = yyyymmdd / 100;
int year = yyyymm/100;
int month = abs(yyyymm - year * 100);
int day = abs((int) yyyymmdd - yyyymm * 100);
int hhmm = hhmmss / 100;
int hour = hhmm / 100;
int min = hhmm - hour * 100;
int sec = hhmmss - hhmm * 100;
julianDay_ = toJulian(year, month, day, hour, min, sec);
tv_sec = get_tv_sec(julianDay_);
useCurrentTime_ = false;
}
break;
case DATE_FORMAT:
dateFormat_ = optarg;
break;
case DYNAMIC_ORIGIN:
dynamicOrigin_ = optarg;
originMode_ = LBR;
break;
case EPHEMERIS:
printEphemeris_ = true;
break;
case FONT:
#ifdef HAVE_LIBFREETYPE
font_.assign(optarg);
#else
{
ostringstream errMsg;
errMsg << "Sorry, this binary was built without FreeType "
<< "support. The -"
<< long_options[option_index].name
<< " option will be ignored.\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
#endif
break;
case FONTSIZE:
{
#ifdef HAVE_LIBFREETYPE
int val;
sscanf(optarg, "%d", &val);
if (val > 0) fontSize_ = val;
#else
{
ostringstream errMsg;
errMsg << "Sorry, this binary was built without FreeType "
<< "support. The -" << long_options[option_index].name
<< " option will be ignored.\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
#endif
}
break;
case FORK:
fork_ = true;
break;
case FOV:
sscanf(optarg, "%lf", &fov_);
if (fov_ <= 0)
{
xpWarn("FOV must be positive.\n", __FILE__, __LINE__);
}
else
{
fov_ *= deg_to_rad;
fovMode_ = FOV;
}
break;
case GEOMETRY:
{
geometryMask_ = XParseGeometry(optarg, &windowX_, &windowY_,
&width, &height);
geometrySelected_ = ((geometryMask_ & WidthValue)
&& (geometryMask_ & HeightValue));
}
break;
case GLARE:
{
double g;
sscanf(optarg, "%lf", &g);
if (g > 0) glare_ = g;
}
break;
case GRS_LON:
sscanf(optarg, "%lf", &grsLon_);
grsLon_ = fmod(grsLon_, 360);
grsSet_ = true;
break;
case HIBERNATE:
sscanf(optarg, "%lu", &hibernate_);
hibernate_ *= 1000;
break;
case IDLEWAIT:
sscanf(optarg, "%lu", &idleWait_);
idleWait_ *= 1000;
break;
case INTERPOLATE_ORIGIN_FILE:
interpolateOriginFile_ = true;
break;
case JDATE:
sscanf(optarg, "%lf", &julianDay_);
tv_sec = get_tv_sec(julianDay_);
useCurrentTime_ = false;
break;
case JPL_FILE:
jplFile_ = optarg;
break;
case LABEL:
drawLabel_ = true;
break;
case LABELPOS:
{
unsigned int temp;
labelMask_ = XParseGeometry(optarg, &labelX_,
&labelY_, &temp,
&temp);
if (labelMask_ & (WidthValue | HeightValue))
{
xpWarn("width and height supplied in -labelpos will be ignored\n",
__FILE__, __LINE__);
}
drawLabel_ = true;
}
break;
case LABEL_STRING:
labelString_ = optarg;
drawLabel_ = true;
break;
case LATITUDE:
sscanf(optarg, "%lf", &latitude_);
if (latitude_ < -90) latitude_ = -90;
if (latitude_ > 90) latitude_ = 90;
latitude_ *= deg_to_rad;
originMode_ = LBR;
break;
case LIGHT_TIME:
lightTime_ = true;
break;
case LOCALTIME:
sscanf(optarg, "%lf", &localTime_);
if (localTime_ < 0 || localTime_ > 24)
{
localTime_ = fmod(localTime_, 24.);
if (localTime_ < 0) localTime_ += 24;
ostringstream errStr;
errStr << "localtime set to " << localTime_ << "\n";
xpWarn(errStr.str(), __FILE__, __LINE__);
}
originMode_ = LBR;
break;
case LOGMAGSTEP:
sscanf(optarg, "%lf", &logMagStep_);
break;
case LONGITUDE:
sscanf(optarg, "%lf", &longitude_);
longitude_ = fmod(longitude_, 360);
longitude_ *= deg_to_rad;
originMode_ = LBR;
break;
case MAKECLOUDMAPS:
displayMode_ = OUTPUT;
makeCloudMaps_ = true;
break;
case MARKER_BOUNDS:
markerBounds_.assign(optarg);
break;
case MARKER_FILE:
markerFiles_.push_back(optarg);
break;
case NORTH:
{
char *lowercase = optarg;
char *ptr = optarg;
while (*ptr) *ptr++ = tolower(*optarg++);
if (strncmp(lowercase, "galactic", 1) == 0)
north_ = GALACTIC;
else if (strncmp(lowercase, "orbit", 1) == 0)
north_ = ORBIT;
else if (strncmp(lowercase, "path", 1) == 0)
north_ = PATH;
else if (strncmp(lowercase, "terrestrial", 1) == 0)
north_ = TERRESTRIAL;
else
{
if (strncmp(lowercase, "body", 1) != 0)
xpWarn("Unknown value for -north, using body\n",
__FILE__, __LINE__);
north_ = BODY;
}
}
break;
case NUM_TIMES:
sscanf(optarg, "%d", &numTimes_);
if (numTimes_ < 0) numTimes_ = 0;
break;
case ORIGIN:
{
char *name = optarg;
if (name[0] == '-')
{
oppositeSide_ = true;
name++;
}
origin_ = Planet::parseBodyName(name);
switch (origin_)
{
case ABOVE_ORBIT:
originMode_ = ABOVE;
break;
case BELOW_ORBIT:
originMode_ = BELOW;
break;
case MAJOR_PLANET:
originMode_ = MAJOR;
break;
case NAIF:
if (strlen(name) < 5)
{
ostringstream errMsg;
errMsg << "NAIF id must be specified "
<< "(e.g. naif-82 for Cassini)\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
else
{
sscanf(name+4, "%d", &originID_);
}
originMode_ = LBR;
break;
case NORAD:
if (strlen(name) < 6)
{
ostringstream errMsg;
errMsg << "NORAD id must be specified "
<< "(e.g. NORAD20580 for Hubble)\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
else
{
sscanf(name+5, "%d", &originID_);
}
originMode_ = LBR;
break;
case RANDOM_BODY:
originMode_ = RANDOM;
break;
case SAME_SYSTEM:
originMode_ = SYSTEM;
break;
case ALONG_PATH:
case UNKNOWN_BODY:
xpWarn("Invalid origin specified, using SUN\n",
__FILE__, __LINE__);
origin_ = SUN;
default:
originMode_ = BODY;
break;
}
}
break;
case ORIGINFILE:
originFile_ = optarg;
originMode_ = LBR;
break;
case TRANSPNG:
transpng_ = true;
// fall through to OUTPUT block
case OUTPUT:
outputBase_ = optarg;
if (outputBase_.find('.') == string::npos)
{
outputExt_ = defaultMapExt;
}
else
{
outputExt_.assign(outputBase_, outputBase_.rfind('.'),
outputBase_.size());
outputBase_.assign(outputBase_, 0, outputBase_.rfind('.'));
}
displayMode_ = OUTPUT;
geometrySelected_ = true;
break;
case OUTPUT_START_INDEX:
sscanf(optarg, "%d", &outputStartIndex_);
break;
case PANGO:
#ifdef HAVE_LIBPANGOFT2
pango_ = true;
#else
{
ostringstream errMsg;
errMsg << "Sorry, this binary was built without Pango "
<< "support. The -" << long_options[option_index].name
<< " option will be ignored.\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
#endif
break;
case PATH_RELATIVE_TO:
pathRelativeTo_ = Planet::parseBodyName(optarg);
switch (pathRelativeTo_)
{
case NAIF:
if (strlen(optarg) < 5)
{
ostringstream errMsg;
errMsg << "NAIF id must be specified "
<< "(e.g. naif-82 for Cassini)\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
else
{
sscanf(optarg+4, "%d", &pathRelativeToID_);
}
break;
case NORAD:
if (strlen(optarg) < 6)
{
ostringstream errMsg;
errMsg << "NORAD id must be specified "
<< "(e.g. NORAD20580 for Hubble)\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
else
{
sscanf(optarg+5, "%d", &pathRelativeToID_);
}
break;
case RANDOM_BODY:
case ABOVE_ORBIT:
case ALONG_PATH:
case BELOW_ORBIT:
case DEFAULT:
case MAJOR_PLANET:
case SAME_SYSTEM:
case UNKNOWN_BODY:
xpWarn("Unknown body specified for path, using SUN\n",
__FILE__, __LINE__);
pathRelativeTo_ = SUN;
default:
break;
}
break;
case POST_COMMAND:
post_command_.assign(optarg);
break;
case PREV_COMMAND:
prev_command_.assign(optarg);
break;
case PROJECTION:
projectionMode_ = getProjectionType(optarg);
break;
case PROJECTIONPARAMETER:
{
double d;
sscanf(optarg, "%lf", &d);
projectionParameters_.push_back(d * deg_to_rad);
}
break;
case QUALITY:
sscanf(optarg, "%d", &quality_);
if (quality_ < 0) quality_ = 0;
if (quality_ > 100) quality_ = 100;
break;
case RADIUS:
sscanf(optarg, "%lf", &radius_);
if (radius_ <= 0)
xpExit("radius must be positive\n", __FILE__, __LINE__);
radius_ /= 100;
fov_ = 1; // just a sneaky way to know that -radius has
// been set
fovMode_ = RADIUS;
break;
case RANDOM:
random_ = true;
originMode_ = LBR;
// This block is repeated in setOrigin(), but this way the
// user can use -random to set a random rotation and then
// set the sub-observer point another way, like with
// -origin sun
longitude_ = random() % 360;
longitude_ *= deg_to_rad;
// Weight random latitudes towards the equator
latitude_ = (random() % 2000)/1000.0 - 1;
latitude_ = asin(latitude_);
rotate0_ = random() % 360;
rotate0_ *= deg_to_rad;
rotate_ = rotate0_;
break;
case RANGE:
sscanf(optarg, "%lf", &range_);
rangeSpecified_ = (range_ > 1);
if (!rangeSpecified_)
{
range_ = 1000;
xpWarn("range must be greater than 1\n",
__FILE__, __LINE__);
}
break;
case ROTATE:
sscanf(optarg, "%lf", &rotate0_);
rotate0_ = fmod(rotate0_, 360.) * deg_to_rad;
rotate_ = rotate0_;
break;
case SAVE_DESKTOP_FILE:
saveDesktopFile_ = true;
break;
case SEARCHDIR:
searchdir.push_back(optarg);
break;
case SPICE_EPHEMERIS:
{
#ifdef HAVE_CSPICE
int id;
sscanf(optarg, "%d", &id);
spiceEphemeris_.push_back(id);
#else
ostringstream errMsg;
errMsg << "Sorry, this binary was built without SPICE "
<< "support. The -"
<< long_options[option_index].name
<< " option will be ignored.\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
#endif
}
break;
case SPICE_FILE:
{
#ifdef HAVE_CSPICE
spiceFiles_.push_back(optarg);
#else
ostringstream errMsg;
errMsg << "Sorry, this binary was built without SPICE "
<< "support. The -"
<< long_options[option_index].name
<< " option will be ignored.\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
#endif
}
break;
case STARFREQ:
sscanf(optarg, "%lf", &starFreq_);
if (starFreq_ < 0) starFreq_ = 0;
else if (starFreq_ > 1) starFreq_ = 1;
break;
case STARMAP:
star_map = optarg;
break;
case TARGET:
target_ = Planet::parseBodyName(optarg);
switch (target_)
{
case ALONG_PATH:
targetMode_ = LOOKAT;
break;
case MAJOR_PLANET:
targetMode_ = MAJOR;
break;
case NAIF:
if (strlen(optarg) < 5)
{
ostringstream errMsg;
errMsg << "NAIF id must be specified "
<< "(e.g. naif-82 for Cassini)\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
else
{
sscanf(optarg+4, "%d", &targetID_);
targetMode_ = LOOKAT;
}
break;
case NORAD:
if (strlen(optarg) < 6)
{
ostringstream errMsg;
errMsg << "NORAD id must be specified "
<< "(e.g. NORAD20580 for Hubble)\n";
xpWarn(errMsg.str(), __FILE__, __LINE__);
}
else
{
sscanf(optarg+5, "%d", &targetID_);
targetMode_ = LOOKAT;
}
break;
case RANDOM_BODY:
targetMode_ = RANDOM;
break;
case ABOVE_ORBIT:
case BELOW_ORBIT:
case SAME_SYSTEM:
case UNKNOWN_BODY:
xpWarn("Unknown target body specified, using EARTH\n",
__FILE__, __LINE__);
target_ = EARTH;
default:
targetMode_ = BODY;
break;
}
break;
case TERRESTRIAL:
universalTime_ = false;
break;
case TIMEWARP:
sscanf(optarg, "%lf", &timewarp);
useCurrentTime_ = false;
break;
case TMPDIR:
tmpDir_.assign(optarg);
tmpDir_ += separator;
break;
case TRANSPARENT:
transparency_ = true;
break;
case UTCLABEL:
drawLabel_ = true;
drawUTCLabel_ = true;
break;
case VERBOSITY:
sscanf(optarg, "%d", &verbosity_);
break;
case VERSIONNUMBER:
printVersion();
exit(EXIT_SUCCESS);
break;
case VROOT:
virtual_root = true;
break;
case WAIT:
sscanf(optarg, "%d", &wait);
break;
case WINDOWTITLE:
windowTitle_.assign(optarg);
// fall through
case WINDOW:
displayMode_ = WINDOW;
geometrySelected_ = true;
break;
default:
case XWINID:
{
if (optarg[0] == '0'
&& (optarg[1] == 'x' || optarg[1] == 'X'))
{
sscanf(optarg, "%lx", &xid_);
}
else
{
sscanf(optarg, "%lu", &xid_);
}
displayMode_ = WINDOW;
}
break;
case UNKNOWN:
{
cout << "Valid options to Xplanet are:\n";
unsigned int i = 0;
while (1)
{
if (long_options[i].name == NULL) break;
printf("-%-20s", long_options[i].name);
if (long_options[i].has_arg) cout << " (needs argument)";
cout << endl;
i++;
}
exit(EXIT_SUCCESS);
}
break;
}
}
if (optind < argc)
{
string errMsg("unrecognized options: ");
while (optind < argc)
{
errMsg += argv[optind++];
errMsg += " ";
}
errMsg += "\n";
if (long_options[option_index].has_arg)
{
errMsg += "Perhaps you didn't supply an argument to -";
errMsg += long_options[option_index].name;
errMsg += "?\n";
}
xpExit(errMsg, __FILE__, __LINE__);
}
// useCurrentTime is false if:
// 1) -date or -jdate is used
// 2) -timewarp is used
// 3) -origin_file is used AND -interpolate_origin_file is not
// used
if (useCurrentTime_)
{
if (!originFile_.empty() && !interpolateOriginFile_)
{
useCurrentTime_ = false;
}
}
if (!originFile_.empty()
|| !dynamicOrigin_.empty()) originMode_ = LBR;
// A number of options are meaningless if we're not looking at a
// planetary body.
if (targetMode_ == LOOKAT)
{
if (projectionMode_ != MULTIPLE)
{
ostringstream errStr;
errStr << "Can't use -projection option without a "
<< "planetary body\n";
xpWarn(errStr.str(), __FILE__, __LINE__);
projectionMode_ = MULTIPLE;
}
if (fovMode_ != FOV)
{
fov_ = 45 * deg_to_rad;
fovMode_ = FOV;
}
if (north_ == BODY || north_ == ORBIT)
{
north_ = TERRESTRIAL;
}
}
}
void
Options::getOrigin(double &X, double &Y, double &Z)
{
X = oX_;
Y = oY_;
Z = oZ_;
}
void
Options::setOrigin(const double X, const double Y, const double Z)
{
oX_ = X;
oY_ = Y;
oZ_ = Z;
}
void
Options::getTarget(double &X, double &Y, double &Z)
{
X = tX_;
Y = tY_;
Z = tZ_;
}
void
Options::setTarget(const double X, const double Y, const double Z)
{
tX_ = X;
tY_ = Y;
tZ_ = Z;
}
void
Options::setOrigin(PlanetProperties *planetProperties[])
{
switch (originMode_)
{
case LBR:
{
if (random_)
{
longitude_ = random() % 360;
longitude_ *= deg_to_rad;
// Weight random latitudes towards the equator
latitude_ = (random() % 2000)/1000.0 - 1;
latitude_ = asin(latitude_);
rotate0_ = random() % 360;
rotate0_ *= deg_to_rad;
rotate_ = rotate0_;
}
if (origin_ == NAIF || origin_ == NORAD)
{
findBodyXYZ(julianDay_, origin_, originID_, oX_, oY_, oZ_);
}
else
{
if (!targetSet_)
xpExit("Target body not set!\n", __FILE__, __LINE__);
body referenceBody = target_;
if (!originFile_.empty()
|| !dynamicOrigin_.empty()) referenceBody = origin_;
Planet p(julianDay_, referenceBody);
p.calcHeliocentricEquatorial();
if (localTime_ >= 0)
{
double subSolarLat = 0;
double subSolarLon = 0;
p.XYZToPlanetographic(0, 0, 0, subSolarLat, subSolarLon);
longitude_ = (subSolarLon - M_PI
+ p.Flipped() * localTime_ * M_PI / 12);
}
p.PlanetographicToXYZ(oX_, oY_, oZ_,
latitude_, longitude_, range_);
}
}
break;
case MAJOR:
case RANDOM:
case SYSTEM:
{
if (!targetSet_)
xpExit("Target body not set!\n", __FILE__, __LINE__);
// check to see that at least one body has random_origin=true
bool no_random_origin = true;
for (int i = 0; i < RANDOM_BODY; i++)
{
if (i == target_) continue;
if (planetProperties[i]->RandomOrigin())
{
no_random_origin = false;
break;
}
}
if (no_random_origin)
{
string errMsg("Target is ");
errMsg += planetProperties[target_]->Name();
errMsg += ", random_origin is false for all other bodies. ";
errMsg += "Check your config file.\n";
xpExit(errMsg, __FILE__, __LINE__);
}
bool found_origin = false;
while (!found_origin)
{
origin_ = static_cast<body> (random() % RANDOM_BODY);
if (verbosity_ > 1)
{
ostringstream msg;
msg << "target = " << body_string[target_] << ", origin = "
<< body_string[origin_] << endl;
xpMsg(msg.str(), __FILE__, __LINE__);
}
if (origin_ == target_) continue;
if (originMode_ == RANDOM)
{
found_origin = true;
}
else
{
Planet o(julianDay_, origin_);
if (originMode_ == MAJOR)
{
found_origin = (o.Primary() == SUN);
}
else if (originMode_ == SYSTEM)
{
// SYSTEM means one of three things:
// 1) target and origin have same primary
// 2) target is origin's primary
// 3) origin is target's primary
found_origin = ((primary_ == o.Primary()
|| o.Primary() == target_
|| origin_ == primary_));
}
}
if (found_origin)
found_origin = planetProperties[origin_]->RandomOrigin();
} // while (!found_origin)
}
// fall through
case BODY:
{
findBodyXYZ(julianDay_, origin_, originID_, oX_, oY_, oZ_);
if (oppositeSide_)
{
oX_ = 2*tX_ - oX_;
oY_ = 2*tY_ - oY_;
oZ_ = 2*tZ_ - oZ_;
}
}
break;
case ABOVE:
case BELOW:
{
if (!targetSet_)
xpExit("Target body not set!\n", __FILE__, __LINE__);
double pX, pY, pZ;
findBodyXYZ(julianDay_, primary_, -1, pX, pY, pZ);
double vX, vY, vZ;
findBodyVelocity(julianDay_, target_, targetID_, primary_, -1,
vX, vY, vZ);
// cross product of position and velocity vectors points to the
// orbital north pole
double pos[3] = { tX_ - pX, tY_ - pY, tZ_ - pZ };
double vel[3] = { vX, vY, vZ };
double north[3];
cross(pos, vel, north);
double mag = sqrt(dot(north, north));
Planet primary(julianDay_, primary_);
double dist = FAR_DISTANCE * primary.Radius();
oX_ = dist * north[0]/mag + pX;
oY_ = dist * north[1]/mag + pY;
oZ_ = dist * north[2]/mag + pZ;
const double radius = sqrt(pos[0] * pos[0] + pos[1] * pos[1]
+ pos[2] * pos[2]);
if (fov_ < 0) // will only be zero if -fov or -radius haven't
// been specified
{
fov_ = 4*radius/dist; // fit the orbit on the screen
fovMode_ = FOV;
}
if (originMode_ == BELOW)
{
oX_ -= 2 * (oX_ - pX);
oY_ -= 2 * (oY_ - pX);
oZ_ -= 2 * (oZ_ - pX);
}
}
break;
}
if (rangeSpecified_ && targetMode_ != LOOKAT)
{
Planet p2(julianDay_, target_);
p2.calcHeliocentricEquatorial();
p2.XYZToPlanetographic(oX_, oY_, oZ_, latitude_, longitude_);
p2.PlanetographicToXYZ(oX_, oY_, oZ_, latitude_, longitude_,
range_);
}
originSet_ = true;
}
void
Options::setTarget(PlanetProperties *planetProperties[])
{
switch (targetMode_)
{
case MAJOR:
case RANDOM:
{
bool no_random_target = true;
for (int i = 0; i < RANDOM_BODY; i++)
{
if (planetProperties[i]->RandomTarget())
{
no_random_target = false;
break;
}
}
if (no_random_target)
{
ostringstream errMsg;
errMsg << "random_target is false for all bodies. "
<< "Check your config file.\n";
xpExit(errMsg.str(), __FILE__, __LINE__);
}
bool found_target = false;
while (!found_target)
{
target_ = (body) (random() % RANDOM_BODY);
found_target = planetProperties[target_]->RandomTarget();
if (found_target && targetMode_ == MAJOR)
{
Planet p(julianDay_, target_);
found_target = (p.Primary() == SUN);
}
}
}
// fall through
case BODY:
{
Planet t(julianDay_, target_);
primary_ = t.Primary();
}
break;
case LOOKAT:
if (target_ == NAIF
|| target_ == ALONG_PATH)
{
primary_ = SUN;
}
else if (target_ == NORAD)
{
primary_ = EARTH;
}
break;
default:
xpExit("Unknown target mode?\n", __FILE__, __LINE__);
}
if (target_ == ALONG_PATH)
{
findBodyVelocity(julianDay_, origin_, originID_,
pathRelativeTo_, pathRelativeToID_,
tX_, tY_, tZ_);
tX_ *= FAR_DISTANCE;
tY_ *= FAR_DISTANCE;
tZ_ *= FAR_DISTANCE;
}
else
{
findBodyXYZ(julianDay_, target_, targetID_, tX_, tY_, tZ_);
}
targetSet_ = true;
}
void
Options::incrementTime(const double sec)
{
julianDay_ += sec/86400;
tv_sec = get_tv_sec(julianDay_);
}
void
Options::setTime(const double jd)
{
julianDay_ = jd;
tv_sec = get_tv_sec(julianDay_);
}
int
Options::OriginMode() const
{
int returnVal = originMode_;
if (originMode_ == MAJOR
|| originMode_ == RANDOM
|| originMode_ == SYSTEM)
returnVal = BODY;
return(returnVal);
}
syntax highlighted by Code2HTML, v. 0.9.1