aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/man3/geodesic.38
-rw-r--r--src/apps/geod_set.cpp1
-rw-r--r--src/geodesic.c311
-rw-r--r--src/geodesic.h141
-rw-r--r--src/pipeline.cpp2
-rw-r--r--src/tests/geodtest.cpp213
6 files changed, 373 insertions, 303 deletions
diff --git a/man/man3/geodesic.3 b/man/man3/geodesic.3
index c2d3d9df..9cfe9864 100644
--- a/man/man3/geodesic.3
+++ b/man/man3/geodesic.3
@@ -53,9 +53,9 @@ measure angles (latitudes, longitudes, and azimuths) in degrees, unlike
the rest of the \fBproj\fR library, which uses radians. The
documentation for this library is included in geodesic.h. A formatted
version of the documentation is available at
-https://geographiclib.sourceforge.io/1.49/C. Detailed documentation of
+https://geographiclib.sourceforge.io/1.50/C. Detailed documentation of
the interface is given at
-https://geographiclib.sourceforge.io/1.49/C/geodesic_8h.html.
+https://geographiclib.sourceforge.io/1.50/C/geodesic_8h.html.
.SH EXAMPLE
The following program reads in lines with the coordinates for two points
in decimal degrees (\fIlat1\fR, \fIlon1\fR, \fIlat2\fR, \fIlon2\fR) and
@@ -89,9 +89,9 @@ libproj.a \- library of projections and support procedures
.SH SEE ALSO
Full online documentation for \fBgeodesic(3)\fR,
.br
-https://geographiclib.sourceforge.io/1.49/C
+https://geographiclib.sourceforge.io/1.50/C
.br
-https://geographiclib.sourceforge.io/1.49/C/geodesic_8h.html
+https://geographiclib.sourceforge.io/1.50/C/geodesic_8h.html
.PP
.B geod(1)
.PP
diff --git a/src/apps/geod_set.cpp b/src/apps/geod_set.cpp
index cd6b5018..ed7edeb9 100644
--- a/src/apps/geod_set.cpp
+++ b/src/apps/geod_set.cpp
@@ -46,7 +46,6 @@ geod_set(int argc, char **argv) {
/* check if line or arc mode */
if (pj_param(nullptr,start, "tlat_1").i) {
double del_S;
-#undef f
phi1 = pj_param(nullptr,start, "rlat_1").f;
lam1 = pj_param(nullptr,start, "rlon_1").f;
if (pj_param(nullptr,start, "tlat_2").i) {
diff --git a/src/geodesic.c b/src/geodesic.c
index dcdd4d77..02887e10 100644
--- a/src/geodesic.c
+++ b/src/geodesic.c
@@ -18,13 +18,15 @@
*
* See the comments in geodesic.h for documentation.
*
- * Copyright (c) Charles Karney (2012-2018) <charles@karney.com> and licensed
+ * Copyright (c) Charles Karney (2012-2019) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*/
#include "geodesic.h"
#include <math.h>
+#include <limits.h>
+#include <float.h>
#if !defined(HAVE_C99_MATH)
#if defined(PROJ_LIB)
@@ -65,21 +67,9 @@ static real epsilon, realmin, pi, degree, NaN,
static void Init() {
if (!init) {
-#if defined(__DBL_MANT_DIG__)
- digits = __DBL_MANT_DIG__;
-#else
- digits = 53;
-#endif
-#if defined(__DBL_EPSILON__)
- epsilon = __DBL_EPSILON__;
-#else
- epsilon = pow(0.5, digits - 1);
-#endif
-#if defined(__DBL_MIN__)
- realmin = __DBL_MIN__;
-#else
- realmin = pow(0.5, 1022);
-#endif
+ digits = DBL_MANT_DIG;
+ epsilon = DBL_EPSILON;
+ realmin = DBL_MIN;
#if defined(M_PI)
pi = M_PI;
#else
@@ -98,15 +88,15 @@ static void Init() {
tolb = tol0 * tol2;
xthresh = 1000 * tol2;
degree = pi/180;
- #if defined(NAN)
- NaN = NAN;
- #else
+#if defined(NAN)
+ NaN = NAN; /* NAN is defined in C99 */
+#else
{
real minus1 = -1;
/* cppcheck-suppress wrongmathcall */
NaN = sqrt(minus1);
}
- #endif
+#endif
init = 1;
}
}
@@ -122,13 +112,28 @@ enum captype {
OUT_ALL = 0x7F80U
};
-static real sq(real x) { return x * x; }
#if HAVE_C99_MATH
+#define hypotx hypot
+/* no need to redirect log1px, since it's only used by atanhx */
#define atanhx atanh
#define copysignx copysign
-#define hypotx hypot
#define cbrtx cbrt
+#define remainderx remainder
+#define remquox remquo
#else
+/* Replacements for C99 math functions */
+
+static real hypotx(real x, real y) {
+ x = fabs(x); y = fabs(y);
+ if (x < y) {
+ x /= y; /* y is nonzero */
+ return y * sqrt(1 + x * x);
+ } else {
+ y /= (x != 0 ? x : 1);
+ return x * sqrt(1 + y * y);
+ }
+}
+
static real log1px(real x) {
volatile real
y = 1 + x,
@@ -143,22 +148,61 @@ static real log1px(real x) {
static real atanhx(real x) {
real y = fabs(x); /* Enforce odd parity */
y = log1px(2 * y/(1 - y))/2;
- return x < 0 ? -y : y;
+ return x > 0 ? y : (x < 0 ? -y : x); /* atanh(-0.0) = -0.0 */
}
static real copysignx(real x, real y) {
+ /* 1/y trick to get the sign of -0.0 */
return fabs(x) * (y < 0 || (y == 0 && 1/y < 0) ? -1 : 1);
}
-static real hypotx(real x, real y)
-{ return sqrt(x * x + y * y); }
-
static real cbrtx(real x) {
- real y = pow(fabs(x), 1/(real)(3)); /* Return the real cube root */
- return x < 0 ? -y : y;
+ real y = pow(fabs(x), 1/(real)(3)); /* Return the real cube root */
+ return x > 0 ? y : (x < 0 ? -y : x); /* cbrt(-0.0) = -0.0 */
+}
+
+static real remainderx(real x, real y) {
+ real z;
+ y = fabs(y); /* The result doesn't depend on the sign of y */
+ z = fmod(x, y);
+ if (z == 0)
+ /* This shouldn't be necessary. However, before version 14 (2015),
+ * Visual Studio had problems dealing with -0.0. Specifically
+ * VC 10,11,12 and 32-bit compile: fmod(-0.0, 360.0) -> +0.0
+ * python 2.7 on Windows 32-bit machines has the same problem. */
+ z = copysignx(z, x);
+ else if (2 * fabs(z) == y)
+ z -= fmod(x, 2 * y) - z; /* Implement ties to even */
+ else if (2 * fabs(z) > y)
+ z += (z < 0 ? y : -y); /* Fold remaining cases to (-y/2, y/2) */
+ return z;
+}
+
+static real remquox(real x, real y, int* n) {
+ real z = remainderx(x, y);
+ if (n) {
+ real
+ a = remainderx(x, 2 * y),
+ b = remainderx(x, 4 * y),
+ c = remainderx(x, 8 * y);
+ *n = (a > z ? 1 : (a < z ? -1 : 0));
+ *n += (b > a ? 2 : (b < a ? -2 : 0));
+ *n += (c > b ? 4 : (c < b ? -4 : 0));
+ if (y < 0) *n *= -1;
+ if (y != 0) {
+ if (x/y > 0 && *n <= 0)
+ *n += 8;
+ else if (x/y < 0 && *n >= 0)
+ *n -= 8;
+ }
+ }
+ return z;
}
+
#endif
+static real sq(real x) { return x * x; }
+
static real sumx(real u, real v, real* t) {
volatile real s = u + v;
volatile real up = s - v;
@@ -195,23 +239,8 @@ static void norm2(real* sinx, real* cosx) {
}
static real AngNormalize(real x) {
-#if HAVE_C99_MATH
- x = remainder(x, (real)(360));
+ x = remainderx(x, (real)(360));
return x != -180 ? x : 180;
-#else
- real y = fmod(x, (real)(360));
-#if defined(_MSC_VER) && _MSC_VER < 1900
- /*
- * Before version 14 (2015), Visual Studio had problems dealing
- * with -0.0. Specifically
- * VC 10,11,12 and 32-bit compile: fmod(-0.0, 360.0) -> +0.0
- * sincosdx has a similar fix.
- * python 2.7 on Windows 32-bit machines has the same problem.
- */
- if (x == 0) y = x;
-#endif
- return y <= -180 ? y + 360 : (y <= 180 ? y : y - 360);
-#endif
}
static real LatFix(real x)
@@ -242,16 +271,7 @@ static void sincosdx(real x, real* sinx, real* cosx) {
/* In order to minimize round-off errors, this function exactly reduces
* the argument to the range [-45, 45] before converting it to radians. */
real r, s, c; int q;
-#if HAVE_C99_MATH && !defined(__GNUC__)
- /* Disable for gcc because of bug in glibc version < 2.22, see
- * https://sourceware.org/bugzilla/show_bug.cgi?id=17569 */
- r = remquo(x, (real)(90), &q);
-#else
- r = fmod(x, (real)(360));
- /* check for NaN */
- q = r == r ? (int)(floor(r / 90 + (real)(0.5))) : 0;
- r -= 90 * q;
-#endif
+ r = remquox(x, (real)(90), &q);
/* now abs(r) <= 45 */
r *= degree;
/* Possibly could call the gnu extension sincos */
@@ -355,6 +375,11 @@ static void acccopy(const real s[], real t[]);
static void accadd(real s[], real y);
static real accsum(const real s[], real y);
static void accneg(real s[]);
+static void accrem(real s[], real y);
+static real areareduceA(real area[], real area0,
+ int crossings, boolx reverse, boolx sign);
+static real areareduceB(real area, real area0,
+ int crossings, boolx reverse, boolx sign);
void geod_init(struct geod_geodesic* g, real a, real f) {
if (!init) Init();
@@ -698,12 +723,14 @@ real geod_genposition(const struct geod_geodesicline* l,
void geod_setdistance(struct geod_geodesicline* l, real s13) {
l->s13 = s13;
- l->a13 = geod_genposition(l, GEOD_NOFLAGS, l->s13, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ l->a13 = geod_genposition(l, GEOD_NOFLAGS, l->s13, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
}
static void geod_setarc(struct geod_geodesicline* l, real a13) {
l->a13 = a13; l->s13 = NaN;
- geod_genposition(l, GEOD_ARCMODE, l->a13, nullptr, nullptr, nullptr, &l->s13, nullptr, nullptr, nullptr, nullptr);
+ geod_genposition(l, GEOD_ARCMODE, l->a13, nullptr, nullptr, nullptr, &l->s13,
+ nullptr, nullptr, nullptr, nullptr);
}
void geod_gensetdistance(struct geod_geodesicline* l,
@@ -715,7 +742,8 @@ void geod_gensetdistance(struct geod_geodesicline* l,
void geod_position(const struct geod_geodesicline* l, real s12,
real* plat2, real* plon2, real* pazi2) {
- geod_genposition(l, FALSE, s12, plat2, plon2, pazi2, nullptr, nullptr, nullptr, nullptr, nullptr);
+ geod_genposition(l, FALSE, s12, plat2, plon2, pazi2,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
}
real geod_gendirect(const struct geod_geodesic* g,
@@ -1134,7 +1162,8 @@ void geod_inverseline(struct geod_geodesicline* l,
void geod_inverse(const struct geod_geodesic* g,
real lat1, real lon1, real lat2, real lon2,
real* ps12, real* pazi1, real* pazi2) {
- geod_geninverse(g, lat1, lon1, lat2, lon2, ps12, pazi1, pazi2, nullptr, nullptr, nullptr, nullptr);
+ geod_geninverse(g, lat1, lon1, lat2, lon2, ps12, pazi1, pazi2,
+ nullptr, nullptr, nullptr, nullptr);
}
real SinCosSeries(boolx sinp, real sinx, real cosx, const real c[], int n) {
@@ -1297,22 +1326,7 @@ real InverseStart(const struct geod_geodesic* g,
boolx shortline = cbet12 >= 0 && sbet12 < (real)(0.5) &&
cbet2 * lam12 < (real)(0.5);
real somg12, comg12, ssig12, csig12;
-#if defined(__GNUC__) && __GNUC__ == 4 && \
- (__GNUC_MINOR__ < 6 || defined(__MINGW32__))
- /* Volatile declaration needed to fix inverse cases
- * 88.202499451857 0 -88.202499451857 179.981022032992859592
- * 89.262080389218 0 -89.262080389218 179.992207982775375662
- * 89.333123580033 0 -89.333123580032997687 179.99295812360148422
- * which otherwise fail with g++ 4.4.4 x86 -O3 (Linux)
- * and g++ 4.4.0 (mingw) and g++ 4.6.1 (tdm mingw). */
- {
- volatile real xx1 = sbet2 * cbet1;
- volatile real xx2 = cbet2 * sbet1;
- sbet12a = xx1 + xx2;
- }
-#else
sbet12a = sbet2 * cbet1 + cbet2 * sbet1;
-#endif
if (shortline) {
real sbetm2 = sq(sbet1 + sbet2), omg12;
/* sin((bet1+bet2)/2)^2
@@ -1830,17 +1844,12 @@ int transit(real lon1, real lon2) {
}
int transitdirect(real lon1, real lon2) {
-#if HAVE_C99_MATH
- lon1 = remainder(lon1, (real)(720));
- lon2 = remainder(lon2, (real)(720));
+ /* Compute exactly the parity of
+ int(ceil(lon2 / 360)) - int(ceil(lon1 / 360)) */
+ lon1 = remainderx(lon1, (real)(720));
+ lon2 = remainderx(lon2, (real)(720));
return ( (lon2 <= 0 && lon2 > -360 ? 1 : 0) -
(lon1 <= 0 && lon1 > -360 ? 1 : 0) );
-#else
- lon1 = fmod(lon1, (real)(720));
- lon2 = fmod(lon2, (real)(720));
- return ( ((lon2 <= 0 && lon2 > -360) || lon2 > 360 ? 1 : 0) -
- ((lon1 <= 0 && lon1 > -360) || lon1 > 360 ? 1 : 0) );
-#endif
}
void accini(real s[]) {
@@ -1876,6 +1885,12 @@ void accneg(real s[]) {
s[0] = -s[0]; s[1] = -s[1];
}
+void accrem(real s[], real y) {
+ /* Reduce to [-y/2, y/2]. */
+ s[0] = remainderx(s[0], y);
+ accadd(s, (real)(0));
+}
+
void geod_polygon_init(struct geod_polygon* p, boolx polylinep) {
p->polyline = (polylinep != 0);
geod_polygon_clear(p);
@@ -1898,7 +1913,8 @@ void geod_polygon_addpoint(const struct geod_geodesic* g,
} else {
real s12, S12 = 0; /* Initialize S12 to stop Visual Studio warning */
geod_geninverse(g, p->lat, p->lon, lat, lon,
- &s12, nullptr, nullptr, nullptr, nullptr, nullptr, p->polyline ? nullptr : &S12);
+ &s12, nullptr, nullptr, nullptr, nullptr, nullptr,
+ p->polyline ? nullptr : &S12);
accadd(p->P, s12);
if (!p->polyline) {
accadd(p->A, S12);
@@ -1918,7 +1934,8 @@ void geod_polygon_addedge(const struct geod_geodesic* g,
real lat = 0, lon = 0, S12 = 0;
geod_gendirect(g, p->lat, p->lon, azi, GEOD_LONG_UNROLL, s,
&lat, &lon, nullptr,
- nullptr, nullptr, nullptr, nullptr, p->polyline ? nullptr : &S12);
+ nullptr, nullptr, nullptr, nullptr,
+ p->polyline ? nullptr : &S12);
accadd(p->P, s);
if (!p->polyline) {
accadd(p->A, S12);
@@ -1933,8 +1950,7 @@ unsigned geod_polygon_compute(const struct geod_geodesic* g,
const struct geod_polygon* p,
boolx reverse, boolx sign,
real* pA, real* pP) {
- real s12, S12, t[2], area0;
- int crossings;
+ real s12, S12, t[2];
if (p->num < 2) {
if (pP) *pP = 0;
if (!p->polyline && pA) *pA = 0;
@@ -1949,27 +1965,9 @@ unsigned geod_polygon_compute(const struct geod_geodesic* g,
if (pP) *pP = accsum(p->P, s12);
acccopy(p->A, t);
accadd(t, S12);
- crossings = p->crossings + transit(p->lon, p->lon0);
- area0 = 4 * pi * g->c2;
- if (crossings & 1)
- accadd(t, (t[0] < 0 ? 1 : -1) * area0/2);
- /* area is with the clockwise sense. If !reverse convert to
- * counter-clockwise convention. */
- if (!reverse)
- accneg(t);
- /* If sign put area in (-area0/2, area0/2], else put area in [0, area0) */
- if (sign) {
- if (t[0] > area0/2)
- accadd(t, -area0);
- else if (t[0] <= -area0/2)
- accadd(t, +area0);
- } else {
- if (t[0] >= area0)
- accadd(t, -area0);
- else if (t[0] < 0)
- accadd(t, +area0);
- }
- if (pA) *pA = 0 + t[0];
+ if (pA) *pA = areareduceA(t, 4 * pi * g->c2,
+ p->crossings + transit(p->lon, p->lon0),
+ reverse, sign);
return p->num;
}
@@ -1978,7 +1976,7 @@ unsigned geod_polygon_testpoint(const struct geod_geodesic* g,
real lat, real lon,
boolx reverse, boolx sign,
real* pA, real* pP) {
- real perimeter, tempsum, area0;
+ real perimeter, tempsum;
int crossings, i;
unsigned num = p->num + 1;
if (num == 1) {
@@ -1994,7 +1992,8 @@ unsigned geod_polygon_testpoint(const struct geod_geodesic* g,
geod_geninverse(g,
i == 0 ? p->lat : lat, i == 0 ? p->lon : lon,
i != 0 ? p->lat0 : lat, i != 0 ? p->lon0 : lon,
- &s12, nullptr, nullptr, nullptr, nullptr, nullptr, p->polyline ? nullptr : &S12);
+ &s12, nullptr, nullptr, nullptr, nullptr, nullptr,
+ p->polyline ? nullptr : &S12);
perimeter += s12;
if (!p->polyline) {
tempsum += S12;
@@ -2007,26 +2006,7 @@ unsigned geod_polygon_testpoint(const struct geod_geodesic* g,
if (p->polyline)
return num;
- area0 = 4 * pi * g->c2;
- if (crossings & 1)
- tempsum += (tempsum < 0 ? 1 : -1) * area0/2;
- /* area is with the clockwise sense. If !reverse convert to
- * counter-clockwise convention. */
- if (!reverse)
- tempsum *= -1;
- /* If sign put area in (-area0/2, area0/2], else put area in [0, area0) */
- if (sign) {
- if (tempsum > area0/2)
- tempsum -= area0;
- else if (tempsum <= -area0/2)
- tempsum += area0;
- } else {
- if (tempsum >= area0)
- tempsum -= area0;
- else if (tempsum < 0)
- tempsum += area0;
- }
- if (pA) *pA = 0 + tempsum;
+ if (pA) *pA = areareduceB(tempsum, 4 * pi * g->c2, crossings, reverse, sign);
return num;
}
@@ -2035,7 +2015,7 @@ unsigned geod_polygon_testedge(const struct geod_geodesic* g,
real azi, real s,
boolx reverse, boolx sign,
real* pA, real* pP) {
- real perimeter, tempsum, area0;
+ real perimeter, tempsum;
int crossings;
unsigned num = p->num + 1;
if (num == 1) { /* we don't have a starting point! */
@@ -2053,7 +2033,7 @@ unsigned geod_polygon_testedge(const struct geod_geodesic* g,
crossings = p->crossings;
{
/* Initialization of lat, lon, and S12 is to make CLang static analyzer
- happy. */
+ * happy. */
real lat = 0, lon = 0, s12, S12 = 0;
geod_gendirect(g, p->lat, p->lon, azi, GEOD_LONG_UNROLL, s,
&lat, &lon, nullptr,
@@ -2067,27 +2047,8 @@ unsigned geod_polygon_testedge(const struct geod_geodesic* g,
crossings += transit(lon, p->lon0);
}
- area0 = 4 * pi * g->c2;
- if (crossings & 1)
- tempsum += (tempsum < 0 ? 1 : -1) * area0/2;
- /* area is with the clockwise sense. If !reverse convert to
- * counter-clockwise convention. */
- if (!reverse)
- tempsum *= -1;
- /* If sign put area in (-area0/2, area0/2], else put area in [0, area0) */
- if (sign) {
- if (tempsum > area0/2)
- tempsum -= area0;
- else if (tempsum <= -area0/2)
- tempsum += area0;
- } else {
- if (tempsum >= area0)
- tempsum -= area0;
- else if (tempsum < 0)
- tempsum += area0;
- }
if (pP) *pP = perimeter;
- if (pA) *pA = 0 + tempsum;
+ if (pA) *pA = areareduceB(tempsum, 4 * pi * g->c2, crossings, reverse, sign);
return num;
}
@@ -2102,4 +2063,52 @@ void geod_polygonarea(const struct geod_geodesic* g,
geod_polygon_compute(g, &p, FALSE, TRUE, pA, pP);
}
+real areareduceA(real area[], real area0,
+ int crossings, boolx reverse, boolx sign) {
+ accrem(area, area0);
+ if (crossings & 1)
+ accadd(area, (area[0] < 0 ? 1 : -1) * area0/2);
+ /* area is with the clockwise sense. If !reverse convert to
+ * counter-clockwise convention. */
+ if (!reverse)
+ accneg(area);
+ /* If sign put area in (-area0/2, area0/2], else put area in [0, area0) */
+ if (sign) {
+ if (area[0] > area0/2)
+ accadd(area, -area0);
+ else if (area[0] <= -area0/2)
+ accadd(area, +area0);
+ } else {
+ if (area[0] >= area0)
+ accadd(area, -area0);
+ else if (area[0] < 0)
+ accadd(area, +area0);
+ }
+ return 0 + area[0];
+}
+
+real areareduceB(real area, real area0,
+ int crossings, boolx reverse, boolx sign) {
+ area = remainderx(area, area0);
+ if (crossings & 1)
+ area += (area < 0 ? 1 : -1) * area0/2;
+ /* area is with the clockwise sense. If !reverse convert to
+ * counter-clockwise convention. */
+ if (!reverse)
+ area *= -1;
+ /* If sign put area in (-area0/2, area0/2], else put area in [0, area0) */
+ if (sign) {
+ if (area > area0/2)
+ area -= area0;
+ else if (area <= -area0/2)
+ area += area0;
+ } else {
+ if (area >= area0)
+ area -= area0;
+ else if (area < 0)
+ area += area0;
+ }
+ return 0 + area;
+}
+
/** @endcond */
diff --git a/src/geodesic.h b/src/geodesic.h
index 11484ec7..5d230531 100644
--- a/src/geodesic.h
+++ b/src/geodesic.h
@@ -107,12 +107,12 @@
* twice about restructuring the internals of the C code since this may make
* porting fixes from the C++ code more difficult.
*
- * Copyright (c) Charles Karney (2012-2018) <charles@karney.com> and licensed
+ * Copyright (c) Charles Karney (2012-2019) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
*
* This library was distributed with
- * <a href="../index.html">GeographicLib</a> 1.49.
+ * <a href="../index.html">GeographicLib</a> 1.50.
**********************************************************************/
#if !defined(GEODESIC_H)
@@ -127,12 +127,12 @@
* The minor version of the geodesic library. (This tracks the version of
* GeographicLib.)
**********************************************************************/
-#define GEODESIC_VERSION_MINOR 49
+#define GEODESIC_VERSION_MINOR 50
/**
* The patch level of the geodesic library. (This tracks the version of
* GeographicLib.)
**********************************************************************/
-#define GEODESIC_VERSION_PATCH 3
+#define GEODESIC_VERSION_PATCH 0
/**
* Pack the version components into a single integer. Users should not rely on
@@ -157,7 +157,7 @@
GEODESIC_VERSION_MINOR, \
GEODESIC_VERSION_PATCH)
-#ifndef GEOD_DLL
+#if !defined(GEOD_DLL)
#if defined(_MSC_VER)
#define GEOD_DLL __declspec(dllexport)
#elif defined(__GNUC__)
@@ -167,7 +167,7 @@
#endif
#endif
-#ifdef PROJ_RENAME_SYMBOLS
+#if defined(PROJ_RENAME_SYMBOLS)
#include "proj_symbol_rename.h"
#endif
@@ -277,8 +277,8 @@ extern "C" {
@endcode
**********************************************************************/
void GEOD_DLL geod_direct(const struct geod_geodesic* g,
- double lat1, double lon1, double azi1, double s12,
- double* plat2, double* plon2, double* pazi2);
+ double lat1, double lon1, double azi1, double s12,
+ double* plat2, double* plon2, double* pazi2);
/**
* The general direct geodesic problem.
@@ -319,11 +319,12 @@ extern "C" {
* what sense the geodesic encircles the ellipsoid.
**********************************************************************/
double GEOD_DLL geod_gendirect(const struct geod_geodesic* g,
- double lat1, double lon1, double azi1,
- unsigned flags, double s12_a12,
- double* plat2, double* plon2, double* pazi2,
- double* ps12, double* pm12, double* pM12, double* pM21,
- double* pS12);
+ double lat1, double lon1, double azi1,
+ unsigned flags, double s12_a12,
+ double* plat2, double* plon2, double* pazi2,
+ double* ps12, double* pm12,
+ double* pM12, double* pM21,
+ double* pS12);
/**
* Solve the inverse geodesic problem.
@@ -364,8 +365,9 @@ extern "C" {
@endcode
**********************************************************************/
void GEOD_DLL geod_inverse(const struct geod_geodesic* g,
- double lat1, double lon1, double lat2, double lon2,
- double* ps12, double* pazi1, double* pazi2);
+ double lat1, double lon1,
+ double lat2, double lon2,
+ double* ps12, double* pazi1, double* pazi2);
/**
* The general inverse geodesic calculation.
@@ -395,10 +397,11 @@ extern "C" {
* some quantities computed.
**********************************************************************/
double GEOD_DLL geod_geninverse(const struct geod_geodesic* g,
- double lat1, double lon1, double lat2, double lon2,
- double* ps12, double* pazi1, double* pazi2,
- double* pm12, double* pM12, double* pM21,
- double* pS12);
+ double lat1, double lon1,
+ double lat2, double lon2,
+ double* ps12, double* pazi1, double* pazi2,
+ double* pm12, double* pM12, double* pM21,
+ double* pS12);
/**
* Initialize a geod_geodesicline object.
@@ -440,8 +443,9 @@ extern "C" {
* NaN).
**********************************************************************/
void GEOD_DLL geod_lineinit(struct geod_geodesicline* l,
- const struct geod_geodesic* g,
- double lat1, double lon1, double azi1, unsigned caps);
+ const struct geod_geodesic* g,
+ double lat1, double lon1, double azi1,
+ unsigned caps);
/**
* Initialize a geod_geodesicline object in terms of the direct geodesic
@@ -465,9 +469,10 @@ extern "C" {
* information.
**********************************************************************/
void GEOD_DLL geod_directline(struct geod_geodesicline* l,
- const struct geod_geodesic* g,
- double lat1, double lon1, double azi1, double s12,
- unsigned caps);
+ const struct geod_geodesic* g,
+ double lat1, double lon1,
+ double azi1, double s12,
+ unsigned caps);
/**
* Initialize a geod_geodesicline object in terms of the direct geodesic
@@ -495,10 +500,10 @@ extern "C" {
* information.
**********************************************************************/
void GEOD_DLL geod_gendirectline(struct geod_geodesicline* l,
- const struct geod_geodesic* g,
- double lat1, double lon1, double azi1,
- unsigned flags, double s12_a12,
- unsigned caps);
+ const struct geod_geodesic* g,
+ double lat1, double lon1, double azi1,
+ unsigned flags, double s12_a12,
+ unsigned caps);
/**
* Initialize a geod_geodesicline object in terms of the inverse geodesic
@@ -521,9 +526,10 @@ extern "C" {
* information.
**********************************************************************/
void GEOD_DLL geod_inverseline(struct geod_geodesicline* l,
- const struct geod_geodesic* g,
- double lat1, double lon1, double lat2, double lon2,
- unsigned caps);
+ const struct geod_geodesic* g,
+ double lat1, double lon1,
+ double lat2, double lon2,
+ unsigned caps);
/**
* Compute the position along a geod_geodesicline.
@@ -538,9 +544,9 @@ extern "C" {
* @param[out] pazi2 pointer to the (forward) azimuth at point 2 (degrees).
*
* \e l must have been initialized with a call, e.g., to geod_lineinit(),
- * with \e caps |= GEOD_DISTANCE_IN. The values of \e lon2 and \e azi2
- * returned are in the range [&minus;180&deg;, 180&deg;]. Any of the
- * "return" arguments \e plat2, etc., may be replaced by 0, if you do not
+ * with \e caps |= GEOD_DISTANCE_IN (or \e caps = 0). The values of \e lon2
+ * and \e azi2 returned are in the range [&minus;180&deg;, 180&deg;]. Any of
+ * the "return" arguments \e plat2, etc., may be replaced by 0, if you do not
* need some quantities computed.
*
* Example, compute way points between JFK and Singapore Changi Airport
@@ -571,7 +577,7 @@ extern "C" {
@endcode
**********************************************************************/
void GEOD_DLL geod_position(const struct geod_geodesicline* l, double s12,
- double* plat2, double* plon2, double* pazi2);
+ double* plat2, double* plon2, double* pazi2);
/**
* The general position function.
@@ -638,11 +644,11 @@ extern "C" {
@endcode
**********************************************************************/
double GEOD_DLL geod_genposition(const struct geod_geodesicline* l,
- unsigned flags, double s12_a12,
- double* plat2, double* plon2, double* pazi2,
- double* ps12, double* pm12,
- double* pM12, double* pM21,
- double* pS12);
+ unsigned flags, double s12_a12,
+ double* plat2, double* plon2, double* pazi2,
+ double* ps12, double* pm12,
+ double* pM12, double* pM21,
+ double* pS12);
/**
* Specify position of point 3 in terms of distance.
@@ -672,7 +678,7 @@ extern "C" {
* been constructed with \e caps |= GEOD_DISTANCE.
**********************************************************************/
void GEOD_DLL geod_gensetdistance(struct geod_geodesicline* l,
- unsigned flags, double s13_a13);
+ unsigned flags, double s13_a13);
/**
* Initialize a geod_polygon object.
@@ -721,8 +727,8 @@ extern "C" {
* geod_polygon_compute().
**********************************************************************/
void GEOD_DLL geod_polygon_addpoint(const struct geod_geodesic* g,
- struct geod_polygon* p,
- double lat, double lon);
+ struct geod_polygon* p,
+ double lat, double lon);
/**
* Add an edge to the polygon or polyline.
@@ -741,8 +747,8 @@ extern "C" {
* new vertex.
**********************************************************************/
void GEOD_DLL geod_polygon_addedge(const struct geod_geodesic* g,
- struct geod_polygon* p,
- double azi, double s);
+ struct geod_polygon* p,
+ double azi, double s);
/**
* Return the results for a polygon.
@@ -763,10 +769,12 @@ extern "C" {
*
* The area and perimeter are accumulated at two times the standard floating
* point precision to guard against the loss of accuracy with many-sided
- * polygons. Only simple polygons (which are not self-intersecting) are
- * allowed. There's no need to "close" the polygon by repeating the first
- * vertex. Set \e pA or \e pP to zero, if you do not want the corresponding
- * quantity returned.
+ * polygons. Arbitrarily complex polygons are allowed. In the case of
+ * self-intersecting polygons the area is accumulated "algebraically", e.g.,
+ * the areas of the 2 loops in a figure-8 polygon will partially cancel.
+ * There's no need to "close" the polygon by repeating the first vertex. Set
+ * \e pA or \e pP to zero, if you do not want the corresponding quantity
+ * returned.
*
* More points can be added to the polygon after this call.
*
@@ -788,9 +796,9 @@ extern "C" {
@endcode
**********************************************************************/
unsigned GEOD_DLL geod_polygon_compute(const struct geod_geodesic* g,
- const struct geod_polygon* p,
- int reverse, int sign,
- double* pA, double* pP);
+ const struct geod_polygon* p,
+ int reverse, int sign,
+ double* pA, double* pP);
/**
* Return the results assuming a tentative final test point is added;
@@ -819,10 +827,10 @@ extern "C" {
* \e lat should be in the range [&minus;90&deg;, 90&deg;].
**********************************************************************/
unsigned GEOD_DLL geod_polygon_testpoint(const struct geod_geodesic* g,
- const struct geod_polygon* p,
- double lat, double lon,
- int reverse, int sign,
- double* pA, double* pP);
+ const struct geod_polygon* p,
+ double lat, double lon,
+ int reverse, int sign,
+ double* pA, double* pP);
/**
* Return the results assuming a tentative final test point is added via an
@@ -850,10 +858,10 @@ extern "C" {
* @return the number of points.
**********************************************************************/
unsigned GEOD_DLL geod_polygon_testedge(const struct geod_geodesic* g,
- const struct geod_polygon* p,
- double azi, double s,
- int reverse, int sign,
- double* pA, double* pP);
+ const struct geod_polygon* p,
+ double azi, double s,
+ int reverse, int sign,
+ double* pA, double* pP);
/**
* A simple interface for computing the area of a geodesic polygon.
@@ -868,10 +876,11 @@ extern "C" {
*
* \e lats should be in the range [&minus;90&deg;, 90&deg;].
*
- * Only simple polygons (which are not self-intersecting) are allowed.
- * There's no need to "close" the polygon by repeating the first vertex. The
- * area returned is signed with counter-clockwise traversal being treated as
- * positive.
+ * Arbitrarily complex polygons are allowed. In the case self-intersecting
+ * of polygons the area is accumulated "algebraically", e.g., the areas of
+ * the 2 loops in a figure-8 polygon will partially cancel. There's no need
+ * to "close" the polygon by repeating the first vertex. The area returned
+ * is signed with counter-clockwise traversal being treated as positive.
*
* Example, compute the area of Antarctica:
@code{.c}
@@ -888,8 +897,8 @@ extern "C" {
@endcode
**********************************************************************/
void GEOD_DLL geod_polygonarea(const struct geod_geodesic* g,
- double lats[], double lons[], int n,
- double* pA, double* pP);
+ double lats[], double lons[], int n,
+ double* pA, double* pP);
/**
* mask values for the \e caps argument to geod_lineinit().
diff --git a/src/pipeline.cpp b/src/pipeline.cpp
index afa3b19a..a82fce31 100644
--- a/src/pipeline.cpp
+++ b/src/pipeline.cpp
@@ -330,7 +330,7 @@ static void set_ellipsoid(PJ *P) {
pj_calc_ellipsoid_params (P, P->a, P->es);
- geod_init(P->geod, P->a, (1 - sqrt (1 - P->es)));
+ geod_init(P->geod, P->a, P->es / (1 + sqrt(P->one_es)));
/* Re-attach the dangling list */
/* Note: cur will always be non 0 given argv_sentinel presence, */
diff --git a/src/tests/geodtest.cpp b/src/tests/geodtest.cpp
index 6b3ea8b2..097682ac 100644
--- a/src/tests/geodtest.cpp
+++ b/src/tests/geodtest.cpp
@@ -4,7 +4,7 @@
*
* Run these tests by configuring with cmake and running "make test".
*
- * Copyright (c) Charles Karney (2015-2018) <charles@karney.com> and licensed
+ * Copyright (c) Charles Karney (2015-2019) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* https://geographiclib.sourceforge.io/
**********************************************************************/
@@ -20,6 +20,10 @@
# pragma warning (disable: 4706)
#endif
+#if !defined(__cplusplus)
+#define nullptr 0
+#endif
+
static const double wgs84_a = 6378137, wgs84_f = 1/298.257223563; /* WGS84 */
static int checkEquals(double x, double y, double d) {
@@ -30,6 +34,7 @@ static int checkEquals(double x, double y, double d) {
}
static int checkNaN(double x) {
+ /* cppcheck-suppress duplicateExpression */
if (x != x)
return 0;
printf("checkNaN fails: %.7g\n", x);
@@ -157,8 +162,7 @@ static int testdirect() {
s12 = testcases[i][6]; a12 = testcases[i][7]; m12 = testcases[i][8];
M12 = testcases[i][9]; M21 = testcases[i][10]; S12 = testcases[i][11];
a12a = geod_gendirect(&g, lat1, lon1, azi1, flags, s12,
- &lat2a, &lon2a, &azi2a, nullptr,
- &m12a, &M12a, &M21a, &S12a);
+ &lat2a, &lon2a, &azi2a, nullptr, &m12a, &M12a, &M21a, &S12a);
result += checkEquals(lat2, lat2a, 1e-13);
result += checkEquals(lon2, lon2a, 1e-13);
result += checkEquals(azi2, azi2a, 1e-13);
@@ -277,13 +281,16 @@ static int GeodSolve6() {
int result = 0;
geod_init(&g, wgs84_a, wgs84_f);
geod_inverse(&g, 88.202499451857, 0,
- -88.202499451857, 179.981022032992859592, &s12, nullptr, nullptr);
+ -88.202499451857, 179.981022032992859592,
+ &s12, nullptr, nullptr);
result += checkEquals(s12, 20003898.214, 0.5e-3);
geod_inverse(&g, 89.262080389218, 0,
- -89.262080389218, 179.992207982775375662, &s12, nullptr, nullptr);
+ -89.262080389218, 179.992207982775375662,
+ &s12, nullptr, nullptr);
result += checkEquals(s12, 20003925.854, 0.5e-3);
geod_inverse(&g, 89.333123580033, 0,
- -89.333123580032997687, 179.99295812360148422, &s12, nullptr, nullptr);
+ -89.333123580032997687, 179.99295812360148422,
+ &s12, nullptr, nullptr);
result += checkEquals(s12, 20003926.881, 0.5e-3);
return result;
}
@@ -295,7 +302,8 @@ static int GeodSolve9() {
int result = 0;
geod_init(&g, wgs84_a, wgs84_f);
geod_inverse(&g, 56.320923501171, 0,
- -56.320923501171, 179.664747671772880215, &s12, nullptr, nullptr);
+ -56.320923501171, 179.664747671772880215,
+ &s12, nullptr, nullptr);
result += checkEquals(s12, 19993558.287, 0.5e-3);
return result;
}
@@ -308,7 +316,8 @@ static int GeodSolve10() {
int result = 0;
geod_init(&g, wgs84_a, wgs84_f);
geod_inverse(&g, 52.784459512564, 0,
- -52.784459512563990912, 179.634407464943777557, &s12, nullptr, nullptr);
+ -52.784459512563990912, 179.634407464943777557,
+ &s12, nullptr, nullptr);
result += checkEquals(s12, 19991596.095, 0.5e-3);
return result;
}
@@ -321,7 +330,8 @@ static int GeodSolve11() {
int result = 0;
geod_init(&g, wgs84_a, wgs84_f);
geod_inverse(&g, 48.522876735459, 0,
- -48.52287673545898293, 179.599720456223079643, &s12, nullptr, nullptr);
+ -48.52287673545898293, 179.599720456223079643,
+ &s12, nullptr, nullptr);
result += checkEquals(s12, 19989144.774, 0.5e-3);
return result;
}
@@ -366,8 +376,8 @@ static int GeodSolve15() {
struct geod_geodesic g;
int result = 0;
geod_init(&g, 6.4e6, -1/150.0);
- geod_gendirect(&g, 1, 2, 3, 0, 4,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &S12);
+ geod_gendirect(&g, 1, 2, 3, 0, 4, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, &S12);
result += checkEquals(S12, 23700, 0.5);
return result;
}
@@ -380,13 +390,14 @@ static int GeodSolve17() {
int result = 0;
unsigned flags = GEOD_LONG_UNROLL;
geod_init(&g, wgs84_a, wgs84_f);
- geod_gendirect(&g, 40, -75, -10, flags, 2e7,
- &lat2, &lon2, &azi2, nullptr, nullptr, nullptr, nullptr, nullptr);
+ geod_gendirect(&g, 40, -75, -10, flags, 2e7, &lat2, &lon2, &azi2,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
result += checkEquals(lat2, -39, 1);
result += checkEquals(lon2, -254, 1);
result += checkEquals(azi2, -170, 1);
geod_lineinit(&l, &g, 40, -75, -10, 0);
- geod_genposition(&l, flags, 2e7, &lat2, &lon2, &azi2, nullptr, nullptr, nullptr, nullptr, nullptr);
+ geod_genposition(&l, flags, 2e7, &lat2, &lon2, &azi2,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
result += checkEquals(lat2, -39, 1);
result += checkEquals(lon2, -254, 1);
result += checkEquals(azi2, -170, 1);
@@ -407,7 +418,8 @@ static int GeodSolve26() {
struct geod_geodesic g;
int result = 0;
geod_init(&g, 6.4e6, 0);
- geod_geninverse(&g, 1, 2, 3, 4, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &S12);
+ geod_geninverse(&g, 1, 2, 3, 4, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, &S12);
result += checkEquals(S12, 49911046115.0, 0.5);
return result;
}
@@ -419,7 +431,8 @@ static int GeodSolve28() {
struct geod_geodesic g;
int result = 0;
geod_init(&g, 6.4e6, 0.1);
- a12 = geod_gendirect(&g, 1, 2, 10, 0, 5e6, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ a12 = geod_gendirect(&g, 1, 2, 10, 0, 5e6, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
result += checkEquals(a12, 48.55570690, 0.5e-8);
return result;
}
@@ -527,12 +540,14 @@ static int GeodSolve61() {
unsigned flags = GEOD_LONG_UNROLL;
geod_init(&g, wgs84_a, wgs84_f);
geod_gendirect(&g, 45, 0, -0.000000000000000003, flags, 1e7,
- &lat2, &lon2, &azi2, nullptr, nullptr, nullptr, nullptr, nullptr);
+ &lat2, &lon2, &azi2,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
result += checkEquals(lat2, 45.30632, 0.5e-5);
result += checkEquals(lon2, -180, 0.5e-5);
result += checkEquals(fabs(azi2), 180, 0.5e-5);
geod_inverseline(&l, &g, 45, 0, 80, -0.000000000000000003, 0);
- geod_genposition(&l, flags, 1e7, &lat2, &lon2, &azi2, nullptr, nullptr, nullptr, nullptr, nullptr);
+ geod_genposition(&l, flags, 1e7, &lat2, &lon2, &azi2,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
result += checkEquals(lat2, 45.30632, 0.5e-5);
result += checkEquals(lon2, -180, 0.5e-5);
result += checkEquals(fabs(azi2), 180, 0.5e-5);
@@ -577,7 +592,7 @@ static int GeodSolve65() {
static int GeodSolve67() {
/* Check for InverseLine if line is slightly west of S and that s13 is
- correctly set. */
+ * correctly set. */
double lat2, lon2, azi2;
struct geod_geodesic g;
struct geod_geodesicline l;
@@ -585,11 +600,13 @@ static int GeodSolve67() {
unsigned flags = GEOD_LONG_UNROLL;
geod_init(&g, wgs84_a, wgs84_f);
geod_inverseline(&l, &g, -5, -0.000000000000002, -10, 180, 0);
- geod_genposition(&l, flags, 2e7, &lat2, &lon2, &azi2, nullptr, nullptr, nullptr, nullptr, nullptr);
+ geod_genposition(&l, flags, 2e7, &lat2, &lon2, &azi2,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
result += checkEquals(lat2, 4.96445, 0.5e-5);
result += checkEquals(lon2, -180.00000, 0.5e-5);
result += checkEquals(azi2, -0.00000, 0.5e-5);
- geod_genposition(&l, flags, 0.5 * l.s13, &lat2, &lon2, &azi2, nullptr, nullptr, nullptr, nullptr, nullptr);
+ geod_genposition(&l, flags, 0.5 * l.s13, &lat2, &lon2, &azi2,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
result += checkEquals(lat2, -87.52461, 0.5e-5);
result += checkEquals(lon2, -0.00000, 0.5e-5);
result += checkEquals(azi2, -180.00000, 0.5e-5);
@@ -614,7 +631,9 @@ static int GeodSolve71() {
static int GeodSolve73() {
/* Check for backwards from the pole bug reported by Anon on 2016-02-13.
* This only affected the Java implementation. It was introduced in Java
- * version 1.44 and fixed in 1.46-SNAPSHOT on 2016-01-17. */
+ * version 1.44 and fixed in 1.46-SNAPSHOT on 2016-01-17.
+ * Also the + sign on azi2 is a check on the normalizing of azimuths
+ * (converting -0.0 to +0.0). */
double lat2, lon2, azi2;
struct geod_geodesic g;
int result = 0;
@@ -652,7 +671,7 @@ static void polylength(const struct geod_geodesic* g,
static int GeodSolve74() {
/* Check fix for inaccurate areas, bug introduced in v1.46, fixed
- 2015-10-16. */
+ * 2015-10-16. */
double a12, s12, azi1, azi2, m12, M12, M21, S12;
struct geod_geodesic g;
int result = 0;
@@ -672,7 +691,7 @@ static int GeodSolve74() {
static int GeodSolve76() {
/* The distance from Wellington and Salamanca (a classic failure of
- Vincenty) */
+ * Vincenty) */
double azi1, azi2, s12;
struct geod_geodesic g;
int result = 0;
@@ -700,19 +719,24 @@ static int GeodSolve78() {
static int GeodSolve80() {
/* Some tests to add code coverage: computing scale in special cases + zero
- length geodesic (includes GeodSolve80 - GeodSolve83) + using an incapable
- line. */
+ * length geodesic (includes GeodSolve80 - GeodSolve83) + using an incapable
+ * line. */
double a12, s12, azi1, azi2, m12, M12, M21, S12;
struct geod_geodesic g;
struct geod_geodesicline l;
int result = 0;
geod_init(&g, wgs84_a, wgs84_f);
- geod_geninverse(&g, 0, 0, 0, 90, nullptr, nullptr, nullptr, nullptr, &M12, &M21, nullptr);
+
+ geod_geninverse(&g, 0, 0, 0, 90, nullptr, nullptr, nullptr,
+ nullptr, &M12, &M21, nullptr);
result += checkEquals(M12, -0.00528427534, 0.5e-10);
result += checkEquals(M21, -0.00528427534, 0.5e-10);
- geod_geninverse(&g, 0, 0, 1e-6, 1e-6, nullptr, nullptr, nullptr, nullptr, &M12, &M21, nullptr);
+
+ geod_geninverse(&g, 0, 0, 1e-6, 1e-6, nullptr, nullptr, nullptr,
+ nullptr, &M12, &M21, nullptr);
result += checkEquals(M12, 1, 0.5e-10);
result += checkEquals(M21, 1, 0.5e-10);
+
a12 = geod_geninverse(&g, 20.001, 0, 20.001, 0,
&s12, &azi1, &azi2, &m12, &M12, &M21, &S12);
result += checkEquals(a12, 0, 1e-13);
@@ -723,6 +747,7 @@ static int GeodSolve80() {
result += checkEquals(M12, 1, 1e-15);
result += checkEquals(M21, 1, 1e-15);
result += checkEquals(S12, 0, 1e-10);
+
a12 = geod_geninverse(&g, 90, 0, 90, 180,
&s12, &azi1, &azi2, &m12, &M12, &M21, &S12);
result += checkEquals(a12, 0, 1e-13);
@@ -732,14 +757,70 @@ static int GeodSolve80() {
result += checkEquals(m12, 0, 1e-8);
result += checkEquals(M12, 1, 1e-15);
result += checkEquals(M21, 1, 1e-15);
- result += checkEquals(S12, 127516405431022, 0.5);
+ result += checkEquals(S12, 127516405431022.0, 0.5);
+
/* An incapable line which can't take distance as input */
geod_lineinit(&l, &g, 1, 2, 90, GEOD_LATITUDE);
- a12 = geod_genposition(&l, 0, 1000, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
+ a12 = geod_genposition(&l, 0, 1000, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr);
result += checkNaN(a12);
return result;
}
+static int GeodSolve84() {
+ /* Tests for python implementation to check fix for range errors with
+ * {fmod,sin,cos}(inf) (includes GeodSolve84 - GeodSolve86). */
+
+ double lat2, lon2, azi2, inf, nan;
+ struct geod_geodesic g;
+ int result = 0;
+ geod_init(&g, wgs84_a, wgs84_f);
+ {
+ /* a round about way to set inf = 0 */
+ geod_direct(&g, 0, 0, 90, 0, &inf, nullptr, nullptr);
+ /* so that this doesn't give a compiler time error on Windows */
+ inf = 1.0/inf;
+ }
+ {
+ double minus1 = -1;
+ /* cppcheck-suppress wrongmathcall */
+ nan = sqrt(minus1);
+ }
+ geod_direct(&g, 0, 0, 90, inf, &lat2, &lon2, &azi2);
+ result += checkNaN(lat2);
+ result += checkNaN(lon2);
+ result += checkNaN(azi2);
+ geod_direct(&g, 0, 0, 90, nan, &lat2, &lon2, &azi2);
+ result += checkNaN(lat2);
+ result += checkNaN(lon2);
+ result += checkNaN(azi2);
+ geod_direct(&g, 0, 0, inf, 1000, &lat2, &lon2, &azi2);
+ result += checkNaN(lat2);
+ result += checkNaN(lon2);
+ result += checkNaN(azi2);
+ geod_direct(&g, 0, 0, nan, 1000, &lat2, &lon2, &azi2);
+ result += checkNaN(lat2);
+ result += checkNaN(lon2);
+ result += checkNaN(azi2);
+ geod_direct(&g, 0, inf, 90, 1000, &lat2, &lon2, &azi2);
+ result += lat2 == 0 ? 0 : 1;
+ result += checkNaN(lon2);
+ result += azi2 == 90 ? 0 : 1;
+ geod_direct(&g, 0, nan, 90, 1000, &lat2, &lon2, &azi2);
+ result += lat2 == 0 ? 0 : 1;
+ result += checkNaN(lon2);
+ result += azi2 == 90 ? 0 : 1;
+ geod_direct(&g, inf, 0, 90, 1000, &lat2, &lon2, &azi2);
+ result += checkNaN(lat2);
+ result += checkNaN(lon2);
+ result += checkNaN(azi2);
+ geod_direct(&g, nan, 0, 90, 1000, &lat2, &lon2, &azi2);
+ result += checkNaN(lat2);
+ result += checkNaN(lon2);
+ result += checkNaN(azi2);
+ return result;
+}
+
static int Planimeter0() {
/* Check fix for pole-encircling bug found 2011-03-16 */
double pa[4][2] = {{89, 0}, {89, 90}, {89, 180}, {89, 270}};
@@ -841,7 +922,7 @@ static int Planimeter13() {
static int Planimeter15() {
/* Coverage tests, includes Planimeter15 - Planimeter18 (combinations of
- reverse and sign) + calls to testpoint, testedge, geod_polygonarea. */
+ * reverse and sign) + calls to testpoint, testedge, geod_polygonarea. */
struct geod_geodesic g;
struct geod_polygon p;
double lat[] = {2, 1, 3}, lon[] = {1, 2, 3};
@@ -886,7 +967,7 @@ static int Planimeter15() {
static int Planimeter19() {
/* Coverage tests, includes Planimeter19 - Planimeter20 (degenerate
- polygons) + extra cases. */
+ * polygons) + extra cases. */
struct geod_geodesic g;
struct geod_polygon p;
double area, perim;
@@ -916,16 +997,17 @@ static int Planimeter19() {
geod_polygon_addpoint(&g, &p, 1, 1);
geod_polygon_compute(&g, &p, 0, 1, nullptr, &perim);
result += perim == 0 ? 0 : 1;
+ geod_polygon_addpoint(&g, &p, 1, 1);
+ geod_polygon_testedge(&g, &p, 90, 1000, 0, 1, nullptr, &perim);
+ result += checkEquals(perim, 1000, 1e-10);
+ geod_polygon_testpoint(&g, &p, 2, 2, 0, 1, nullptr, &perim);
+ result += checkEquals(perim, 156876.149, 0.5e-3);
return result;
}
static int Planimeter21() {
/* Some test to add code coverage: multiple circlings of pole (includes
- Planimeter21 - Planimeter28) + invocations via testpoint and testedge.
- Some of the results for i = 4 in the loop are wrong because we don't
- reduce the area to the allowed range correctly. However these cases are
- not "simple" polygons, so we'll defer fixing the problem for now.
- */
+ * Planimeter21 - Planimeter28) + invocations via testpoint and testedge. */
struct geod_geodesic g;
struct geod_polygon p;
double area, lat = 45,
@@ -945,35 +1027,35 @@ static int Planimeter21() {
geod_polygon_addpoint(&g, &p, lat, 60);
geod_polygon_addpoint(&g, &p, lat, 180);
geod_polygon_testpoint(&g, &p, lat, -60, 0, 1, &area, nullptr);
- if (i != 4) result += checkEquals(area, i*r, 0.5);
+ result += checkEquals(area, i*r, 0.5);
geod_polygon_testpoint(&g, &p, lat, -60, 0, 0, &area, nullptr);
- if (i != 4) result += checkEquals(area, i*r, 0.5);
+ result += checkEquals(area, i*r, 0.5);
geod_polygon_testpoint(&g, &p, lat, -60, 1, 1, &area, nullptr);
- if (i != 4) result += checkEquals(area, -i*r, 0.5);
+ result += checkEquals(area, -i*r, 0.5);
geod_polygon_testpoint(&g, &p, lat, -60, 1, 0, &area, nullptr);
result += checkEquals(area, -i*r + a0, 0.5);
geod_polygon_testedge(&g, &p, a, s, 0, 1, &area, nullptr);
- if (i != 4) result += checkEquals(area, i*r, 0.5);
+ result += checkEquals(area, i*r, 0.5);
geod_polygon_testedge(&g, &p, a, s, 0, 0, &area, nullptr);
- if (i != 4) result += checkEquals(area, i*r, 0.5);
+ result += checkEquals(area, i*r, 0.5);
geod_polygon_testedge(&g, &p, a, s, 1, 1, &area, nullptr);
- if (i != 4) result += checkEquals(area, -i*r, 0.5);
+ result += checkEquals(area, -i*r, 0.5);
geod_polygon_testedge(&g, &p, a, s, 1, 0, &area, nullptr);
result += checkEquals(area, -i*r + a0, 0.5);
geod_polygon_addpoint(&g, &p, lat, -60);
geod_polygon_compute(&g, &p, 0, 1, &area, nullptr);
- if (i != 4) result += checkEquals(area, i*r, 0.5);
+ result += checkEquals(area, i*r, 0.5);
geod_polygon_compute(&g, &p, 0, 0, &area, nullptr);
- if (i != 4) result += checkEquals(area, i*r, 0.5);
+ result += checkEquals(area, i*r, 0.5);
geod_polygon_compute(&g, &p, 1, 1, &area, nullptr);
- if (i != 4) result += checkEquals(area, -i*r, 0.5);
+ result += checkEquals(area, -i*r, 0.5);
geod_polygon_compute(&g, &p, 1, 0, &area, nullptr);
result += checkEquals(area, -i*r + a0, 0.5);
}
return result;
}
-static int AddEdge1() {
+static int Planimeter29() {
/* Check fix to transitdirect vs transit zero handling inconsistency */
struct geod_geodesic g;
struct geod_polygon p;
@@ -986,41 +1068,12 @@ static int AddEdge1() {
geod_polygon_addedge(&g, &p, 0, 1000);
geod_polygon_addedge(&g, &p, -90, 1000);
geod_polygon_compute(&g, &p, 0, 1, &area, nullptr);
+ /* The area should be 1e6. Prior to the fix it was 1e6 - A/2, where
+ * A = ellipsoid area. */
result += checkEquals(area, 1000000.0, 0.01);
return result;
}
-static int EmptyPoly() {
- struct geod_geodesic g;
- struct geod_polygon p;
- double perim, area;
- int result = 0;
- geod_init(&g, wgs84_a, wgs84_f);
- geod_polygon_init(&p, 0);
- geod_polygon_testpoint(&g, &p, 1, 1, 0, 1, &area, &perim);
- result += area == 0 ? 0 : 1;
- result += perim == 0 ? 0 : 1;
- geod_polygon_testedge(&g, &p, 90, 1000, 0, 1, &area, &perim);
- result += checkNaN(area);
- result += checkNaN(perim);
- geod_polygon_compute(&g, &p, 0, 1, &area, &perim);
- result += area == 0 ? 0 : 1;
- result += perim == 0 ? 0 : 1;
- geod_polygon_init(&p, 1);
- geod_polygon_testpoint(&g, &p, 1, 1, 0, 1, nullptr, &perim);
- result += perim == 0 ? 0 : 1;
- geod_polygon_testedge(&g, &p, 90, 1000, 0, 1, nullptr, &perim);
- result += checkNaN(perim);
- geod_polygon_compute(&g, &p, 0, 1, nullptr, &perim);
- result += perim == 0 ? 0 : 1;
- geod_polygon_addpoint(&g, &p, 1, 1);
- geod_polygon_testedge(&g, &p, 90, 1000, 0, 1, nullptr, &perim);
- result += checkEquals(perim, 1000, 1e-10);
- geod_polygon_testpoint(&g, &p, 2, 2, 0, 1, nullptr, &perim);
- result += checkEquals(perim, 156876.149, 0.5e-3);
- return result;
-}
-
int main() {
int n = 0, i;
if ((i = testinverse())) {++n; printf("testinverse fail: %d\n", i);}
@@ -1053,6 +1106,7 @@ int main() {
if ((i = GeodSolve76())) {++n; printf("GeodSolve76 fail: %d\n", i);}
if ((i = GeodSolve78())) {++n; printf("GeodSolve78 fail: %d\n", i);}
if ((i = GeodSolve80())) {++n; printf("GeodSolve80 fail: %d\n", i);}
+ if ((i = GeodSolve84())) {++n; printf("GeodSolve84 fail: %d\n", i);}
if ((i = Planimeter0())) {++n; printf("Planimeter0 fail: %d\n", i);}
if ((i = Planimeter5())) {++n; printf("Planimeter5 fail: %d\n", i);}
if ((i = Planimeter6())) {++n; printf("Planimeter6 fail: %d\n", i);}
@@ -1061,8 +1115,7 @@ int main() {
if ((i = Planimeter15())) {++n; printf("Planimeter15 fail: %d\n", i);}
if ((i = Planimeter19())) {++n; printf("Planimeter19 fail: %d\n", i);}
if ((i = Planimeter21())) {++n; printf("Planimeter21 fail: %d\n", i);}
- if ((i = AddEdge1())) {++n; printf("AddEdge1 fail: %d\n", i);}
- if ((i = EmptyPoly())) {++n; printf("EmptyPoly fail: %d\n", i);}
+ if ((i = Planimeter29())) {++n; printf("Planimeter29 fail: %d\n", i);}
return n;
}