--- /dev/null
+/*
+ Earth Centered Earth Fixed (ECEF) WGS84 Navigation Utility Copyright © 2013-2017 Infinite Delta Corp
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser 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 Lesser General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <iostream>
+#include <ecef-quaternion.h>
+#include <ecef-wgs84.h>
+
+namespace ecef
+{
+static bool tst(const double i, const double j=0, const double t=0.0000001)
+ {if (i>=j ? i-j <= t : j-i <= t) return true;
+ std::cout << i << " " << j << " " << i-j << " " << t << " ";
+ return false;
+ }
+
+#define ERR(e,m) {std::cout << "Test Error: \"" << m << "\" in " << __FILE__ << ":" << __LINE__ << std::endl; return e;}
+
+#define LL_INC wgs84Const::maxNorth/1000.0
+
+int tst1()
+{
+ vec cent;
+ wgs84 pos;
+
+ if (pos.x != 6378137.0) ERR(1, "Default X is not Wgs84 Radius");
+ if (pos.y != 0.0) ERR(1, "Default Y is not zero");
+ if (pos.z != 0.0) ERR(1, "Default Z is not zero");
+ // std::cout << pos.x << std::endl;
+ // std::cout << pos.y << std::endl;
+ // std::cout << pos.z << std::endl;
+
+ if (vec(1.0, 0.0, 0.0) + vec(0.0, 2.0, 0.0) + vec(0.0, 0.0, 3.0) !=
+ vec(1.0, 2.0, 3.0)) ERR(1, "Bad vector addition");
+
+ if (vec(1.0, 0.0, 0.0) - vec(2.0, 3.0, 0.0) - vec(0.0, 0.0, 4.0) !=
+ vec(-1.0, -3.0, -4.0)) ERR(1, "Bad vector subtraction");
+
+ if (vec(1.0, 2.0, 3.0).dot(vec(4.0, 5.0, 6.0)) != 32.0) ERR(1, "Bad vector dot product");
+
+ if (vec(1.0, 0.0, 0.0).cross(vec(0.0, 1.0, 0.0)) != vec(0.0, 0.0, 1.0))
+ ERR(1, "Bad vector cross product");
+
+ if (vec(0.0, 1.0, 0.0).cross(vec(0.0, 1.0, 0.0)) != vec(0.0, 0.0, 0.0))
+ ERR(1, "Bad vector cross product");
+
+ if (vec(0.0, 0.0, 1.0).cross(vec(0.0, 1.0, 0.0)) != vec(-1.0, 0.0, 0.0))
+ ERR(1, "Bad vector cross product");
+
+ // std::cout << pos.dist(vec(6378137.0, 0.0, 0.0)) << std::endl;
+
+ if (!(pos == vec(6378137.0, 0.0, 0.0))) ERR(1, "Default pos is not prime meridian");
+ if (pos != vec(6378137.0, 0.0, 0.0)) ERR(1, "Default pos is not prime meridian");
+
+ // std::cout << cent.dist(pos)- 6378137.0 << std::endl;
+
+ if (cent.dist(pos) != 6378137.0) ERR(1, "Equator Radius not Wgs84");
+ if (wgs84Const::c != 6356752.3142451792954l) ERR(1, "Minor axis not Wgs84");
+
+ // std::cout << wgs84(wgs84Const::maxNorth, 0.0).x << std::endl;
+ // std::cout << wgs84(wgs84Const::maxNorth, 0.0).y << std::endl;
+ // std::cout << wgs84(wgs84Const::maxNorth, 0.0).z << std::endl;
+
+ // std::cout << a * (1-1/fr) << std::endl;
+
+ if (wgs84(wgs84Const::maxNorth, 0.0).z != wgs84Const::c) ERR(1, "Bad North");
+ if (!tst(wgs84(wgs84Const::maxNorth, 0.0).z, 6356752.31424518l)) ERR(1, "Bad North");
+
+ for (double lon=wgs84Const::maxEast; lon > wgs84Const::maxWest; lon -= LL_INC)
+ {
+ if (!tst(cent.dist(wgs84(0.0, lon)), 6378137.0))
+ {
+ std::cout << lon << ": " << cent.dist(wgs84(0.0, lon)) - 6378137.0 << std::endl;
+
+ ERR(1, "World Equator Radius not Wgs84");
+ }
+ }
+
+ return 0;
+}
+
+int tst2()
+{
+ int total=0;
+ wgs84Line line;
+ // line l1(vec(6378137.0/2,0,0));
+ // line l1(vec(6000000.0,0,0));
+ // line l2(count, l1);
+
+ // std::cout << count << std::endl;
+ // std::cout << l2.p1.x << std::endl;
+ // std::cout << l2.p1.y << std::endl;
+ // std::cout << l2.p1.z << std::endl;
+ // std::cout << l2.p2.x << std::endl;
+ // std::cout << l2.p2.y << std::endl;
+ // std::cout << l2.p2.z << std::endl;
+
+ if (line.trimToEllipsoid() != 2) ERR(2, "WGS84 Crossing count");
+ if (line.p[0] != vec(-6378137.0,0,0)) ERR(2, "WGS84 Crossing");
+ if (line.p[1] != vec( 6378137.0,0,0)) ERR(2, "WGS84 Crossing");
+
+ line = wgs84Line(vec(0,1,0));
+ if (line.trimToEllipsoid() != 2) ERR(2, "WGS84 Crossing count");
+ // std::cout << " " << line.p[0].x << std::endl;
+ // std::cout << " " << line.p[0].y << std::endl;
+ // std::cout << " " << line.p[0].z << std::endl;
+ // std::cout << std::endl;
+ if (line.p[0] != vec(0,-6378137.0,0)) ERR(2, "WGS84 Crossing");
+ if (line.p[1] != vec(0, 6378137.0,0)) ERR(2, "WGS84 Crossing");
+
+ line = wgs84Line(vec(0,0,1));
+ if (line.trimToEllipsoid() != 2) ERR(2, "WGS84 Crossing count");
+ if (line.p[0] != vec(0,0,-6356752.31424518)) ERR(2, "WGS84 Crossing");
+ if (line.p[1] != vec(0,0, 6356752.31424518)) ERR(2, "WGS84 Crossing");
+
+ for (double lon=wgs84Const::maxEast; lon > wgs84Const::maxWest; lon -= LL_INC)
+ {
+ for (double lat=wgs84Const::maxNorth; lat > wgs84Const::maxSouth; lat -= LL_INC)
+ {
+ wgs84Line l1(wgs84(lat,lon), wgs84(wgs84Const::maxNorth/2, wgs84Const::maxNorth));
+ wgs84Line l2(l1);
+ int count = l2.trimToEllipsoid();
+ if (count > 0 && l1.p[0] != l2.p[0]) ERR(2, "WGS84 robust");
+ if (count > 1 && l1.p[1] != l2.p[1]) ERR(2, "WGS84 robust");
+
+ wgs84Line l3(wgs84(lat,lon));
+ wgs84Line l5(l3.p[1]/33.0);
+ l5.trimToEllipsoid();
+
+ if (l3.p[1]*-1 != l5.p[0]) ERR(2, "WGS84 trim robust");
+ if (l3.p[1] != l5.p[1]) ERR(2, "WGS84 trim robust");
+
+#ifdef tlz
+ vec p1(wgs84(lat,lon));
+ vec p2(p1);
+ p2.y = 0;
+ line l6(count, line(p1, p2));
+ if (l6.p1 != p1)
+ {
+ std::cout << p1.x << std::endl;
+ std::cout << p1.y << std::endl;
+ std::cout << p1.z << std::endl;
+ std::cout << l6.p1.x << std::endl;
+ std::cout << l6.p1.y << std::endl;
+ std::cout << l6.p1.z << std::endl;
+ ERR(2, "WGS84 robust");
+ }
+#endif
+ ++total;
+ }
+ }
+ std::cout << "Total " << total << std::endl;
+ return 0;
+}
+
+int tstLon()
+{
+ for (double lon=wgs84Const::maxEast; lon > wgs84Const::maxWest; lon -= LL_INC)
+ {
+ wgs84 npole(wgs84Const::maxNorth,lon);
+ if (!tst(0, npole.lon()*1800/M_PIl)) ERR(4, "Bad Longitude");
+ wgs84 spole(wgs84Const::maxSouth,lon);
+ if (!tst(0, spole.lon()*1800/M_PIl)) ERR(4, "Bad Longitude");
+
+ for (double lat=wgs84Const::maxNorth-LL_INC; lat >= wgs84Const::maxSouth+LL_INC; lat -= LL_INC)
+ {
+ wgs84 t(lat,lon);
+ if (!tst(lon*1800/M_PIl, t.lon()*1800/M_PIl)) ERR(4, "Bad Longitude");
+ }
+ }
+ return 0;
+}
+
+int tstCos()
+{
+ vec t(1,0,0);
+
+ if (!tst(acos(t.cos(vec(1,1,0)))*180/M_PIl, 45)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(1,0,1)))*180/M_PIl, 45)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(1,0,0)))*180/M_PIl, 0)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(1,-1,0)))*180/M_PIl, 45)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(1,0,-1)))*180/M_PIl, 45)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(-1,0,0)))*180/M_PIl, 180)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(0,1,0)))*180/M_PIl, 90)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(0,0,1)))*180/M_PIl, 90)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(0,-1,0)))*180/M_PIl, 90)) ERR(4, "Bad Cos");
+ if (!tst(acos(t.cos(vec(0,0,-1)))*180/M_PIl, 90)) ERR(4, "Bad Cos");
+
+ for (double lon=wgs84Const::maxEast; lon > wgs84Const::maxWest; lon -= LL_INC*100)
+ {
+ // std::cout << lon*1800/M_PIl << std::endl;
+ for (double lat=wgs84Const::maxNorth; lat >= wgs84Const::maxSouth; lat -= LL_INC)
+ {
+ wgs84Fast t(lat,lon), n(t.north());
+ if (!tst(lat*1800/M_PIl, t.lat()*1800/M_PIl)) ERR(4, "Bad Lat");
+
+ if (!tst(abs(t.sinLat()), n.distZ()/n.dist())) ERR(4, "Bad North vector");
+
+ wgs84Fast t2(lat,-85,10000);
+ if (!tst(lat*1800/M_PIl, t2.lat()*1800/M_PIl, 0.0035)) ERR(4, "Bad Lat at alt");
+ }
+ }
+
+ return 0;
+}
+
+int tst3()
+{
+ for (double lat=wgs84Const::maxNorth; lat > wgs84Const::maxSouth; lat -= LL_INC)
+ {
+ wgs84Fast pnt(lat,0);
+ // std::cout << " " << lat*1800/M_PIl;
+ // std::cout << pnt.x - FindX2D(pnt.z);
+ // std::cout << " " << Slope2D(pnt.z);
+ // std::cout << " " << tan(lat);
+ // std::cout << " " << tan(lat) - Slope2D(pnt.z);
+ // if (!tst(pnt.x, pnt.rotationRadius(), 0.00001)) ERR(4, "Bad radius");
+ if (!tst(pnt.x, pnt.distZ())) ERR(4, "Bad radius");
+ //tlz if (!tst(tan(lat), pnt.tanLat())) ERR(4, "Bad Tan");
+ //tlz if (!tst(pnt.x, tan(lat)*(pnt.z - TanZCrossing(pnt.z)), 0.000001)) ERR(4, "Bad Z0");
+ if (!tst(lat, asin(pnt.sinLat()), 0.0000001)) ERR(4, "Bad WGS84 Sin");
+
+ pnt = wgs84(lat,0,10000);
+ // std::cout << " " << lat*1800/M_PIl;
+ // std::cout << " " << pnt.x;
+ // std::cout << " " << pnt.y;
+ // std::cout << " " << pnt.z;
+ // std::cout << " " << TanZCrossing(pnt.z);
+ // std::cout << " " << tan(lat);
+ // std::cout << " " << (find2dX(pnt.z) - find2dX(pnt.z+0.1))/0.1;
+ // std::cout << " " << pnt.x / (pnt.z - TanZCrossing(pnt.z));
+ // std::cout << " " << pnt.z;
+ // std::cout << " " << WGS84EarthCenter(pnt.z);
+ // std::cout << std::endl;
+ if (!tst(lat, asin(pnt.sinLat()), 0.00001)) ERR(4, "Bad WGS84 Sin");
+
+ // if (lat > wgs84Const::maxNorth-0.2) continue; // Skip near polls TanZCrossing is better!
+ // if (lat < wgs84Const::maxSouth+0.2) continue; // Skip near polls TanZCrossing is better!
+
+ // if (!tst(pnt.x, tan(lat)*(pnt.z - TanZCrossing(pnt.z)), 0.1)) ERR(4, "Bad Z0");
+ }
+
+ return 0;
+}
+
+int qtst()
+{
+ quat q;
+
+ q = quat(0, vec(0,0,0)).versor();
+ if (!tst(q.a, 0)) ERR(5, "Bad Quat Versor Init");
+ if (!tst(q.v.x, 0)) ERR(5, "Bad Quat Versor Init");
+ if (!tst(q.v.y, 0)) ERR(5, "Bad Quat Versor Init");
+ if (!tst(q.v.z, 1)) ERR(5, "Bad Quat Versor Init");
+
+ q = quat(3, vec(4,5,6)).conj();
+ if (!tst(q.a, 3)) ERR(5, "Bad Quat Conj Angle");
+ if (!tst(q.v.x, -4)) ERR(5, "Bad Quat Conj X");
+ if (!tst(q.v.y, -5)) ERR(5, "Bad Quat Conj Y");
+ if (!tst(q.v.z, -6)) ERR(5, "Bad Quat Conj Z");
+ if (!tst(q.mag(), sqrt(86.0))) ERR(5, "Bad Quat Magnitude");
+ if (!tst(q.versor().mag(), 1)) ERR(5, "Bad Quat Versor");
+
+ q = quat(0, zAxis) * quat(0, zAxis);
+ if (!tst(q.a, -1)) ERR(5, "Bad Quat Angle");
+ if (!tst(q.v.x, 0)) ERR(5, "Bad Quat X");
+ if (!tst(q.v.y, 0)) ERR(5, "Bad Quat Y");
+ if (!tst(q.v.z, 0)) ERR(5, "Bad Quat Z");
+
+ q = quat(0, zAxis) * quat(0, vec(1,0,0));
+ if (!tst(q.a, 0)) ERR(5, "Bad Quat Angle");
+ if (!tst(q.v.x, 0)) ERR(5, "Bad Quat X");
+ if (!tst(q.v.y, 1)) ERR(5, "Bad Quat Y");
+ if (!tst(q.v.z, 0)) ERR(5, "Bad Quat Z");
+
+ // q = quat(cos(M_PI_2l/2), zAxis) * quat(cos(M_PI_2l/2), zAxis);
+ // q = quat(cos(M_PI_2l/2), zAxis * sin(M_PI_2l/2));
+
+ q = quat(cos(M_PI_4l/2), zAxis).normVec();
+ q = q * q;
+
+ if (!tst(q.a, cos(M_PI_4l))) ERR(5, "Bad Quat Hamilton Multiple Angle");
+ if (!tst(q.v.x, 0)) ERR(5, "Bad Quat Mult X");
+ if (!tst(q.v.y, 0)) ERR(5, "Bad Quat Mult Y");
+ if (!tst(q.v.norm().z, 1)) ERR(5, "Bad Quat Z");
+
+ q = quat(cos(M_PI_4l/4), zAxis).normVec() * quat(cos(M_PI_4l/2), zAxis).normVec();
+ if (!tst(q.a, cos(M_PI_4l * 3/4))) ERR(5, "Bad Quat Hamilton Multiple Angle");
+ if (!tst(q.v.x, 0)) ERR(5, "Bad Quat Mult X");
+ if (!tst(q.v.y, 0)) ERR(5, "Bad Quat Mult Y");
+ if (!tst(q.v.norm().z, 1)) ERR(5, "Bad Quat Z");
+
+ q = quat(cos(M_PI_2l), zAxis).normVec() * quat(cos(M_PI_2l), vec(0,1,0)).normVec();
+ if (!tst(q.a, cos(M_PI_2l))) ERR(5, "Bad Quat Hamilton Multiple Angle");
+ if (!tst(q.v.x, -1)) ERR(5, "Bad Quat Mult X");
+ if (!tst(q.v.y, 0)) ERR(5, "Bad Quat Mult Y");
+ if (!tst(q.v.z, 0)) ERR(5, "Bad Quat Mult Z");
+
+ q = quat(cos(M_PI_4l), zAxis).normVec() * quat(cos(M_PI_4l), vec(0,1,0)).normVec();
+ if (!tst(q.a, cos(M_PIl/3))) ERR(5, "Bad Quat Hamilton Multiple Angle");
+ if (!tst(q.v.x, -0.5)) ERR(5, "Bad Quat Mult X");
+ if (!tst(q.v.y, 0.5)) ERR(5, "Bad Quat Mult Y");
+ if (!tst(q.v.z, 0.5)) ERR(5, "Bad Quat Mult Z");
+
+ // std::cout << " " << q.a;
+ // std::cout << " " << acos(q.a) * 180 / M_PIl;
+ // std::cout << " " << q.v.x;
+ // std::cout << " " << q.v.y;
+ // std::cout << " " << q.v.z;
+ // std::cout << std::endl;
+
+ return 0;
+}
+
+int qvtst()
+{
+ vec v;
+ quat q(cos(M_PI_4l), zAxis);
+ q = q.normVec();
+
+ v = q * vec(1,0,0);
+ if (!tst(v.x, 0)) ERR(5, "Bad Quat rotate X");
+ if (!tst(v.y, 1)) ERR(5, "Bad Quat rotate Y");
+ if (!tst(v.z, 0)) ERR(5, "Bad Quat rotate Z");
+
+ v = q * vec(0,1,0);
+ if (!tst(v.x, -1)) ERR(5, "Bad Quat rotate X");
+ if (!tst(v.y, 0)) ERR(5, "Bad Quat rotate Y");
+ if (!tst(v.z, 0)) ERR(5, "Bad Quat rotate Z");
+
+ v = q * vec(0,0,1);
+ if (!tst(v.x, 0)) ERR(5, "Bad Quat rotate X");
+ if (!tst(v.y, 0)) ERR(5, "Bad Quat rotate Y");
+ if (!tst(v.z, 1)) ERR(5, "Bad Quat rotate Z");
+
+ v = q * vec(1,1,0);
+ if (!tst(v.x, -1)) ERR(5, "Bad Quat rotate X");
+ if (!tst(v.y, 1)) ERR(5, "Bad Quat rotate Y");
+ if (!tst(v.z, 0)) ERR(5, "Bad Quat rotate Z");
+
+ q = quat(cos(M_PI_4l/2), zAxis).normVec();
+ v = q * vec(1,0,0);
+ if (!tst(v.x, sqrt(0.5))) ERR(5, "Bad Quat rotate X");
+ if (!tst(v.y, sqrt(0.5))) ERR(5, "Bad Quat rotate Y");
+ if (!tst(v.z, 0)) ERR(5, "Bad Quat rotate Z");
+
+ q = quat(cos(30.0 * M_PI_2l/180), zAxis).normVec();
+ v = q * vec(5,0,0);
+ //if (!tst(v.x, sqrt(0.5))) ERR(5, "Bad Quat rotate X");
+ if (!tst(v.y, 2.5)) ERR(5, "Bad Quat rotate Y");
+ if (!tst(v.z, 0)) ERR(5, "Bad Quat rotate Z");
+
+ /*
+ std::cout << " " << v.x;
+ std::cout << " " << v.y;
+ std::cout << " " << v.z;
+ std::cout << std::endl;
+ */
+
+ return 0;
+}
+
+} // namespace ecef
+
+int main()
+{
+ int err=0;
+
+ std::cout.precision(14);
+ std::cout << std::scientific;
+
+ std::cout << "starting ecef-wgs84_test..." << std::endl;
+
+ err |= ecef::tstLon();
+ err |= ecef::tst1();
+ err |= ecef::tst2();
+ err |= ecef::tstCos();
+ err |= ecef::tst3();
+ err |= ecef::qtst();
+ err |= ecef::qvtst();
+
+ std::cout << "finishing ecef-wgs84_test." << std::endl;
+
+ return err;
+}