aboutsummaryrefslogtreecommitdiff
path: root/src/projections/igh.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/projections/igh.cpp')
-rw-r--r--src/projections/igh.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/projections/igh.cpp b/src/projections/igh.cpp
new file mode 100644
index 00000000..e3576861
--- /dev/null
+++ b/src/projections/igh.cpp
@@ -0,0 +1,227 @@
+#define PJ_LIB__
+
+#include <errno.h>
+#include <math.h>
+
+#include "projects.h"
+
+PROJ_HEAD(igh, "Interrupted Goode Homolosine") "\n\tPCyl, Sph";
+
+C_NAMESPACE PJ *pj_sinu(PJ *), *pj_moll(PJ *);
+
+/* 40d 44' 11.8" [degrees] */
+/*
+static const double d4044118 = (40 + 44/60. + 11.8/3600.) * DEG_TO_RAD;
+has been replaced by this define, to eliminate portability issue:
+Initializer element not computable at load time
+*/
+#define d4044118 ((40 + 44/60. + 11.8/3600.) * DEG_TO_RAD)
+
+static const double d10 = 10 * DEG_TO_RAD;
+static const double d20 = 20 * DEG_TO_RAD;
+static const double d30 = 30 * DEG_TO_RAD;
+static const double d40 = 40 * DEG_TO_RAD;
+static const double d50 = 50 * DEG_TO_RAD;
+static const double d60 = 60 * DEG_TO_RAD;
+static const double d80 = 80 * DEG_TO_RAD;
+static const double d90 = 90 * DEG_TO_RAD;
+static const double d100 = 100 * DEG_TO_RAD;
+static const double d140 = 140 * DEG_TO_RAD;
+static const double d160 = 160 * DEG_TO_RAD;
+static const double d180 = 180 * DEG_TO_RAD;
+
+static const double EPSLN = 1.e-10; /* allow a little 'slack' on zone edge positions */
+
+namespace { // anonymous namespace
+struct pj_opaque {
+ struct PJconsts* pj[12]; \
+ double dy0;
+};
+} // anonymous namespace
+
+
+static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */
+ XY xy;
+ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque);
+ int z;
+
+ if (lp.phi >= d4044118) { /* 1|2 */
+ z = (lp.lam <= -d40 ? 1: 2);
+ }
+ else if (lp.phi >= 0) { /* 3|4 */
+ z = (lp.lam <= -d40 ? 3: 4);
+ }
+ else if (lp.phi >= -d4044118) { /* 5|6|7|8 */
+ if (lp.lam <= -d100) z = 5; /* 5 */
+ else if (lp.lam <= -d20) z = 6; /* 6 */
+ else if (lp.lam <= d80) z = 7; /* 7 */
+ else z = 8; /* 8 */
+ }
+ else { /* 9|10|11|12 */
+ if (lp.lam <= -d100) z = 9; /* 9 */
+ else if (lp.lam <= -d20) z = 10; /* 10 */
+ else if (lp.lam <= d80) z = 11; /* 11 */
+ else z = 12; /* 12 */
+ }
+
+ lp.lam -= Q->pj[z-1]->lam0;
+ xy = Q->pj[z-1]->fwd(lp, Q->pj[z-1]);
+ xy.x += Q->pj[z-1]->x0;
+ xy.y += Q->pj[z-1]->y0;
+
+ return xy;
+}
+
+
+static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */
+ LP lp = {0.0,0.0};
+ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque);
+ const double y90 = Q->dy0 + sqrt(2); /* lt=90 corresponds to y=y0+sqrt(2) */
+
+ int z = 0;
+ if (xy.y > y90+EPSLN || xy.y < -y90+EPSLN) /* 0 */
+ z = 0;
+ else if (xy.y >= d4044118) /* 1|2 */
+ z = (xy.x <= -d40? 1: 2);
+ else if (xy.y >= 0) /* 3|4 */
+ z = (xy.x <= -d40? 3: 4);
+ else if (xy.y >= -d4044118) { /* 5|6|7|8 */
+ if (xy.x <= -d100) z = 5; /* 5 */
+ else if (xy.x <= -d20) z = 6; /* 6 */
+ else if (xy.x <= d80) z = 7; /* 7 */
+ else z = 8; /* 8 */
+ }
+ else { /* 9|10|11|12 */
+ if (xy.x <= -d100) z = 9; /* 9 */
+ else if (xy.x <= -d20) z = 10; /* 10 */
+ else if (xy.x <= d80) z = 11; /* 11 */
+ else z = 12; /* 12 */
+ }
+
+ if (z) {
+ int ok = 0;
+
+ xy.x -= Q->pj[z-1]->x0;
+ xy.y -= Q->pj[z-1]->y0;
+ lp = Q->pj[z-1]->inv(xy, Q->pj[z-1]);
+ lp.lam += Q->pj[z-1]->lam0;
+
+ switch (z) {
+ case 1: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d40+EPSLN) ||
+ ((lp.lam >= -d40-EPSLN && lp.lam <= -d10+EPSLN) &&
+ (lp.phi >= d60-EPSLN && lp.phi <= d90+EPSLN)); break;
+ case 2: ok = (lp.lam >= -d40-EPSLN && lp.lam <= d180+EPSLN) ||
+ ((lp.lam >= -d180-EPSLN && lp.lam <= -d160+EPSLN) &&
+ (lp.phi >= d50-EPSLN && lp.phi <= d90+EPSLN)) ||
+ ((lp.lam >= -d50-EPSLN && lp.lam <= -d40+EPSLN) &&
+ (lp.phi >= d60-EPSLN && lp.phi <= d90+EPSLN)); break;
+ case 3: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d40+EPSLN); break;
+ case 4: ok = (lp.lam >= -d40-EPSLN && lp.lam <= d180+EPSLN); break;
+ case 5: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d100+EPSLN); break;
+ case 6: ok = (lp.lam >= -d100-EPSLN && lp.lam <= -d20+EPSLN); break;
+ case 7: ok = (lp.lam >= -d20-EPSLN && lp.lam <= d80+EPSLN); break;
+ case 8: ok = (lp.lam >= d80-EPSLN && lp.lam <= d180+EPSLN); break;
+ case 9: ok = (lp.lam >= -d180-EPSLN && lp.lam <= -d100+EPSLN); break;
+ case 10: ok = (lp.lam >= -d100-EPSLN && lp.lam <= -d20+EPSLN); break;
+ case 11: ok = (lp.lam >= -d20-EPSLN && lp.lam <= d80+EPSLN); break;
+ case 12: ok = (lp.lam >= d80-EPSLN && lp.lam <= d180+EPSLN); break;
+ }
+ z = (!ok? 0: z); /* projectable? */
+ }
+
+ if (!z) lp.lam = HUGE_VAL;
+ if (!z) lp.phi = HUGE_VAL;
+
+ return lp;
+}
+
+
+static PJ *destructor (PJ *P, int errlev) {
+ int i;
+ if (nullptr==P)
+ return nullptr;
+
+ if (nullptr==P->opaque)
+ return pj_default_destructor (P, errlev);
+
+ for (i = 0; i < 12; ++i) {
+ if (static_cast<struct pj_opaque*>(P->opaque)->pj[i])
+ static_cast<struct pj_opaque*>(P->opaque)->pj[i]->destructor(static_cast<struct pj_opaque*>(P->opaque)->pj[i], errlev);
+ }
+
+ return pj_default_destructor(P, errlev);
+}
+
+
+
+/*
+ Zones:
+
+ -180 -40 180
+ +--------------+-------------------------+ Zones 1,2,9,10,11 & 12:
+ |1 |2 | Mollweide projection
+ | | |
+ +--------------+-------------------------+ Zones 3,4,5,6,7 & 8:
+ |3 |4 | Sinusoidal projection
+ | | |
+ 0 +-------+------+-+-----------+-----------+
+ |5 |6 |7 |8 |
+ | | | | |
+ +-------+--------+-----------+-----------+
+ |9 |10 |11 |12 |
+ | | | | |
+ +-------+--------+-----------+-----------+
+ -180 -100 -20 80 180
+*/
+
+#define SETUP(n, proj, x_0, y_0, lon_0) \
+ if (!(Q->pj[n-1] = pj_##proj(nullptr))) return destructor(P, ENOMEM); \
+ if (!(Q->pj[n-1] = pj_##proj(Q->pj[n-1]))) return destructor(P, ENOMEM); \
+ Q->pj[n-1]->ctx = P->ctx; \
+ Q->pj[n-1]->x0 = x_0; \
+ Q->pj[n-1]->y0 = y_0; \
+ Q->pj[n-1]->lam0 = lon_0;
+
+
+PJ *PROJECTION(igh) {
+ XY xy1, xy3;
+ LP lp = { 0, d4044118 };
+ struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque)));
+ if (nullptr==Q)
+ return pj_default_destructor (P, ENOMEM);
+ P->opaque = Q;
+
+
+ /* sinusoidal zones */
+ SETUP(3, sinu, -d100, 0, -d100);
+ SETUP(4, sinu, d30, 0, d30);
+ SETUP(5, sinu, -d160, 0, -d160);
+ SETUP(6, sinu, -d60, 0, -d60);
+ SETUP(7, sinu, d20, 0, d20);
+ SETUP(8, sinu, d140, 0, d140);
+
+ /* mollweide zones */
+ SETUP(1, moll, -d100, 0, -d100);
+
+ /* y0 ? */
+ xy1 = Q->pj[0]->fwd(lp, Q->pj[0]); /* zone 1 */
+ xy3 = Q->pj[2]->fwd(lp, Q->pj[2]); /* zone 3 */
+ /* y0 + xy1.y = xy3.y for lt = 40d44'11.8" */
+ Q->dy0 = xy3.y - xy1.y;
+
+ Q->pj[0]->y0 = Q->dy0;
+
+ /* mollweide zones (cont'd) */
+ SETUP( 2, moll, d30, Q->dy0, d30);
+ SETUP( 9, moll, -d160, -Q->dy0, -d160);
+ SETUP(10, moll, -d60, -Q->dy0, -d60);
+ SETUP(11, moll, d20, -Q->dy0, d20);
+ SETUP(12, moll, d140, -Q->dy0, d140);
+
+ P->inv = s_inverse;
+ P->fwd = s_forward;
+ P->destructor = destructor;
+ P->es = 0.;
+
+ return P;
+}