1 //==============================================================================
2 //
3 //  This file is part of GPSTk, the GPS Toolkit.
4 //
5 //  The GPSTk is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU Lesser General Public License as published
7 //  by the Free Software Foundation; either version 3.0 of the License, or
8 //  any later version.
9 //
10 //  The GPSTk 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 Lesser General Public License for more details.
14 //
15 //  You should have received a copy of the GNU Lesser General Public
16 //  License along with GPSTk; if not, write to the Free Software Foundation,
17 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 //  This software was developed by Applied Research Laboratories at the
20 //  University of Texas at Austin.
21 //  Copyright 2004-2020, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 //  This software was developed by Applied Research Laboratories at the
28 //  University of Texas at Austin, under contract to an agency or agencies
29 //  within the U.S. Department of Defense. The U.S. Government retains all
30 //  rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 //  Pursuant to DoD Directive 523024
33 //
34 //  DISTRIBUTION STATEMENT A: This software has been approved for public
35 //                            release, distribution is unlimited.
36 //
37 //==============================================================================
38 
39 /**
40  * @file Timetable.cpp
41  * Compute reference satellites time table for program DDBase.
42  */
43 
44 //------------------------------------------------------------------------------------
45 //------------------------------------------------------------------------------------
46 // includes
47 // system
48 #include "TimeString.hpp"
49 #include "GPSWeekSecond.hpp"
50 
51 // GPSTk
52 // Geomatics
53 #include "DDid.hpp"
54 #include "index.hpp"
55 // DDBase
56 #include "DDBase.hpp"
57 
58 //------------------------------------------------------------------------------------
59 using namespace std;
60 using namespace gpstk;
61 using namespace StringUtils;
62 
63 //------------------------------------------------------------------------------------
64 // ElevationMask.cpp
65 double RotatedAntennaElevation(double elevation, double azimuth);
66 
67 //------------------------------------------------------------------------------------
68 // Segment structure used in deducing time table functions implemented in
69 // Timetable.cpp
70 class TTSegment {
71 public:
72    std::string site1,site2;
73    gpstk::GSatID sat;
74    int start,stop;   // starting and ending counts
75    int usestart,usestop;   // counts to actually use in timetable
76    int length;       // length (in data points)
77    double minelev;   // minimum elevation in this segment
78    double maxelev;   // maximum elevation in this segment
79 
TTSegment(void)80    TTSegment(void)
81     : start(-1), stop(-1), usestart(-1), usestop(-1),
82       length(0), minelev(0.0), maxelev(0.0)
83     {}
metric(void) const84    double metric(void) const
85    { return (double(length)/100.0 + 100.0*(minelev+maxelev)/90.0); }
86 
87    void findElev(void);
88 
89    friend ostream& operator<<(ostream& s, const TTSegment& t);
90 
91    friend bool increasingMetricSort(const TTSegment& left, const TTSegment& right);
92    friend bool decreasingMetricSort(const TTSegment& left, const TTSegment& right);
93    friend bool startSort(const TTSegment& left, const TTSegment& right);
94 };
95 
96 //------------------------------------------------------------------------------------
97 // local data
98 list<TTSegment> TimeTable;    // satellite time table
99 map<SDid,SDData> SDmap;       // map of SD data - not full single differences
100 
101 //------------------------------------------------------------------------------------
102 // prototypes -- this module only
103 int ReadTimeTable(void);
104 int ComputeBaselineTimeTable(const string& bl);
105 int TTComputeSingleDifferences(const string& bl, const double ElevLimit);
106 int TimeTableAlgorithm(list<TTSegment>& TTS, list<TTSegment>& TTab);
107 bool startSort(const TTSegment& left, const TTSegment& right);
108 bool increasingMetricSort(const TTSegment& left, const TTSegment& right);
109 bool decreasingMetricSort(const TTSegment& left, const TTSegment& right);
110 
111 //------------------------------------------------------------------------------------
112 // Find the entry in the timetable which applies to the baseline given in sdid and
113 // the time tt. Set the satellite in sdid to the reference satellite, and set the
114 // time tt to the time (in the future) when the reference will change again.
115 // return 0 on success, 1 on failure.
QueryTimeTable(SDid & sdid,CommonTime & tt)116 int QueryTimeTable(SDid& sdid, CommonTime& tt)
117 {
118 try {
119    int ntt(static_cast<int>(0.5+(tt-FirstEpoch)/CI.DataInterval));
120       // loop over the timetable, looking for a match : baseline and time
121    list<TTSegment>::iterator ttit;
122    for(ttit=TimeTable.begin(); ttit != TimeTable.end(); ttit++) {
123       if(((ttit->site1 == sdid.site1 && ttit->site2 == sdid.site2) ||
124           (ttit->site1 == sdid.site2 && ttit->site2 == sdid.site1)   ) &&
125           ttit->usestart <= ntt && ttit->usestop  >= ntt)
126       {                                                  // success
127          sdid.sat = ttit->sat;
128          tt = FirstEpoch+CI.DataInterval*ttit->usestop;
129          return 0;
130       }
131    }
132 
133    return 1;      // failure
134 }
135 catch(Exception& e) { GPSTK_RETHROW(e); }
136 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
137 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
138 }
139 
140 //------------------------------------------------------------------------------------
141 // Find the start and stop counts in the timetable which applies to the given baseline
QueryTimeTable(string baseline,int & beg,int & end)142 int QueryTimeTable(string baseline, int& beg, int& end)
143 {
144 try {
145    string site1=word(baseline,0,'-');
146    string site2=word(baseline,1,'-');
147    beg = end = -1;
148       // loop over the timetable, looking for a match in baseline
149    list<TTSegment>::iterator ttit;
150    for(ttit=TimeTable.begin(); ttit != TimeTable.end(); ttit++) {
151       if((ttit->site1 == site1 && ttit->site2 == site2) ||
152          (ttit->site1 == site2 && ttit->site2 == site1)   )
153       {                                                  // success
154          if(beg == -1 || ttit->usestart < beg) beg = ttit->usestart;
155          if(end == -1 || ttit->usestop  > end) end = ttit->usestop;
156       }
157    }
158    return 0;
159 }
160 catch(Exception& e) { GPSTK_RETHROW(e); }
161 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
162 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
163 }
164 
165 //------------------------------------------------------------------------------------
Timetable(void)166 int Timetable(void)
167 {
168 try {
169    if(CI.Verbose) oflog << "BEGIN Timetable()"
170       << " at total time " << fixed << setprecision(3)
171       << double(clock()-totaltime)/double(CLOCKS_PER_SEC) << " seconds."
172       << endl;
173 
174    int iret;
175    size_t ib;
176    list<TTSegment>::iterator ttit;
177 
178    if(CI.TimeTableFile.size() > 0) {
179       iret = ReadTimeTable();
180    }
181    else if(CI.RefSat.id != -1) {         // user says use this sat only
182       // loop over baselines
183       for(ib=0; ib<Baselines.size(); ib++) {
184          TTSegment ts;
185          ts.site1 = word(Baselines[ib],0,'-');
186          ts.site2 = word(Baselines[ib],1,'-');
187          ts.sat = CI.RefSat;
188          ts.start = ts.usestart = 0;
189          ts.stop = ts.usestop = maxCount;
190          ts.minelev = ts.maxelev = 0.0;
191          ts.length = ts.stop - ts.start + 1;
192          TimeTable.push_back(ts);
193          iret = 0;
194       }
195    }
196    else {
197       // loop over baselines
198       for(ib=0; ib<Baselines.size(); ib++) {
199          iret = ComputeBaselineTimeTable(Baselines[ib]);
200          if(iret) break;
201       }  // end loop over baselines
202    }
203 
204    if(iret == 0) {
205       // write out timetable to log
206       // REF site site sat week use_start use_stop data_start data_stop
207       CommonTime tt;
208       GSatID sat;
209       oflog << "Here is the time table (" << TimeTable.size() << ")" << endl;
210       if(CI.Screen)
211          cout << "Time table (" << TimeTable.size() << "):" << endl;
212       oflog << "# " << Title << endl;
213       oflog << "# REF site site sat week use_start use_stop data_start data_stop\n";
214       if(CI.Screen)
215          cout << "# REF site site sat week use_start use_stop data_start data_stop\n";
216       for(ttit=TimeTable.begin(); ttit != TimeTable.end(); ttit++) {
217          oflog << "REF " << ttit->site1 << " " << ttit->site2 << " " << ttit->sat;
218          if(CI.Screen)
219             cout << "REF " << ttit->site1 << " " << ttit->site2 << " " << ttit->sat;
220          tt = FirstEpoch + CI.DataInterval * ttit->usestart;
221          oflog << printTime(tt," %4F %10.3g");        // TD week rollover!
222          if(CI.Screen)
223             cout << printTime(tt," %4F %10.3g");        // TD week rollover!
224          tt = FirstEpoch + CI.DataInterval * ttit->usestop;
225          oflog << printTime(tt," %10.3g");
226          if(CI.Screen)
227             cout << printTime(tt," %10.3g");
228          tt = FirstEpoch + CI.DataInterval * ttit->start;
229          oflog << printTime(tt," %10.3g");
230          if(CI.Screen)
231             cout << printTime(tt," %10.3g");
232          tt = FirstEpoch + CI.DataInterval * ttit->stop;
233          oflog << printTime(tt," %10.3g");
234          if(CI.Screen)
235             cout << printTime(tt," %10.3g");
236          // TD? ttit->minelev, ttit->maxelev, ttit->length, ttit->metric()
237          oflog << " " << fixed << setw(4) << setprecision(1) << ttit->minelev;
238          if(CI.Screen)
239             cout << " " << fixed << setw(4) << setprecision(1) << ttit->minelev;
240          oflog << " " << fixed << setw(4) << setprecision(1) << ttit->maxelev;
241          if(CI.Screen)
242             cout << " " << fixed << setw(4) << setprecision(1) << ttit->maxelev;
243          // write the number of counts for this ref
244          oflog << " " << setw(5) << ttit->length;
245          if(CI.Screen)
246             cout << " " << setw(5) << ttit->length;
247          oflog << endl;
248          if(CI.Screen)
249             cout << endl;
250 
251          // for next time
252          sat = ttit->sat;
253       }
254       oflog << "End of time table." << endl;
255       if(CI.Screen)
256          cout << "End of time table." << endl;
257    }
258 
259    return iret;
260 
261    return 0;
262 }
263 catch(Exception& e) { GPSTK_RETHROW(e); }
264 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
265 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
266 }   // end Timetable()
267 
268 //------------------------------------------------------------------------------------
269 // Input the time table from a file
ReadTimeTable(void)270 int ReadTimeTable(void)
271 {
272 try {
273    int week;
274    double sow;
275    string line;
276    CommonTime tt;
277 
278    // open an input file for all timetables
279    if(CI.Debug) oflog << "Try to open time table file " << CI.TimeTableFile << endl;
280    ifstream ttifs(CI.TimeTableFile.c_str());
281    if(!ttifs) {
282       cerr << "Failed to open input time table file " << CI.TimeTableFile << endl;
283       return -3;
284    }
285 
286    //REF site site sat week use_start use_stop data_start data_stop
287    do {
288       getline(ttifs,line);
289       stripTrailing(line,'\r');
290       if(ttifs.eof() || !ttifs.good()) break;
291 
292       if(line.size() <= 0) continue;                              // skip blank lines
293       if(line[0] == '#') continue;                                // skip comments
294       if(numWords(line) < 9) continue; // TD msg?    // skip bad lines
295       if(words(line,0,1) != string("REF")) continue; // only REF lines
296       TTSegment ts;
297       ts.site1 = words(line,1,1);
298       ts.site2 = words(line,2,1);
299       ts.sat.fromString(words(line,3,1));
300 
301       week = asInt(words(line,4,1));
302       sow = asInt(words(line,5,1));
303       tt=GPSWeekSecond(week,sow);           // TD handle week rollover
304       ts.usestart = int(0.5+(tt-FirstEpoch)/CI.DataInterval);
305 
306       sow = asInt(words(line,6,1));
307       tt=GPSWeekSecond(week,sow);
308       ts.usestop = int(0.5+(tt-FirstEpoch)/CI.DataInterval);
309 
310       sow = asInt(words(line,7,1));
311       tt=GPSWeekSecond(week,sow);
312       ts.start = int(0.5+(tt-FirstEpoch)/CI.DataInterval);
313 
314       sow = asInt(words(line,8,1));
315       tt=GPSWeekSecond(week,sow);
316       ts.stop = int(0.5+(tt-FirstEpoch)/CI.DataInterval);
317 
318       //ts.minelev = ts.maxelev = 0.0;
319       ts.length = ts.stop - ts.start + 1;
320       ts.findElev();
321       TimeTable.push_back(ts);
322 
323    } while(1);
324    // close the output timetable file
325    ttifs.close();
326 
327    oflog << "Read time table from file " << CI.TimeTableFile << endl;
328 
329    return 0;
330 }
331 catch(Exception& e) { GPSTK_RETHROW(e); }
332 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
333 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
334 }
335 
336 //------------------------------------------------------------------------------------
ComputeBaselineTimeTable(const string & bl)337 int ComputeBaselineTimeTable(const string& bl)
338 {
339 try {
340    int j;
341    size_t i;
342    map<SDid,SDData>::const_iterator it;
343    list<TTSegment> SegList;
344 
345    SDmap.clear();
346    i = TTComputeSingleDifferences(bl,40.0);
347    if(i) return i;
348 
349    // now compute the timetable based on SDmap
350    for(it=SDmap.begin(); it != SDmap.end(); it++) {
351       TTSegment ts;
352       ts.site1 = it->first.site1;
353       ts.site2 = it->first.site2;
354       ts.sat = it->first.sat;
355       ts.start = it->second.count[0];
356       ts.minelev = ts.maxelev = 0.0;
357       for(i=0; i<it->second.count.size()-1; i++) {
358          j = it->second.count.at(i+1) - it->second.count.at(i);
359          if(j > 1) {
360             TTSegment tts;
361             tts = ts;
362             tts.stop = it->second.count.at(i);
363             tts.length = tts.stop - tts.start + 1;
364             tts.findElev();
365             SegList.push_back(tts);
366             ts.start = it->second.count.at(i+1);
367          }
368       }
369       ts.stop = it->second.count[it->second.count.size()-1];
370       ts.length = ts.stop - ts.start + 1;
371       ts.findElev();
372       SegList.push_back(ts);
373    }
374 
375    if(SegList.size() == 0) return -2;
376 
377    // figure out the time table from the list of segments
378    list<TTSegment> TTable;
379    i = TimeTableAlgorithm(SegList, TTable);
380    if(i) return i;
381 
382    // add this timetable to the master timetable.
383    list<TTSegment>::iterator ttit;
384    for(ttit=TTable.begin(); ttit != TTable.end(); ttit++)
385       TimeTable.push_back(*ttit);
386 
387    return 0;
388 }
389 catch(Exception& e) { GPSTK_RETHROW(e); }
390 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
391 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
392 }
393 
394 //------------------------------------------------------------------------------------
TTComputeSingleDifferences(const string & bl,const double ElevLimit)395 int TTComputeSingleDifferences(const string& bl, const double ElevLimit)
396 {
397 try {
398    size_t i,j;
399    int k;
400    const size_t MinSize = 10;
401    double elevi,elevj;
402    GSatID sat;
403    map<GSatID,RawData>::const_iterator it,jt;
404    map<SDid,SDData>::const_iterator kt;
405    ofstream rawofs;
406    format f62(6,2),f133(13,3);
407 
408    // loop over buffered raw data of sats common to both
409    string est=word(bl,0,'-');
410    string fix=word(bl,1,'-');
411 
412    for(it=Stations[est].RawDataBuffers.begin();
413        it != Stations[est].RawDataBuffers.end(); it++) {
414 
415       // consider each satellite
416       sat = it->first;
417       if(CI.Verbose) oflog << "Single difference " << est << " " << fix << " " << sat;
418 
419       // is sat also found at fixed site?
420       jt = Stations[fix].RawDataBuffers.find(sat);
421       if(jt == Stations[fix].RawDataBuffers.end()) {
422          if(CI.Verbose) oflog << " not found on both sites" << endl;
423          continue;
424       }
425 
426       if(CI.Verbose) oflog << " (raw buffers size: " << it->second.count.size()
427          << " " << jt->second.count.size() << ")";
428 
429       // is there enough data in the buffers?
430       if(it->second.count.size() < MinSize || jt->second.count.size() < MinSize) {
431          if(CI.Verbose) oflog << " raw buffers size too small: "
432             << it->second.count.size() << " and " << jt->second.count.size() << endl;
433          continue;
434       }
435 
436       // compute continuous segments of SD data
437       // sdd.count is the intersection of the two count vectors
438       SDid sdid(fix,est,sat);
439       SDData sdd;
440       sdd.elevmin = 100.0;
441       sdd.elevmax = -1.0;
442       i = j = 0;
443       do {
444          if(it->second.count[i] == jt->second.count[j]) {
445             elevi = RotatedAntennaElevation(it->second.elev[i],it->second.az[i]);
446             elevj = RotatedAntennaElevation(jt->second.elev[j],jt->second.az[j]);
447             if(elevi >= ElevLimit && elevj >= ElevLimit) {
448                sdd.count.push_back(it->second.count[i]);
449                if(elevi < sdd.elevmin) sdd.elevmin = elevi;
450                if(elevi > sdd.elevmax) sdd.elevmax = elevi;
451             }
452             i++;
453             j++;
454          }
455          else if(it->second.count[i] < jt->second.count[j]) {
456             i++;
457          }
458          else {
459             j++;
460          }
461       } while( i < it->second.count.size() &&
462                j < jt->second.count.size() );
463 
464       // TD ?
465       if(sdd.count.size() < MinSize) {
466          if(CI.Verbose) oflog << " size is too small ("
467             << sdd.count.size() << ")" << endl;
468          continue;
469       }
470 
471       // save it in the map
472       SDmap[sdid] = sdd;
473 
474       if(CI.Verbose) oflog << endl;
475 
476    }  // end loop over raw buffered data common to both sites
477 
478    // write out a summary of single differences
479    oflog << "Single differences summary :" << endl;
480    for(k=1,kt=SDmap.begin(); kt != SDmap.end(); kt++,k++) {
481       oflog << " " << setw(2) << k << " " << kt->first
482          << " " << setw(5) << kt->second.count.size()
483          << " " << setw(5) << kt->second.count.at(0)
484          << " - " << setw(5) << kt->second.count.at(kt->second.count.size()-1);
485          // elevation
486       oflog << " elev: "
487          << fixed << setw(4) << setprecision(1) << kt->second.elevmin
488          << " - " << setw(4) << setprecision(1) << kt->second.elevmax;
489          // gaps - (count : number of pts)
490       for(i=0; i<kt->second.count.size()-1; i++) {
491          j = kt->second.count.at(i+1) - kt->second.count.at(i);
492          if(j > 1)
493             oflog << " (" << kt->second.count.at(i)+1 << ":" << j-1 << ")";
494       }
495       oflog << endl;
496    }
497 
498    if(SDmap.size() == 0) {
499       oflog << "Returning error code -1 from TTComputeSingleDifferences()" << endl;
500       return -1;
501    }
502 
503    return 0;
504 }
505 catch(Exception& e) { GPSTK_RETHROW(e); }
506 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
507 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
508 }
509 
510 //------------------------------------------------------------------------------------
511 // preprocess the segment list - get first and last counts
TimeTableAlgorithm(list<TTSegment> & TTS,list<TTSegment> & TTab)512 int TimeTableAlgorithm(list<TTSegment>& TTS, list<TTSegment>& TTab)
513 {
514 try {
515    bool keep;
516    int i,beg=0,end;
517    int begcount,endcount;
518    list<TTSegment>::iterator ttit,ttjt;
519    typedef pair<int,int> seg;
520    list<seg> Segs;
521    list<seg>::iterator lit,ljt;
522 
523    // 0 sort list in order of decreasing metric()
524    // 0.5 delete very small segments
525    // 0.6 run through the list, finding the smallest begin, and largest end, counts;
526    // call these the begin and end counts.
527    // 1. run through the sorted list, starting at largest metric(), and pick out
528    // first segments which have the begin and/or end counts; add these to TTab
529    // and erase from TTS.
530    // 2. run through TTS again, starting at the largest metric(); if a segment
531    // includes some counts that have not been covered before, than add this
532    // to TTab and erase from TTS. Quit when either the entire range from
533    // begcount to endcount is covered, a given minimum metric() is reached,
534    // or when the end of TTS is reached.
535    // 3. if gaps remain in the coverage, these are real gaps in the data and
536    // the estimation will have to reset.
537    // 4. sort TTab in increasing order. Run through TTab looking for
538    // segments which can be removed without generating gaps; remove these.
539 
540    // 0. sort in reverse order (largest metric() first)
541    // [ list has its own sort sort(TTS.rbegin(),TTS.rend()); ]
542    TTS.sort(decreasingMetricSort);
543 
544    // 0.5 delete very small segments and output the sorted list
545    // 0.6 find begcount and endcount (after deletion)
546    begcount = endcount = -1;
547    oflog << "Here is the sorted list of segments:" << endl;
548    for(i=1,ttit=TTS.begin(); ttit != TTS.end(); i++) {
549       oflog << " " << setw(4) << i << *ttit;
550       if(ttit->length < 10) {
551          oflog << " -- delete this segment: too small";
552          ttit = TTS.erase(ttit); // ttit now points to next seg
553       }
554       else {
555          if(begcount < 0 || ttit->start < begcount)
556             begcount = ttit->start;
557          if(endcount < 0 || ttit->stop > endcount)
558             endcount = ttit->stop;
559          ttit++;
560       }
561       oflog << endl;
562    }
563    oflog << "End the sorted list; limits : " << begcount << " - " << endcount << endl;
564 
565    // 1.find the begin point
566    for(ttit=TTS.begin(); ttit != TTS.end(); ttit++) {
567       if(ttit->start == begcount) {
568          oflog << "Found the begin time: " << *ttit << endl;
569          TTab.push_back(*ttit);
570          beg = ttit->stop;
571         TTS.erase(ttit);
572          break;
573       }
574    }
575 
576    if(beg == endcount) {
577       // one segment covers it all - done!
578       oflog << "One segment covers it all!" << endl;
579       end = endcount;
580    }
581    else {
582       // find the end point
583       for(ttit=TTS.begin(); ttit != TTS.end(); ttit++) {
584          if(ttit->stop == endcount) {
585             oflog << "Found the   end time: " << *ttit << endl;
586             TTab.push_back(*ttit);
587             end = ttit->start;
588             TTS.erase(ttit);
589             break;
590          }
591       }
592 
593       if(TTab.size() != 2) {
594          // error, we didn't find the beg and end -- throw?
595          return -2;
596       }
597    }
598 
599    // start list of segs with the ones that contain endpoints
600    ttit = TTab.begin();
601    Segs.push_back(make_pair(ttit->start,ttit->stop));
602    ttit++;
603    if(ttit != TTab.end())
604       Segs.push_back(make_pair(ttit->start,ttit->stop));
605 
606    if(beg >= end) { // two segments cover it all
607       if(Segs.size() > 1) {            // TD unsure if the logic is wrong here...
608          ljt = lit = Segs.begin();
609          ljt++;
610          lit->second = ljt->second;
611          if(CI.Debug) oflog << "Two segments cover it all: erase seg ("
612             << ljt->first << "-" << ljt->second << ")" << endl;
613          Segs.erase(ljt);
614       }
615    }
616    else {
617       // 2.
618       // start with
619       // |======1st Seg======|            gap                 |=====last Seg======|
620       //
621       // in general, new segs can be added, so Segs looks like this:
622       // |===1st Seg===|    gap       |===2nd Seg===|    gap       |===last Seg===|
623       //
624       // consider 8 cases of new segments from TTS:
625       // 1.   |--------------|                               covers end of seg
626       // 2.               |-------|                          lies entirely w/in gap
627       // 3.                     |--------|                   covers beg of seg
628       // 4.         |--------------------|                   covers entire gap
629       // 5.                      |----------------------|    covers entire seg
630       // 6. covers seg and gap   |-------------------------------------|
631       // 7.         |-------------------------------------|  covers gap and seg
632       // 8.                               |-----|            lies entirely w/in seg
633       //
634       // Here is the algorithm:
635       // for each new segment extending from b to e
636       // for each i in list of segments in list (extending bi to ei) {
637       // if(b > ei) skip to the next i
638       // if(e > ei) {                              // b <= ei and e > ei
639       //    mod seg i so that ei -> e              // case 1,4,7
640       //    if(b < bi) mod seg i so that bi -> b   // case 5,6
641       //    while (e >= bj) where j > i,
642       //       merge segments i and j and delete j // case 4,6,7
643       //    keep this segment
644       // }
645       // else {                                    // b <= ei and e <= ei
646       //    if(e >= bi) {
647       //       if(b < bi) {
648       //          mod segment i so bi -> b         // case 3
649       //          keep this segment
650       //       }
651       //       //else { ignore this segment }      // case 8
652       //    }
653       //    else {
654       //       make a new segment (b,e),
655       //          and insert it before segment i   // case 2
656       //       keep this segment
657       //    }
658       // }
659       // } // end of loop over segments i
660       // if(keep) add this segment to the time table
661       //
662       // loop over all segments, in decreasing order of metric()
663       for(i=1,ttit=TTS.begin(); ttit != TTS.end(); i++,ttit++) { // i temp
664 
665          if(CI.Debug) { // temp
666             oflog << "Here is the current time table (" << TTab.size() << ")"
667                << endl;
668             for(ttjt=TTab.begin(); ttjt != TTab.end(); ttjt++)
669                oflog << " " << *ttjt << endl;
670          }
671 
672          if(CI.Debug) {
673             oflog << "and here is the seg list";
674             for(lit=Segs.begin(); lit != Segs.end(); lit++)
675                oflog << " (" << lit->first << "-" << lit->second << ")";
676             oflog << endl;
677          }
678 
679          // done if one segment covers all
680          lit = Segs.begin();
681          if(Segs.size() == 1 && lit->first == begcount && lit->second == endcount)
682             break;
683 
684          // keep this? you don't want metric to become very small -> failure
685          if(ttit->metric() <= 100.0) break;        // TD input param
686 
687          beg = ttit->start;
688          end = ttit->stop;
689          if(CI.Debug) oflog << "consider new segment ("
690             << beg << "-" << end << ")" << endl;
691 
692          // loop over the segs
693          keep = false;
694          lit = Segs.begin();
695          while(lit != Segs.end()) {
696             if(beg > lit->second) {
697                if(CI.Debug) oflog << " skip seg ("
698                   << lit->first << "-" << lit->second << ")" << endl;
699                lit++;
700                continue;
701             }
702             if(end > lit->second) {
703                if(CI.Debug) oflog << " mod 1 seg ("
704                   << lit->first << "-" << lit->second << ")";
705                lit->second = end;
706                if(beg < lit->first) lit->first=beg;
707                if(CI.Debug) oflog << " to ("
708                   << lit->first << "-" << lit->second << ")" << endl;
709                ljt = lit;
710                while(++ljt != Segs.end() && end >= ljt->first) {
711                   // merge i and j
712                   if(CI.Debug) oflog << " merge segs ("
713                      << lit->first << "-" << lit->second << ") and ("
714                      << ljt->first << "-" << ljt->second << ")";
715                   lit->second = ljt->second;
716                   if(CI.Debug) oflog << " and erase seg ("
717                      << ljt->first << "-" << ljt->second << ")" << endl;
718                   Segs.erase(ljt);
719                   ljt = lit;
720                }
721                keep = true;
722             }
723             else {
724                if(end >= lit->first) {
725                   if(beg < lit->first) {
726                      if(CI.Debug) oflog << " mod 2 seg ("
727                         << lit->first << "-" << lit->second << ")";
728                      lit->first = beg;
729                      keep = true;
730                      if(CI.Debug) oflog << " to ("
731                         << lit->first << "-" << lit->second << ")" << endl;
732                   }
733                   //else { keep=false; ignore -- this seg has nothing new }
734                }
735                else {
736                   seg newseg(beg,end);
737                   if(CI.Debug) oflog << " add seg ("
738                      << newseg.first << "-" << newseg.second << ")" << endl;
739                   Segs.insert(lit,newseg);
740                   keep = true;
741                }
742             }
743             break;
744          }  // end while loop over segs
745 
746          if(keep) {
747             TTab.push_back(*ttit);
748             TTab.sort(startSort);       // temp
749          }
750 
751          if(CI.Debug) if(i > 100) break;      // temp
752 
753       }  // end for loop over segments TTS
754 
755    }  // end if(initial gap is non-zero)
756 
757    // 3. are there gaps?
758    if(Segs.size() != 1) {
759       oflog << "There are real gaps in the data; segments with data:" << endl;
760       for(lit=Segs.begin(); lit != Segs.end(); lit++)
761          oflog << " (" << lit->first << "-" << lit->second << ")";
762       oflog << endl;
763    }
764    else oflog << "There are no gaps in the data" << endl;
765 
766    // sort the timetable
767    TTab.sort(startSort);
768 
769    // TD 4. edit TTab, removing segments that do not create gaps
770 
771    // decide on actual transition times
772    for(ttit=TTab.begin(); ttit != TTab.end(); ttit++) {
773       //if(CI.Verbose) oflog << " " << *ttit << endl;
774 
775       // compute the count at which to switch
776       if(ttit == TTab.begin()) {
777          ttit->usestart = ttit->start;    // usestart = start for first segment
778          ttjt = ttit;                     // initialize ttjt
779       }
780       else if(ttjt->stop > ttit->start) { // if there is overlap, switch at midpoint
781          ttit->usestart = (ttjt->stop + ttit->start)/2;
782       }
783       else {
784          ttit->usestart = ttit->start;    // there is a gap
785       }
786       ttit->usestop = ttit->stop;         // change later, except for last segment
787       if(ttit != TTab.begin()) {
788          ttjt->usestop = ttit->usestart;  // count at the switch point
789          ttjt++;                          // ttjt lags behind ttit by 1
790       }
791    }
792 
793    return 0;
794 }
795 catch(Exception& e) { GPSTK_RETHROW(e); }
796 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
797 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
798 }
799 
800 //------------------------------------------------------------------------------------
findElev(void)801 void TTSegment::findElev(void)
802 {
803    int i,k;
804    double elevi;
805    RawData& rd=Stations[site1].RawDataBuffers[sat];
806    minelev = 99.0;
807    maxelev = -1.0;
808    k = index(rd.count,start);
809    if(k == -1) return;
810    for(i=k; i<k+length; i++) {
811       elevi = RotatedAntennaElevation(rd.elev.at(i),rd.az.at(i));
812       if(elevi > maxelev) maxelev = elevi;
813       if(elevi < minelev) minelev = elevi;
814    }
815 }
816 
817 //------------------------------------------------------------------------------------
818 // friends of TTSegment, defined there
startSort(const TTSegment & left,const TTSegment & right)819 bool startSort(const TTSegment& left, const TTSegment& right)
820 { return (left.start < right.start); }
821 
increasingMetricSort(const TTSegment & left,const TTSegment & right)822 bool increasingMetricSort(const TTSegment& left, const TTSegment& right)
823 { return (left.metric() < right.metric()); }
824 
decreasingMetricSort(const TTSegment & left,const TTSegment & right)825 bool decreasingMetricSort(const TTSegment& left, const TTSegment& right)
826 { return (left.metric() > right.metric()); }
827 
828 //------------------------------------------------------------------------------------
operator <<(ostream & os,const TTSegment & t)829 ostream& operator<<(ostream& os, const TTSegment& t)
830 {
831 try {
832    os << " " << t.site1
833       << " " << t.site2
834       << " " << t.sat
835       << " " << setw(5) << t.length
836       << " " << setw(5) << t.start
837       << " - " << setw(5) << t.stop
838       << " " << fixed << setw(4) << setprecision(1) << t.minelev
839       << " - " << fixed << setw(4) << setprecision(1) << t.maxelev
840       << " " << setw(7) << setprecision(2) << t.metric();
841    return os;
842 }
843 catch(Exception& e) { GPSTK_RETHROW(e); }
844 catch(std::exception& e) { Exception E("std except: "+string(e.what())); GPSTK_THROW(E); }
845 catch(...) { Exception e("Unknown exception"); GPSTK_THROW(e); }
846 }
847 
848 //------------------------------------------------------------------------------------
849 //------------------------------------------------------------------------------------
850