ADD: new track message, Entity class and Position class

This commit is contained in:
Henry Winkel
2022-12-20 17:20:35 +01:00
parent 469ecfb099
commit 98ebb563a8
2114 changed files with 482360 additions and 24 deletions

View File

@@ -0,0 +1,498 @@
/**
* \file GeodTest.cpp
**********************************************************************/
#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#include "GeographicLib/Geodesic.hpp"
#include "GeographicLib/GeodesicLine.hpp"
#include "GeographicLib/GeodesicExact.hpp"
#include "GeographicLib/GeodesicLineExact.hpp"
#include "GeographicLib/Constants.hpp"
#include <GeographicLib/Utility.hpp>
#include <cmath>
#include <vector>
#include <utility>
#include <algorithm>
#include <limits>
using namespace std;
using namespace GeographicLib;
int usage(int retval) {
( retval ? cerr : cout ) <<
"GeodTest [ -a | -c | -t0 | -t1 | -t2 | -t3 | -h ]\n\
\n\
Check GeographicLib::Geodesic class.\n\
-a (default) accuracy test (reads test data on standard input)\n\
-E accuracy test with GeodesicExact (reads test data on standard input)\n\
-F accuracy test with GeodesicExact (reads test data on standard input\n\
first line gives a and f)\n\
-c coverage test (reads test data on standard input)\n\
-t0 time GeodecicLine with distances using synthetic data\n\
-t1 time GeodecicLine with angles using synthetic data\n\
-t2 time Geodecic::Direct using synthetic data\n\
-t3 time Geodecic::Inverse with synthetic data\n\
-T0 time GeodecicLineExact with distances using synthetic data\n\
-T1 time GeodecicLineExact with angles using synthetic data\n\
-T2 time GeodecicExact::Direct using synthetic data\n\
-T3 time GeodecicExact::Inverse with synthetic data\n\
\n\
-c requires an instrumented version of Geodesic.\n";
return retval;
}
Math::real angdiff(Math::real a1, Math::real a2) {
Math::real d = a2 - a1;
if (d >= 180)
d -= 360;
else if (d < -180)
d += 360;
return d;
}
Math::real azidiff(Math::real lat,
Math::real lon1, Math::real lon2,
Math::real azi1, Math::real azi2) {
Math::real
phi = lat * Math::degree(),
alpha1 = azi1 * Math::degree(),
alpha2 = azi2 * Math::degree(),
dlam = angdiff(lon1, lon2) * Math::degree();
Math::real res = sin(alpha2-alpha1)*cos(dlam)
-cos(alpha2-alpha1)*sin(dlam)*sin(phi)
// -sin(alpha1)*cos(alpha2)*(1-cos(dlam))*cos(phi)*cos(phi)
;
return res;
}
Math::real dist(Math::real a, Math::real f,
Math::real lat0, Math::real lon0,
Math::real lat1, Math::real lon1) {
// typedef GeographicLib::Math::real real;
// real s12;
// GeographicLib::Geodesic::
// WGS84.Inverse(real(lat0), real(lon0), real(lat1), real(lon1), s12);
// return Math::real(s12);
a *= Math::degree();
if (abs(lat0 + lat1) > Math::real(179.998)) {
// Near pole, transform into polar coordinates
Math::real
r0 = 90 - abs(lat0),
r1 = 90 - abs(lat1),
lam0 = lon0 * Math::degree(),
lam1 = lon1 * Math::degree();
return (a / (1 - f)) *
hypot(r0 * cos(lam0) - r1 * cos(lam1), r0 * sin(lam0) - r1 * sin(lam1));
} else {
// Otherwise use cylindrical formula
Math::real
phi = lat0 * Math::degree(),
cphi = abs(lat0) <= 45 ? cos(phi)
: sin((90 - abs(lat0)) * Math::degree()),
e2 = f * (2 - f),
sinphi = sin(phi),
n = 1/sqrt(1 - e2 * sinphi * sinphi),
// See Wikipedia article on latitude
degreeLon = a * cphi * n,
degreeLat = a * (1 - e2) * n * n * n,
dlon = angdiff(lon1, lon0),
dlat = lat1 - lat0;
dlat *= degreeLat;
dlon *= degreeLon;
return hypot(dlat, dlon);
}
}
// err[0] error in position of point 2 for the direct problem.
// err[1] error in azimuth at point 2 for the direct problem.
// err[2] error in m12 for the direct problem & inverse (except near conjugacy)
// err[3] error in s12 for the inverse problem.
// err[4] error in the azimuths for the inverse problem scaled by m12.
// err[5] consistency of the azimuths for the inverse problem.
// err[6] area error direct & inverse (except near conjugacy)
template<class test>
void GeodError(const test& tgeod,
Math::real lat1, Math::real lon1, Math::real azi1,
Math::real lat2, Math::real lon2, Math::real azi2,
Math::real s12, Math::real /*a12*/,
Math::real m12, Math::real S12,
vector<Math::real>& err) {
Math::real tlat1, tlon1, tazi1, tlat2, tlon2, tazi2, ts12, tm12a, tm12b,
tM12, tM21, tS12a, tS12b /*, ta12*/;
Math::real rlat1, rlon1, razi1, rlat2, rlon2, razi2, rm12;
tgeod.Direct(lat1, lon1, azi1, s12,
tlat2, tlon2, tazi2, tm12a,
tM12, tM21, tS12a);
tS12a -= tgeod.EllipsoidArea() * (tazi2-azi2)/720;
tgeod.Direct(lat2, lon2, azi2, -s12,
tlat1, tlon1, tazi1, tm12b,
tM12, tM21, tS12b);
tS12b -= tgeod.EllipsoidArea() * (tazi1-azi1)/720;
err[0] = max(dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
lat2, lon2, tlat2, tlon2),
dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
lat1, lon1, tlat1, tlon1));
err[1] = max(abs(azidiff(lat2, lon2, tlon2, azi2, tazi2)),
abs(azidiff(lat1, lon1, tlon1, azi1, tazi1))) *
tgeod.EquatorialRadius();
err[2] = max(abs(tm12a - m12), abs(tm12b + m12));
if (!isnan(S12))
err[6] = max(abs(tS12a - S12), abs(tS12b + S12)) / tgeod.EquatorialRadius();
/* ta12 = */ tgeod.Inverse(lat1, lon1, lat2, lon2,
ts12, tazi1, tazi2, tm12a,
tM12, tM21, tS12a);
tS12a -= tgeod.EllipsoidArea() * ((tazi2-azi2)-(tazi1-azi1))/720;
err[3] = abs(ts12 - s12);
err[4] = max(abs(angdiff(azi1, tazi1)), abs(angdiff(azi2, tazi2))) *
Math::degree() * abs(m12);
if (lat1 + lat2 == 0)
err[4] = min(err[4],
max(abs(angdiff(azi1, tazi2)), abs(angdiff(azi2, tazi1))) *
Math::degree() * abs(m12));
// m12 and S12 are very sensitive with the inverse problem near conjugacy
if (!(s12 > tgeod.EquatorialRadius() && m12 < 10e3)) {
err[2] = max(err[2], abs(tm12a - m12));
if (!isnan(S12))
err[6] = max(err[6], abs(tS12a - S12) / tgeod.EquatorialRadius());
}
if (s12 > tgeod.EquatorialRadius()) {
tgeod.Direct(lat1, lon1, tazi1, ts12/2, rlat2, rlon2, razi2, rm12);
tgeod.Direct(lat2, lon2, tazi2, - ts12/2, rlat1, rlon1, razi1, rm12);
err[5] = dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
rlat1, rlon1, rlat2, rlon2);
} else {
tgeod.Direct(lat1, lon1, tazi1,
ts12 + tgeod.EquatorialRadius(),
rlat2, rlon2, razi2, rm12);
tgeod.Direct(lat2, lon2, tazi2, tgeod.EquatorialRadius(),
rlat1, rlon1, razi1, rm12);
err[5] = dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
rlat1, rlon1, rlat2, rlon2);
tgeod.Direct(lat1, lon1, tazi1, - tgeod.EquatorialRadius(),
rlat2, rlon2, razi2, rm12);
tgeod.Direct(lat2, lon2, tazi2,
- ts12 - tgeod.EquatorialRadius(),
rlat1, rlon1, razi1, rm12);
err[5] = max(err[5], dist(tgeod.EquatorialRadius(), tgeod.Flattening(),
rlat1, rlon1, rlat2, rlon2));
}
}
int main(int argc, char* argv[]) {
Utility::set_digits();
Math::real a = Constants::WGS84_a();
Math::real f = Constants::WGS84_f();
bool timing = false;
int timecase = 0; // 0 = line, 1 = line ang, 2 = direct, 3 = inverse
bool accuracytest = true;
bool coverage = false;
bool exact = false;
if (argc == 2) {
string arg = argv[1];
if (arg == "-a") {
accuracytest = true;
coverage = false;
timing = false;
exact = false;
} else if (arg == "-E") {
accuracytest = true;
coverage = false;
timing = false;
exact = true;
} else if (arg == "-F") {
accuracytest = true;
coverage = false;
timing = false;
exact = true;
string s;
getline(cin, s);
istringstream str(s);
str >> a >> f;
} else if (arg == "-c") {
accuracytest = false;
coverage = true;
timing = false;
exact = false;
} else if (arg == "-t0") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 0;
exact = false;
} else if (arg == "-t1") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 1;
exact = false;
} else if (arg == "-t2") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 2;
exact = false;
} else if (arg == "-t3") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 3;
exact = false;
} else if (arg == "-T0") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 0;
exact = true;
} else if (arg == "-T1") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 1;
exact = true;
} else if (arg == "-T2") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 2;
exact = true;
} else if (arg == "-T3") {
accuracytest = false;
coverage = false;
timing = true;
timecase = 3;
exact = true;
} else
return usage(arg == "-h" ? 0 : 1);
} else if (argc > 2)
return usage(1);
if (timing) {
if (!exact) {
const Geodesic& geod = Geodesic::WGS84();
unsigned cnt = 0;
Math::real s = 0;
Math::real dl;
switch (timecase) {
case 0:
// Time Line
dl = 2e7/1000;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
const GeodesicLine l(geod, lat1, 0.0, azi1);
for (int k = 0; k <= 1000; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
l.Position(s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 1:
// Time Line ang
dl = Math::real(180)/1000;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
GeodesicLine l(geod, lat1, 0.0, azi1);
for (int k = 0; k <= 1000; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
l.ArcPosition(s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 2:
// Time Direct
dl = 2e7/200;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
for (int k = 0; k <= 200; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
geod.Direct(lat1, 0.0, azi1, s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 3:
// Time Inverse
for (int i = 1; i <= 179; i += 2) {
Math::real lat1 = i * Math::real(0.5);
for (int j = -179; j <= 179; j += 2) {
Math::real lat2 = j * Math::real(0.5);
for (int k = 1; k <= 359; k += 2) {
Math::real lon2 = k * Math::real(0.5);
Math::real s12;
geod.Inverse(lat1, 0.0, lat2, lon2, s12);
++cnt;
s += s12;
}
}
}
cout << cnt << " " << s << "\n";
break;
}
} else {
const GeodesicExact& geod = GeodesicExact::WGS84();
unsigned cnt = 0;
Math::real s = 0;
Math::real dl;
switch (timecase) {
case 0:
// Time Line
dl = 2e7/1000;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
const GeodesicLineExact l(geod, lat1, 0.0, azi1);
for (int k = 0; k <= 1000; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
l.Position(s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 1:
// Time Line ang
dl = Math::real(180)/1000;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
GeodesicLineExact l(geod, lat1, 0.0, azi1);
for (int k = 0; k <= 1000; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
l.ArcPosition(s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 2:
// Time Direct
dl = 2e7/200;
for (int i = 0; i <= 90; ++i) {
Math::real lat1 = i;
for (int j = 0; j <= 180; ++j) {
Math::real azi1 = j;
for (int k = 0; k <= 200; ++k) {
Math::real s12 = dl * k;
Math::real lat2, lon2;
geod.Direct(lat1, 0.0, azi1, s12, lat2, lon2);
++cnt;
s += lat2;
}
}
}
cout << cnt << " " << s << "\n";
break;
case 3:
// Time Inverse
for (int i = 1; i <= 179; i += 2) {
Math::real lat1 = i * Math::real(0.5);
for (int j = -179; j <= 179; j += 2) {
Math::real lat2 = j * Math::real(0.5);
for (int k = 1; k <= 359; k += 2) {
Math::real lon2 = k * Math::real(0.5);
Math::real s12;
geod.Inverse(lat1, 0.0, lat2, lon2, s12);
++cnt;
s += s12;
}
}
}
cout << cnt << " " << s << "\n";
break;
}
}
}
else if (accuracytest || coverage) {
const Geodesic geod(a, f);
const GeodesicExact geode(a, f);
const unsigned NUMERR = 7;
cout << fixed << setprecision(2);
vector<Math::real> erra(NUMERR);
vector<Math::real> err(NUMERR, 0.0);
vector<unsigned> errind(NUMERR);
unsigned cnt = 0;
string s;
while (getline(cin, s)) {
istringstream str(s);
Math::real lat1l, lon1l, azi1l, lat2l, lon2l, azi2l,
s12l, a12l, m12l, S12l;
if (!(str >> lat1l >> lon1l >> azi1l
>> lat2l >> lon2l >> azi2l
>> s12l >> a12l >> m12l))
break;
if (!(str >> S12l))
S12l = Math::NaN();
if (coverage) {
#if defined(GEOD_DIAG) && GEOD_DIAG
Math::real
lat1 = lat1l, lon1 = lon1l,
lat2 = lat2l, lon2 = lon2l,
azi1, azi2, s12, m12;
geod.Inverse(lat1, lon1, lat2, lon2, s12, azi1, azi2, m12);
cout << geod.coverage << " " << geod.niter << "\n";
#endif
} else {
exact ?
GeodError< GeodesicExact >
(geode, lat1l, lon1l, azi1l,
lat2l, lon2l, azi2l,
s12l, a12l, m12l, S12l,
erra) :
GeodError< Geodesic >
(geod, lat1l, lon1l, azi1l,
lat2l, lon2l, azi2l,
s12l, a12l, m12l, S12l,
erra);
for (unsigned i = 0; i < NUMERR; ++i) {
if (isfinite(err[i]) && !(erra[i] <= err[i])) {
err[i] = erra[i];
errind[i] = cnt;
}
}
++cnt;
}
}
if (accuracytest) {
Math::real mult = Math::real(Math::extra_digits() == 0 ? 1e9l :
Math::extra_digits() <= 3 ? 1e12l : 1e15l);
for (unsigned i = 0; i < NUMERR; ++i)
cout << i << " " << mult * err[i]
<< " " << errind[i] << "\n";
}
}
}