-
Notifications
You must be signed in to change notification settings - Fork 127
/
defs.h
1064 lines (919 loc) · 35.4 KB
/
defs.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
Copyright (C) 2002-2014 Robert Lipe, [email protected]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DEFS_H_INCLUDED_
#define DEFS_H_INCLUDED_
#include <cmath> // for nan
#include <cstddef> // for NULL, nullptr_t, size_t
#include <cstdint> // for int32_t, uint32_t
#include <cstdio> // for NULL, fprintf, FILE, stdout
#include <ctime> // for time_t
#include <numbers> // for inv_pi, pi
#include <optional> // for optional
#include <utility> // for move
#include <QByteArray> // for QByteArray
#include <QDate> // for QDate
#include <QTime> // for QTime
#include <QDateTime> // for QDateTime
#include <QDebug> // for QDebug
#include <QList> // for QList, QList<>::const_iterator, QList<>::const_reverse_iterator, QList<>::count, QList<>::reverse_iterator
#include <QString> // for QString
#include <QStringView> // for QStringView
#include <QTextCodec> // for QTextCodec
#ifdef LIGHTWEIGHT_TIMEZONES_SUPPORTED
#include <QTimeZone> // for QTimeZone
#endif
#include <Qt> // for CaseInsensitive
#include <QtGlobal> // for QForeachContainer, qMakeForeachContainer, foreach, qint64
#include "geocache.h" // for Geocache
#include "formspec.h" // for FormatSpecificData
#include "inifile.h" // for inifile_t
#include "option.h"
#include "session.h" // for session_t
#include "src/core/datetime.h" // for DateTime
#define gbLogCStr(qstr) qUtf8Printable(qstr)
#define CSTR(qstr) ((qstr).toUtf8().constData())
#define CSTRc(qstr) ((qstr).toLatin1().constData())
/*
* The constants marked "exact in decimal notation" may be more accurately
* converted to doubles when we don't ask the compiler to do any multiplication.
* e.g. kMetersPerMile = 0.0254 * 12.0 * 5280.0; might have a larger error than
* kMetersPerMile = 1609.344;
* Historically we have had some problematic test cases where this mattered.
* It is a better idea to use test cases that aren't so demanding.
*/
constexpr double kMetersPerFoot = 0.3048; /* exact in decimal notation */
constexpr double kFeetPerMeter = 1.0 / kMetersPerFoot;
constexpr double kMetersPerMile = 1609.344; /* exact in decimal notation */
constexpr double kMilesPerMeter = 1.0 / kMetersPerMile;
constexpr double kKilometersPerMile = 1.609344; /* exact in decimal notation */
constexpr double kMilesPerKilometer = 1.0 / kKilometersPerMile;
constexpr double kMetersPerNMile = 1852.0; /* exact in decimal notation */
constexpr double kNMilesPerMeter = 1.0 / kMetersPerNMile;
constexpr double FEET_TO_METERS(double feetsies) { return feetsies * kMetersPerFoot;}
constexpr double METERS_TO_FEET(double meetsies) { return meetsies * kFeetPerMeter;}
constexpr double NMILES_TO_METERS(double a) { return a * kMetersPerNMile;} /* nautical miles */
constexpr double METERS_TO_NMILES(double a) { return a * kNMilesPerMeter;}
constexpr double MILES_TO_METERS(double a) { return a * kMetersPerMile;}
constexpr double METERS_TO_MILES(double a) { return a * kMilesPerMeter;}
constexpr double FATHOMS_TO_METERS(double a) { return a * 1.8288;}
constexpr double CELSIUS_TO_FAHRENHEIT(double a) { return (a * 1.8) + 32.0;}
constexpr double FAHRENHEIT_TO_CELSIUS(double a) { return (a - 32.0) / 1.8;}
constexpr long SECONDS_PER_HOUR = 60L * 60;
constexpr long SECONDS_PER_DAY = 24L * 60 * 60;
constexpr double kKPHPerMPS = SECONDS_PER_HOUR / 1000.0;
constexpr double kMPSPerKPH = 1.0 / kKPHPerMPS;
constexpr double kMPHPerMPS = kMilesPerMeter * SECONDS_PER_HOUR;
constexpr double kMPSPerMPH = 1.0 / kMPHPerMPS;
constexpr double kKnotsPerMPS = kNMilesPerMeter * SECONDS_PER_HOUR;
constexpr double kMPSPerKnot = 1.0 / kKnotsPerMPS;
/* meters/second to kilometers/hour */
constexpr double MPS_TO_KPH(double a) { return a * kKPHPerMPS;}
/* meters/second to miles/hour */
constexpr double MPS_TO_MPH(double a) { return a * kMPHPerMPS;}
/* meters/second to knots(nautical miles/hour) */
constexpr double MPS_TO_KNOTS(double a) { return a * kKnotsPerMPS;}
/* kilometers/hour to meters/second */
constexpr double KPH_TO_MPS(double a) { return a * kMPSPerKPH;}
/* miles/hour to meters/second */
constexpr double MPH_TO_MPS(double a) { return a * kMPSPerMPH;}
/* knots(nautical miles/hour) to meters/second */
constexpr double KNOTS_TO_MPS(double a) {return a * kMPSPerKnot;}
/* Degrees to radians */
constexpr double kDegreesPerRadian = 180.0 * std::numbers::inv_pi;
constexpr double DEG(double x) { return x * kDegreesPerRadian; }
/* Radians to degrees */
constexpr double kRadiansPerDegree = 1.0 / kDegreesPerRadian;
constexpr double RAD(double x) { return x * kRadiansPerDegree; }
constexpr int kDatumOSGB36 = 86; // GPS_Lookup_Datum_Index("OSGB36")
constexpr int kDatumWGS84 = 118; // GPS_Lookup_Datum_Index("WGS 84")
/*
* Common definitions. There should be no protocol or file-specific
* data in this file.
*/
/*
* Define globally on which kind of data gpsbabel is working.
* Important for "file types" that are essentially a communication
* protocol for a receiver, like the Magellan serial data.
*/
enum gpsdata_type {
unknown_gpsdata = 0,
trkdata = 1,
wptdata,
rtedata,
posndata
};
#define NOTHINGMASK 0U
#define WPTDATAMASK 1U
#define TRKDATAMASK 2U
#define RTEDATAMASK 4U
#define POSNDATAMASK 8U
/* mask objective testing */
#define doing_nothing (global_opts.masked_objective == NOTHINGMASK)
#define doing_wpts ((global_opts.masked_objective & WPTDATAMASK) == WPTDATAMASK)
#define doing_trks ((global_opts.masked_objective & TRKDATAMASK) == TRKDATAMASK)
#define doing_rtes ((global_opts.masked_objective & RTEDATAMASK) == RTEDATAMASK)
#define doing_posn ((global_opts.masked_objective & POSNDATAMASK) == POSNDATAMASK)
struct global_options {
int debug_level;
gpsdata_type objective;
unsigned int masked_objective;
int verbose_status; /* set by GUI wrappers for status */
inifile_t* inifile;
bool synthesize_shortnames;
bool smart_icons;
bool smart_names;
};
extern global_options global_opts;
extern const char gpsbabel_version[];
extern time_t gpsbabel_time; /* gpsbabel startup-time; initialized in main.c with current_time(), ! ZERO within testo ! */
enum fix_type {
fix_unknown=-1,
fix_none=0,
fix_2d=1,
fix_3d,
fix_dgps,
fix_pps
};
class gb_color
{
public:
int bbggrr{-1}; // 32 bit color: Blue/Green/Red. < 0 == unknown.
unsigned char opacity{255}; // 0 == transparent. 255 == opaque.
};
/*
* Structures and functions for multiple URLs per waypoint.
*/
class UrlLink
{
public:
UrlLink() = default;
UrlLink(QString url) :
url_(std::move(url))
{ }
explicit UrlLink(const char* url) :
url_(url)
{ }
UrlLink(QString url, QString url_link_text) :
url_(std::move(url)),
url_link_text_(std::move(url_link_text))
{ }
UrlLink(QString url, QString url_link_text, QString url_link_type) :
url_(std::move(url)),
url_link_text_(std::move(url_link_text)),
url_link_type_(std::move(url_link_type))
{ }
QString url_;
QString url_link_text_;
QString url_link_type_;
};
class UrlList : public QList<UrlLink>
{
public:
void AddUrlLink(const UrlLink& l)
{
push_back(l);
}
bool HasUrlLink() const
{
return !isEmpty();
}
const UrlLink& GetUrlLink() const
{
return first();
}
};
/*
* Misc bitfields inside struct waypoint;
*/
class wp_flags
{
public:
unsigned int shortname_is_synthetic:1{0};
unsigned int fmt_use:2{0}; /* lightweight "extra data" */
unsigned int is_split:1{0}; /* the waypoint represents a split */
unsigned int new_trkseg:1{0}; /* True if first in new trkseg. */
unsigned int marked_for_deletion:1{0}; /* True if schedulded for deletion. */
};
/*
* Bounding box information.
*/
struct bounds {
double max_lat;
double max_lon;
double max_alt; /* unknown_alt => invalid */
double min_lat;
double min_lon;
double min_alt; /* -unknown_alt => invalid */
};
struct PositionRad; // forward declare
struct PositionDeg
{
PositionDeg() = default;
explicit(false) inline PositionDeg(const PositionRad& posr); /* converting ctor */
PositionDeg(double latd, double lond) : latD(latd), lonD(lond) {}
double latD{std::nan("")};
double lonD{std::nan("")};
};
struct PositionRad
{
PositionRad() = default;
explicit(false) inline PositionRad(const PositionDeg& posd); /* converting ctor */
PositionRad(double latr, double lonr) : latR(latr), lonR(lonr) {}
double latR{std::nan("")};
double lonR{std::nan("")};
};
inline PositionDeg::PositionDeg(const PositionRad& posr) :
latD(posr.latR * kDegreesPerRadian),
lonD(posr.lonR * kDegreesPerRadian) {}
inline PositionRad::PositionRad(const PositionDeg& posd) :
latR(posd.latD * kRadiansPerDegree),
lonR(posd.lonD * kRadiansPerDegree) {}
/*
* This is a waypoint, as stored in the GPSR. It tries to not
* cater to any specific model or protocol. Anything that needs to
* be truncated, edited, or otherwise trimmed should be done on the
* way to the target.
*/
class Waypoint
{
private:
/* Types */
class op_flags
{
public:
bool temperature:1{false}; /* temperature field is set */
bool proximity:1{false}; /* proximity field is set */
bool course:1{false}; /* course field is set */
bool speed:1{false}; /* speed field is set */
bool geoidheight:1{false}; /* geoidheight field is set */
bool depth:1{false}; /* depth field is set */
/* !ToDo!
unsigned int altitude:1{false}; /+ altitude field is set +/
... and hdop,pdop,vdop,fix,sat,heartrate,cadence,power,
odometer_distance
*/
};
/* Data Members */
static Geocache empty_gc_data;
double geoidheight; /* Height (in meters) of geoid (mean sea level) above WGS84 earth ellipsoid. */
/*
* The "thickness" of a waypoint; adds an element of 3D. Can be
* used to construct rudimentary polygons for, say, airspace
* definitions. The units are meters.
*/
double depth;
/*
* An alarm trigger value that can be considered to be a circle
* surrounding a waypoint (or cylinder if depth is also defined).
* The units are meters.
*/
double proximity;
float course; /* Optional: degrees true */
float speed; /* Optional: meters per second. */
float temperature; /* Degrees celsius */
op_flags opt_flags;
public:
/* Special Member Functions */
Waypoint();
~Waypoint();
Waypoint(const Waypoint& other);
Waypoint& operator=(const Waypoint& rhs);
/* Member Functions */
bool HasUrlLink() const;
const UrlLink& GetUrlLink() const;
void AddUrlLink(const UrlLink& l);
QString CreationTimeXML() const;
gpsbabel::DateTime GetCreationTime() const;
void SetCreationTime(const gpsbabel::DateTime& t);
void SetCreationTime(qint64 t, qint64 ms = 0);
Geocache* AllocGCData();
int EmptyGCData() const;
void NormalizePosition();
PositionDeg position() const {return PositionDeg(latitude, longitude);}
void SetPosition(const PositionDeg& pos)
{
latitude = pos.latD;
longitude = pos.lonD;
}
// mimic std::optional interface, but use our more space
// efficient wp_flags.
#define GEN_WAYPT_METHODS(field) \
bool field##_has_value() const \
{ \
return opt_flags.field; \
} \
decltype(field) field##_value() const \
{ \
if (!opt_flags.field) { \
throw std::bad_optional_access(); \
} \
return field; \
} \
bool field##s_equal(const Waypoint& other) const \
{ \
return (opt_flags.field && other.opt_flags.field && (field == other.field)) || \
(!opt_flags.field && !other.opt_flags.field); \
} \
decltype(field) field##_value_or(decltype(field) p) const \
{ \
return (opt_flags.field)? field : p; \
} \
void set_##field(decltype(field) p) \
{ \
field = p; \
opt_flags.field = 1; \
} \
void reset_##field() \
{ \
opt_flags.field = 0; \
}
GEN_WAYPT_METHODS(temperature)
GEN_WAYPT_METHODS(proximity)
GEN_WAYPT_METHODS(course)
GEN_WAYPT_METHODS(speed)
GEN_WAYPT_METHODS(geoidheight)
GEN_WAYPT_METHODS(depth)
#undef GEN_WAYPT_METHODS
/* Data Members */
double latitude; /* Degrees */
double longitude; /* Degrees */
double altitude; /* Meters. */
/* shortname is a waypoint name as stored in receiver. It should
* strive to be, well, short, and unique. Enforcing length and
* character restrictions is the job of the output. A typical
* minimum length for shortname is 6 characters for NMEA units,
* 8 for Magellan and 10 for Vista. These are only guidelines.
*/
QString shortname;
/*
* description is typically a human readable description of the
* waypoint. It may be used as a comment field in some receivers.
* These are probably under 40 bytes, but that's only a guideline.
*/
QString description;
/*
* notes are relatively long - over 100 characters - prose associated
* with the above. Unlike shortname and description, these are never
* used to compute anything else and are strictly "passed through".
* Few formats support this.
*/
QString notes;
UrlList urls;
QString icon_descr;
gpsbabel::DateTime creation_time;
wp_flags wpt_flags;
/* Optional dilution of precision: positional, horizontal, vertical.
* 1 <= dop <= 50
*/
float hdop;
float vdop;
float pdop;
fix_type fix; /* Optional: 3d, 2d, etc. */
int sat; /* Optional: number of sats used for fix */
unsigned char heartrate; /* Beats/min. likely to get moved to fs. */
unsigned char cadence; /* revolutions per minute */
float power; /* watts, as measured by cyclists */
float odometer_distance; /* Meters */
Geocache* gc_data;
FormatSpecificDataList fs;
const session_t* session; /* pointer to a session struct */
void* extra_data; /* Extra data added by, say, a filter. */
};
using waypt_cb = void (*)(const Waypoint*);
// TODO: Consider using composition instead of private inheritance.
class WaypointList : private QList<Waypoint*>
{
public:
void waypt_add(Waypoint* wpt); // a.k.a. append(), push_back()
void add_rte_waypt(int waypt_ct, Waypoint* wpt, bool synth, QStringView namepart, int number_digits);
// FIXME: Generally it is inefficient to use an element pointer or reference to define the element to be deleted, use iterator instead,
// and/or implement pop_back() a.k.a. removeLast(), and/or pop_front() a.k.a. removeFirst().
void waypt_del(Waypoint* wpt); // a.k.a. erase()
void del_marked_wpts();
// FIXME: Generally it is inefficient to use an element pointer or reference to define the element to be deleted, use iterator instead,
// and/or implement pop_back() a.k.a. removeLast(), and/or pop_front() a.k.a. removeFirst().
void del_rte_waypt(Waypoint* wpt);
void waypt_compute_bounds(bounds* bounds) const;
Waypoint* find_waypt_by_name(const QString& name) const;
void flush(); // a.k.a. clear()
void copy(WaypointList** dst) const;
void restore(WaypointList* src);
void swap(WaypointList& other);
template <typename Compare>
void sort(Compare cmp) {std::stable_sort(begin(), end(), cmp);}
template <typename T>
void waypt_disp_session(const session_t* se, T cb);
// Expose limited methods for portability.
// public types
using QList<Waypoint*>::const_iterator;
using QList<Waypoint*>::const_reverse_iterator;
using QList<Waypoint*>::iterator;
using QList<Waypoint*>::reverse_iterator;
// public functions
using QList<Waypoint*>::back; // a.k.a. last()
using QList<Waypoint*>::begin;
using QList<Waypoint*>::cbegin;
using QList<Waypoint*>::cend;
using QList<Waypoint*>::count; // a.k.a. size()
using QList<Waypoint*>::crbegin;
using QList<Waypoint*>::crend;
using QList<Waypoint*>::detach; // silence Qt6 foreach warnings
using QList<Waypoint*>::empty; // a.k.a. isEmpty()
using QList<Waypoint*>::end;
using QList<Waypoint*>::front; // a.k.a. first()
using QList<Waypoint*>::rbegin;
using QList<Waypoint*>::rend;
using QList<Waypoint*>::size_type;
};
void waypt_init();
//void update_common_traits(const Waypoint* wpt);
void waypt_add(Waypoint* wpt);
void waypt_del(Waypoint* wpt);
void del_marked_wpts();
int waypt_count();
void waypt_status_disp(int total_ct, int myct);
//void waypt_disp_all(waypt_cb); /* template */
//void waypt_disp_session(const session_t* se, waypt_cb cb); /* template */
void waypt_init_bounds(bounds* bounds);
bool waypt_bounds_valid(bounds* bounds);
void waypt_add_to_bounds(bounds* bounds, const Waypoint* waypointp);
void waypt_compute_bounds(bounds* bounds);
Waypoint* find_waypt_by_name(const QString& name);
void waypt_flush_all();
void waypt_deinit();
void waypt_append(WaypointList* src);
void waypt_backup(WaypointList** head_bak);
void waypt_restore(WaypointList* head_bak);
void waypt_swap(WaypointList& other);
template <typename Compare>
void waypt_sort(Compare cmp)
{
extern WaypointList* global_waypoint_list;
global_waypoint_list->sort(cmp);
}
void waypt_add_url(Waypoint* wpt, const QString& link,
const QString& url_link_text);
void waypt_add_url(Waypoint* wpt, const QString& link,
const QString& url_link_text,
const QString& url_link_type);
double gcgeodist(double lat1, double lon1, double lat2, double lon2);
double waypt_time(const Waypoint* wpt);
double waypt_distance_ex(const Waypoint* A, const Waypoint* B);
double waypt_distance(const Waypoint* A, const Waypoint* B);
double waypt_speed_ex(const Waypoint* A, const Waypoint* B);
double waypt_speed(const Waypoint* A, const Waypoint* B);
double waypt_vertical_speed(const Waypoint* A, const Waypoint* B);
double waypt_gradient(const Waypoint* A, const Waypoint* B);
double waypt_course(const Waypoint* A, const Waypoint* B);
template <typename T>
void
WaypointList::waypt_disp_session(const session_t* se, T cb)
{
int i = 0;
foreach (Waypoint* waypointp, *this) {
if ((se == nullptr) || (waypointp->session == se)) {
if (global_opts.verbose_status) {
i++;
waypt_status_disp(waypt_count(), i);
}
cb(waypointp);
}
}
if (global_opts.verbose_status) {
// Terminate the progress line from waypt_status_disp.
fprintf(stderr, "\n");
fflush(stderr);
}
}
template <typename T>
void
waypt_disp_session(const session_t* se, T cb)
{
extern WaypointList* global_waypoint_list;
global_waypoint_list->waypt_disp_session(se, cb);
}
template <typename T>
void
waypt_disp_all(T cb)
{
extern WaypointList* global_waypoint_list;
global_waypoint_list->waypt_disp_session(nullptr, cb);
}
/*
* Structure of recomputed track/route data.
*/
struct computed_trkdata {
double distance_meters{0.0};
std::optional<double> max_alt; /* Meters */
std::optional<double> min_alt; /* Meters */
std::optional<double> max_spd; /* Meters/sec */
std::optional<double> min_spd; /* Meters/sec */
std::optional<double> avg_hrt; /* Avg Heartrate */
std::optional<double> avg_cad; /* Avg Cadence */
std::optional<double> avg_pwr; /* Avg Power */
gpsbabel::DateTime start; /* Min time */
gpsbabel::DateTime end; /* Max time */
std::optional<int> min_hrt; /* Min Heartrate */
std::optional<int> max_hrt; /* Max Heartrate */
std::optional<int> max_cad; /* Max Cadence */
std::optional<float> max_pwr; /* Max Power */
};
class route_head
{
public:
WaypointList waypoint_list; /* List of child waypoints */
QString rte_name;
QString rte_desc;
UrlList rte_urls;
int rte_num;
FormatSpecificDataList fs;
gb_color line_color; /* Optional line color for rendering */
int line_width; /* in pixels (sigh). < 0 is unknown. */
const session_t* session; /* pointer to a session struct */
public:
route_head();
// the default copy constructor and assignment operator are not appropriate as we do deep copy of some members,
// and we haven't bothered to write an appropriate one.
// Catch attempts to use the default copy constructor and assignment operator.
route_head(const route_head& other) = delete;
route_head& operator=(const route_head& rhs) = delete;
~route_head();
int rte_waypt_ct() const {return waypoint_list.count();} /* # waypoints in waypoint list */
bool rte_waypt_empty() const {return waypoint_list.empty();}
};
using route_hdr = void (*)(const route_head*);
using route_trl = void (*)(const route_head*);
// TODO: Consider using composition instead of private inheritance.
class RouteList : private QList<route_head*>
{
public:
int waypt_count() const;
void add_head(route_head* rte); // a.k.a. append(), push_back()
// FIXME: Generally it is inefficient to use an element pointer or reference to define the element to be deleted, use iterator instead,
// and/or implement pop_back() a.k.a. removeLast(), and/or pop_front() a.k.a. removeFirst().
void del_head(route_head* rte); // a.k.a. erase()
// FIXME: Generally it is inefficient to use an element pointer or reference to define the insertion point, use iterator instead.
void insert_head(route_head* rte, route_head* predecessor); // a.k.a. insert
void add_wpt(route_head* rte, Waypoint* wpt, bool synth, QStringView namepart, int number_digits);
// FIXME: Generally it is inefficient to use an element pointer or reference to define the insertion point, use iterator instead.
void del_wpt(route_head* rte, Waypoint* wpt);
void del_marked_wpts(route_head* rte);
void common_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc);
void flush(); // a.k.a. clear()
void copy(RouteList** dst) const;
void restore(RouteList* src);
void swap(RouteList& other);
void swap_wpts(route_head* rte, WaypointList& other);
template <typename Compare>
void sort(Compare cmp) {std::sort(begin(), end(), cmp);}
template <typename T1, typename T2, typename T3>
void disp_all(T1 rh, T2 rt, T3 wc);
template <typename T2, typename T3>
void disp_all(std::nullptr_t /* rh */, T2 rt, T3 wc);
template <typename T1, typename T3>
void disp_all(T1 rh, std::nullptr_t /* rt */, T3 wc);
template <typename T3>
void disp_all(std::nullptr_t /* rh */, std::nullptr_t /* rt */, T3 wc);
// Only expose methods from our underlying container that won't corrupt our private data.
// Our contained element (route_head) also contains a container (waypoint_list),
// and we maintain a total count the elements in these contained containers, i.e.
// the total number of waypoints in all the routes in the RouteList.
// public types
using QList<route_head*>::const_iterator;
using QList<route_head*>::const_reverse_iterator;
using QList<route_head*>::iterator;
using QList<route_head*>::reverse_iterator;
// public functions
using QList<route_head*>::back; // a.k.a. last()
using QList<route_head*>::begin;
using QList<route_head*>::cbegin;
using QList<route_head*>::cend;
using QList<route_head*>::count; // a.k.a. size()
using QList<route_head*>::crbegin;
using QList<route_head*>::crend;
using QList<route_head*>::detach; // silence Qt6 foreach warnings
using QList<route_head*>::empty; // a.k.a. isEmpty()
using QList<route_head*>::end;
using QList<route_head*>::front; // a.k.a. first()
using QList<route_head*>::rbegin;
using QList<route_head*>::rend;
private:
int waypt_ct{0};
};
void route_init();
int route_waypt_count();
int route_count();
int track_waypt_count();
int track_count();
route_head* route_head_alloc();
void route_add_head(route_head* rte);
void route_del_head(route_head* rte);
void track_add_head(route_head* rte);
void track_del_head(route_head* rte);
void track_insert_head(route_head* rte, route_head* predecessor);
void route_add_wpt(route_head* rte, Waypoint* wpt, QStringView namepart = u"RPT", int number_digits = 3);
void track_add_wpt(route_head* rte, Waypoint* wpt, QStringView namepart = u"RPT", int number_digits = 3);
void route_del_wpt(route_head* rte, Waypoint* wpt);
void track_del_wpt(route_head* rte, Waypoint* wpt);
void route_del_marked_wpts(route_head* rte);
void track_del_marked_wpts(route_head* rte);
void route_swap_wpts(route_head* rte, WaypointList& other);
void track_swap_wpts(route_head* rte, WaypointList& other);
//void route_disp(const route_head* rte, waypt_cb); /* template */
void route_disp(const route_head* rte, std::nullptr_t /* waypt_cb */); /* override to catch nullptr */
//void route_disp_all(route_hdr, route_trl, waypt_cb); /* template */
//void track_disp_all(route_hdr, route_trl, waypt_cb); /* template */
void route_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc);
void track_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc);
void route_flush_all_routes();
void route_flush_all_tracks();
void route_deinit();
void route_append(const RouteList* src);
void track_append(const RouteList* src);
void route_backup(RouteList** head_bak);
void route_restore(RouteList* head_bak);
void route_swap(RouteList& other);
template <typename Compare>
void route_sort(Compare cmp)
{
extern RouteList* global_route_list;
global_route_list->sort(cmp);
}
void track_backup(RouteList** head_bak);
void track_restore(RouteList* head_bak);
void track_swap(RouteList& other);
template <typename Compare>
void track_sort(Compare cmp)
{
extern RouteList* global_track_list;
global_track_list->sort(cmp);
}
computed_trkdata track_recompute(const route_head* trk);
template <typename T>
void
route_disp(const route_head* rh, T cb)
{
// cb != nullptr, caught with an overload of route_disp
foreach (const Waypoint* waypointp, rh->waypoint_list) {
cb(waypointp);
}
}
template <typename T1, typename T2, typename T3>
void
RouteList::disp_all(T1 rh, T2 rt, T3 wc)
{
foreach (const route_head* rhp, *this) {
// rh != nullptr, caught with an overload of common_disp_all
rh(rhp);
route_disp(rhp, wc);
// rt != nullptr, caught with an overload of common_disp_all
rt(rhp);
}
}
template <typename T2, typename T3>
void
RouteList::disp_all(std::nullptr_t /* rh */, T2 rt, T3 wc)
{
foreach (const route_head* rhp, *this) {
// rh == nullptr
route_disp(rhp, wc);
// rt != nullptr, caught with an overload of common_disp_all
rt(rhp);
}
}
template <typename T1, typename T3>
void
RouteList::disp_all(T1 rh, std::nullptr_t /* rt */, T3 wc)
{
foreach (const route_head* rhp, *this) {
// rh != nullptr, caught with an overload of common_disp_all
rh(rhp);
route_disp(rhp, wc);
// rt == nullptr
}
}
template <typename T3>
void
RouteList::disp_all(std::nullptr_t /* rh */, std::nullptr_t /* rt */, T3 wc)
{
foreach (const route_head* rhp, *this) {
// rh == nullptr
route_disp(rhp, wc);
// rt == nullptr
}
}
template <typename T1, typename T2, typename T3>
void
route_disp_all(T1 rh, T2 rt, T3 wc)
{
extern RouteList* global_route_list;
global_route_list->disp_all(rh, rt, wc);
}
template <typename T1, typename T2, typename T3>
void
track_disp_all(T1 rh, T2 rt, T3 wc)
{
extern RouteList* global_track_list;
global_track_list->disp_all(rh, rt, wc);
}
struct posn_status {
volatile int request_terminate;
};
extern posn_status tracking_status;
#define ARGTYPE_UNKNOWN 0x00000000U
#define ARGTYPE_INT 0x00000001U
#define ARGTYPE_FLOAT 0x00000002U
#define ARGTYPE_STRING 0x00000003U
#define ARGTYPE_BOOL 0x00000004U
#define ARGTYPE_FILE 0x00000005U
#define ARGTYPE_OUTFILE 0x00000006U
/* REQUIRED means that the option is required to be set.
* See also BEGIN/END_REQ */
#define ARGTYPE_REQUIRED 0x40000000U
/* HIDDEN means that the option does not appear in help texts. Useful
* for debugging or testing options */
#define ARGTYPE_HIDDEN 0x20000000U
/* BEGIN/END_EXCL mark the beginning and end of an exclusive range of
* options. No more than one of the options in the range may be selected
* or set. If exactly one must be set, use with BEGIN/END_REQ
* Both of these flags set is just like neither set, so avoid doing that. */
#define ARGTYPE_BEGIN_EXCL 0x10000000U
#define ARGTYPE_END_EXCL 0x08000000U
/* BEGIN/END_REQ mark the beginning and end of a required range of
* options. One or more of the options in the range MUST be selected or set.
* If exactly one must be set, use with BEGIN/END_EXCL
* Both of these flags set is synonymous with REQUIRED, so use that instead
* for "groups" of exactly one option. */
#define ARGTYPE_BEGIN_REQ 0x04000000U
#define ARGTYPE_END_REQ 0x02000000U
#define ARGTYPE_TYPEMASK 0x00000fffU
#define ARGTYPE_FLAGMASK 0xfffff000U
#define ARG_NOMINMAX nullptr, nullptr
struct arglist_t {
const QString argstring;
Option* const argval{nullptr};
const QString helpstring;
const QString defaultvalue;
const uint32_t argtype{ARGTYPE_UNKNOWN};
const QString minvalue; /* minimum value for numeric options */
const QString maxvalue; /* maximum value for numeric options */
char* unused{nullptr}; /* TODO: delete from initialization lists */
};
enum ff_type {
ff_type_file = 1, /* normal format: useful to a GUI. */
ff_type_internal, /* fmt not useful with default options */
ff_type_serial /* format describes a serial protocol (GUI can display port names) */
};
enum ff_cap_array {
ff_cap_rw_wpt,
ff_cap_rw_trk,
ff_cap_rw_rte
};
enum ff_cap {
ff_cap_none,
ff_cap_read = 1,
ff_cap_write = 2
};
#define FF_CAP_RW_ALL \
{ (ff_cap) (ff_cap_read | ff_cap_write), (ff_cap) (ff_cap_read | ff_cap_write), (ff_cap) (ff_cap_read | ff_cap_write) }
#define FF_CAP_RW_WPT \
{ (ff_cap) (ff_cap_read | ff_cap_write), ff_cap_none, ff_cap_none}
[[noreturn]] void gbFatal(QDebug& msginstance);
// cppcheck 2.10.3 fails to assign noreturn attribute to gbFatal if
// the noreturn attribute is listed before the gnu::format attribute.
// A PR to resolve this is https://github.com/danmar/cppcheck/pull/4971,
// but cppcheck works if the noreturn attribute follows the gnu::format
// attribute.
// This can have a large effect on codacy issues from cppcheck
// nullPointerRedundantCheck, nullPointerArithmeticRedundantCheck,
// negativeIndex, arrayIndexOutOfBoundsCond.
[[gnu::format(printf, 1, 2)]] [[noreturn]] void gbFatal(const char* fmt, ...);
[[gnu::format(printf, 1, 2)]] void gbWarning(const char* fmt, ...);
[[gnu::format(printf, 1, 2)]] void gbInfo(const char* fmt, ...);
[[gnu::format(printf, 1, 2)]] void gbDebug(const char* fmt, ...);
void gbVLegacyLog(QtMsgType type, const char* fmt, va_list args1);
void printposn(double c, bool is_lat);
void* xcalloc(size_t nmemb, size_t size);
void* xmalloc(size_t size);
void* xrealloc(void* p, size_t s);
void xfree(const void* mem);
char* xstrdup(const char* s);
FILE* xfopen(const QString& fname, const char* type);
// Thin wrapper around fopen() that supports Unicode fname on all platforms.
FILE* ufopen(const QString& fname, const char* mode);
// FIXME: case_ignore_strcmp() and case_ignore_strncmp() should probably
// just be replaced at the call sites. These shims are just here to make
// them more accommodating of QString input.
inline int
case_ignore_strcmp(const QString& s1, const QString& s2)
{
return QString::compare(s1, s2, Qt::CaseInsensitive);
}
// In 95% of the callers, this could be s1.startsWith(s2)...
inline int case_ignore_strncmp(const QString& s1, const QString& s2, int n)
{
return s1.left(n).compare(s2.left(n), Qt::CaseInsensitive);
}
QDateTime make_datetime(QDate date, QTime time, bool is_localtime, bool force_utc, int utc_offset);
bool gpsbabel_testmode();
gpsbabel::DateTime current_time();
QDateTime dotnet_time_to_qdatetime(long long dotnet);
long long qdatetime_to_dotnet_time(const QDateTime& dt);
QString strip_html(const QString& utfstring);
QString strip_nastyhtml(const QString& in);
QString convert_human_date_format(const QString& human_datef); /* "MM,YYYY,DD" -> "%m,%Y,%d" */
QString convert_human_time_format(const QString& human_timef); /* "HH+mm+ss" -> "%H+%M+%S" */
QString pretty_deg_format(double lat, double lon, char fmt, const char* sep, bool html); /* decimal -> dd.dddd or dd mm.mmm or dd mm ss */
QString get_filename(const QString& fname); /* extract the filename portion */
/* this lives in gpx.c */
gpsbabel::DateTime xml_parse_time(const QString& dateTimeString);
QString rot13(const QString& s);
/*
* Prototypes for Endianness helpers.
*/
signed int be_read16(const void* ptr);
unsigned int be_readu16(const void* ptr);
signed int be_read32(const void* ptr);
signed int le_read16(const void* ptr);
unsigned int le_readu16(const void* ptr);
signed int le_read32(const void* ptr);
unsigned int le_readu32(const void* ptr);
void le_read64(void* dest, const void* src);
void be_write16(void* ptr, unsigned value);
void be_write32(void* ptr, unsigned value);
void le_write16(void* ptr, unsigned value);
void le_write32(void* ptr, unsigned value);
double endian_read_double(const void* ptr, int read_le);
float endian_read_float(const void* ptr, int read_le);
void endian_write_double(void* ptr, double value, int write_le);
void endian_write_float(void* ptr, float value, int write_le);
float be_read_float(void* ptr);
double be_read_double(void* ptr);
void be_write_float(void* ptr, float value);
void be_write_double(void* ptr, double value);