1
/****************************************************************************
2
Xplanet 0.94 - render an image of a planet into an X window
3
Copyright (C) 2002 Hari Nair <hari@alumni.caltech.edu>
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
****************************************************************************/
33
#include "Satellite.h"
36
static list<Satellite> full_satellite_list; // need this for -sattrackid
39
satelliteFileExists(string &filename)
43
cout << "\nLooking for satellite file ...\n"
47
if (fileExists(filename)) return(true);
49
string satellite_file = "satellites";
50
satellite_file += separator;
51
satellite_file += filename;
53
if (fileExists(satellite_file))
55
filename = satellite_file;
59
satellite_file = prefix;
60
satellite_file += separator;
61
satellite_file += "satellites";
62
satellite_file += separator;
63
satellite_file += filename;
65
if (fileExists(satellite_file))
67
filename = satellite_file;
74
// Given an value X and radius d, this routine draws a half-circle in
75
// the plane where X is constant.
77
drawAltitudeHalfCirc(const double rot[3][3], const double X, const double d,
78
bool Z_positive, const string arcopts, ofstream &sat_a)
81
double Z = (1 - X*X - Y*Y);
82
if (fabs(Z) < 1e-5) Z = 0;
83
Z = (Z_positive ? sqrt(Z) : -sqrt(Z));
86
point.setXYZ(X, Y, Z);
88
point.rectangularToSpherical();
90
for (double siny = 1; siny >= -1; siny -= 1./10.)
92
double prev_lat = point.lat;
93
double prev_lon = point.lon;
95
Y = sin(M_PI_2 * siny) * d;
97
if (fabs(Z) < 1e-5) Z = 0;
98
Z = (Z_positive ? sqrt(Z) : -sqrt(Z));
100
point.setXYZ(X, Y, Z);
102
point.rectangularToSpherical();
103
sat_a << prev_lat/deg_to_rad << '\t' << prev_lon/deg_to_rad
104
<< '\t' << point.lat/deg_to_rad
105
<< '\t' << point.lon/deg_to_rad;
106
if (!arcopts.empty()) sat_a << " " << arcopts;
111
// write the entry in the marker/arc file for this satellite
113
writeSatFiles(Satellite *this_sat, char *options,
114
ofstream &sat_a, ofstream &sat_m)
119
list<double> altcirc;
123
int fontsize = opts.fontsize;
126
string name = this_sat->getName();
128
char *returnstring = NULL;
130
int trail_type = ORBIT;
133
int trail_interval = 1;
136
bool end_of_line = false;
137
bool syntax_error = false;
142
switch (parse(i, options, returnstring))
145
if (returnstring == NULL) break;
146
switch (returnstring[0])
169
cerr << "Unrecognized option for align in "
170
<< "satellite file" << endl;
177
if (returnstring == NULL) break;
178
sscanf(returnstring, "%lf", &angle);
179
if (angle < 0) angle *= -1;
180
if (angle > 90) angle = 90;
182
altcirc.push_back(angle * deg_to_rad);
186
if (returnstring == NULL) break;
187
color.assign(returnstring);
188
arcopts += (" color=" + color);
196
if (returnstring == NULL) break;
197
font.assign(returnstring);
200
if (returnstring == NULL) break;
201
sscanf(returnstring, "%d", &fontsize);
202
if (fontsize < 0) fontsize = opts.fontsize;
205
if (returnstring == NULL) break;
206
image.assign(returnstring);
209
if (returnstring == NULL) break;
210
name.assign(returnstring);
214
if (returnstring == NULL) break;
216
sscanf(returnstring, "%f", &spacing);
217
if (spacing < 0.001) spacing = 0.001;
218
arcopts += " spacing=";
219
arcopts += returnstring;
224
char *ptr = returnstring;
225
while (ptr[0] != ',')
235
if (syntax_error) break;
237
if (!sscanf(++ptr, "%d,%d,%d", &trail_start, &trail_end,
238
&trail_interval) == 3)
240
cerr << "Need four values for trail{}!\n";
245
switch (returnstring[0])
256
cerr << "Unknown type of orbit trail!\n";
260
if (trail_interval < 1) trail_interval = 1;
265
if (returnstring == NULL) break;
267
transparency.assign(returnstring);
270
if (!sscanf(returnstring, "%d,%d,%d", &r, &g, &b) == 3)
272
cerr << "Need three values for transparency pixel!\n";
283
if (returnstring != NULL)
285
delete [] returnstring;
291
cerr << "Syntax error in satellite file\n"
292
<< "line is \"" << this_sat->getID() << " " << options
300
const double EARTH_RADIUS = 6378.140;
302
// Reload TLE data here since select_ephemeris() in libsgp4sdp4
303
// changes it. This is in case the user wants to have two entries
304
// with the same satellite.
307
time_t start_time = (time_t) (opts.time.tv_sec + trail_start * 60);
308
time_t end_time = (time_t) (opts.time.tv_sec + trail_end * 60);
309
time_t interval = (time_t) (trail_interval * 60);
311
if (start_time > end_time)
313
time_t tmp = start_time;
314
start_time = end_time;
318
double lat = 0, lon = 0, alt = 0;
319
this_sat->getSpherical(start_time, lat, lon, alt);
321
for (time_t t = start_time + interval; t <= end_time; t += interval)
323
double prev_lat = lat;
324
double prev_lon = lon;
325
double prev_alt = alt;
326
this_sat->getSpherical(t, lat, lon, alt);
327
sat_a << prev_lat/deg_to_rad << '\t' << prev_lon/deg_to_rad
328
<< '\t' << lat/deg_to_rad << '\t' << lon/deg_to_rad;
330
if (!arcopts.empty()) sat_a << " " << arcopts;
331
if (trail_type == ORBIT)
332
sat_a << " radius=" << 1 + prev_alt/EARTH_RADIUS
333
<< " radius=" << 1 + alt/EARTH_RADIUS;
338
this_sat->getSpherical((time_t) opts.time.tv_sec, lat, lon, alt);
340
sat_m << lat/deg_to_rad << ' ' << lon/deg_to_rad;
341
if (trail_type == ORBIT)
342
sat_m << " radius=" << 1 + alt/EARTH_RADIUS;
365
cerr << "Unknown alignment????\n";
368
if (!color.empty()) sat_m << " color=" << color;
369
if (!font.empty()) sat_m << " font=" << font;
370
if (fontsize != opts.fontsize) sat_m << " fontsize=" << fontsize;
371
if (!image.empty()) sat_m << " image=" << image;
372
if (!name.empty()) sat_m << " {" << name << "}";
373
if (!transparency.empty())
374
sat_m << " transparent={" << transparency << "}";
378
// Distance of satellite from Earth's center, in units of Earth radii
379
double Rs = 1 + alt/EARTH_RADIUS;
382
rotateXYZ(rot, 0, lat, -lon);
384
list<double>::iterator a = altcirc.begin();
385
while (a != altcirc.end())
387
double phi = asin(sin(*a) / Rs);
388
double X = -cos(*a + phi);
389
double d = sin(*a + phi);
391
drawAltitudeHalfCirc(rot, X, d, true, arcopts, sat_a);
392
drawAltitudeHalfCirc(rot, X, d, false, arcopts, sat_a);
398
readSatFileLine(const char *line, list<Satellite> &satellite_list,
399
Satellite *&this_sat, char *&options)
402
while (isDelimiter(line[i])) i++;
403
if (isEndOfLine(line[i])) return(-1);
406
sscanf(line + i, "%d", &id);
407
while (!(isDelimiter(line[i]) || isEndOfLine(line[i]))) i++;
411
list<Satellite>::iterator p = satellite_list.begin();
412
while (p != satellite_list.end())
414
if (id == p->getID())
419
cout << "Found ID #" << id << " ("
420
<< this_sat->getName() << ")\n";
427
if (this_sat == NULL)
429
cerr << "Satellite ID #" << id << " not found in TLE file\n";
434
strcpy(options, line + i);
439
// Run through the list of satellite files and check to see that
440
// they exist, along with the corresponding TLE files.
444
list<string> remove_list;
446
list<string>::iterator p = opts.satellitefile.begin();
447
while(p != opts.satellitefile.end())
449
if (satelliteFileExists(*p))
451
string tlefile = *p + ".tle";
452
if (!satelliteFileExists(tlefile))
454
cerr << "Can't open TLE file " << tlefile << endl;
455
remove_list.push_back(*p);
460
cerr << "Can't open satellite file " << *p << endl;
461
remove_list.push_back(*p);
466
p = remove_list.begin();
467
while (p != remove_list.end())
469
opts.satellitefile.remove(*p);
475
createSatelliteList()
479
list<string>::iterator p = opts.satellitefile.begin();
480
while(p != opts.satellitefile.end())
482
string tlefile = *p + ".tle";
483
ifstream infile(tlefile.c_str());
486
while (infile.getline(lines[0], 80) != NULL)
488
if ((infile.getline(lines[1], 80) == NULL)
489
|| (infile.getline(lines[2], 80) == NULL))
491
cerr << "Malformed TLE file?\n";
495
Satellite sat(lines);
497
if (!sat.isGoodData())
499
cerr << "Bad TLE data\n";
502
if (opts.debug) cout << "Read satellite with ID "
503
<< sat.getID() << endl;
505
full_satellite_list.push_back(sat);
514
createSatelliteFiles(string tmpdir)
517
list<string>::iterator p = opts.satellitefile.begin();
518
while(p != opts.satellitefile.end())
520
list<Satellite> satellite_list;
521
list<Satellite> zero_list;
523
string tlefile = *p + ".tle";
524
if (opts.debug) cout << "Opening TLE file " << tlefile << endl;
526
ifstream infile(tlefile.c_str());
528
while (infile.getline(lines[0], 80) != NULL)
530
if ((infile.getline(lines[1], 80) == NULL)
531
|| (infile.getline(lines[2], 80) == NULL))
533
cerr << "Malformed TLE file?\n";
537
Satellite sat(lines);
538
if (!sat.isGoodData())
540
cerr << "Bad TLE data\n";
543
if (opts.debug) cout << "Read ID " << sat.getID() << endl;
545
satellite_list.push_back(sat);
546
zero_list.push_back(sat);
551
// Now write one marker and one great arc file for each
555
int digits = (int) (log10((double) opts.satellitefile.size())
557
sprintf(pid, "%5.5d-%.*d", ((int) (getpid() % 10000)),
560
string sat_markers = (tmpdir + separator
561
+ "xplanet-markers." + pid);
562
string sat_arcs = tmpdir + separator + "xplanet-arcs." + pid;
564
ofstream sat_a(sat_arcs.c_str());
565
ofstream sat_m(sat_markers.c_str());
567
if (opts.debug) cout << "Opening satellite file " << *p << endl;
568
infile.open(p->c_str());
570
// Now read each line and write the appropriate entry to
571
// the marker/arc files
572
char *line = new char[256];
573
char *zero_options = NULL;
574
while (infile.getline(line, 256, '\n') != NULL)
576
Satellite *this_sat = NULL;
577
char *options = new char[256];
578
int id = readSatFileLine(line, satellite_list,
582
if (zero_options == NULL)
584
zero_options = new char[256];
585
strcpy(zero_options, options);
589
cerr << "ID 0 already specified in satellite file\n";
594
writeSatFiles(this_sat, options, sat_a, sat_m);
595
zero_list.remove(*this_sat);
600
if (zero_options != NULL)
602
list<Satellite>::iterator p2 = zero_list.begin();
603
while (p2 != zero_list.end())
605
writeSatFiles(&(*p2), zero_options, sat_a, sat_m);
608
delete [] zero_options;
616
opts.markerfile.push_back(sat_markers);
617
opts.greatarcfile.push_back(sat_arcs);
625
cleanupSatelliteFiles(string tmpdir)
628
list<string>::iterator p = opts.satellitefile.begin();
629
while(p != opts.satellitefile.end())
632
int digits = (int) (log10((double) opts.satellitefile.size())
634
sprintf(pid, "%5.5d-%.*d", ((int) (getpid() % 10000)),
637
string sat_markers = tmpdir + separator + "xplanet-markers." + pid;
638
string sat_arcs = tmpdir + separator + "xplanet-arcs." + pid;
640
unlink(sat_markers.c_str());
641
unlink(sat_arcs.c_str());
647
getSatLocation(const int id, const time_t time, double &lat, double &lon,
650
Satellite *this_sat = NULL;
651
list<Satellite>::iterator p = full_satellite_list.begin();
652
while (p != full_satellite_list.end())
654
if (id == p->getID())
659
cout << "Found ID #" << id << " (" << this_sat->getName()
667
if (this_sat == NULL)
669
if (opts.satellitefile.size() == 0)
671
cerr << "A TLE file must be specified using the "
672
<< "-satfile option.\n";
676
cerr << "Satellite ID #" << id << " not found in TLE file\n";
681
// Reload TLE data here since select_ephemeris() in libsgp4sdp4
682
// changes it. This is in case the user wants to have two entries
683
// with the same satellite.
686
this_sat->getSpherical(time, lat, lon, alt);