aboutsummaryrefslogtreecommitdiff
path: root/src/projections/krovak.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/projections/krovak.cpp')
-rw-r--r--src/projections/krovak.cpp222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/projections/krovak.cpp b/src/projections/krovak.cpp
new file mode 100644
index 00000000..9ecffb89
--- /dev/null
+++ b/src/projections/krovak.cpp
@@ -0,0 +1,222 @@
+ /*
+ * Project: PROJ
+ * Purpose: Implementation of the krovak (Krovak) projection.
+ * Definition: http://www.ihsenergy.com/epsg/guid7.html#1.4.3
+ * Author: Thomas Flemming, tf@ttqv.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2001, Thomas Flemming, tf@ttqv.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ ******************************************************************************
+ * A description of the (forward) projection is found in:
+ *
+ * Bohuslav Veverka,
+ *
+ * KROVAK’S PROJECTION AND ITS USE FOR THE
+ * CZECH REPUBLIC AND THE SLOVAK REPUBLIC,
+ *
+ * 50 years of the Research Institute of
+ * and the Slovak Republic Geodesy, Topography and Cartography
+ *
+ * which can be found via the Wayback Machine:
+ *
+ * https://web.archive.org/web/20150216143806/https://www.vugtk.cz/odis/sborniky/sb2005/Sbornik_50_let_VUGTK/Part_1-Scientific_Contribution/16-Veverka.pdf
+ *
+ * Further info, including the inverse projection, is given by EPSG:
+ *
+ * Guidance Note 7 part 2
+ * Coordinate Conversions and Transformations including Formulas
+ *
+ * http://www.iogp.org/pubs/373-07-2.pdf
+ *
+ * Variable names in this file mostly follows what is used in the
+ * paper by Veverka.
+ *
+ * According to EPSG the full Krovak projection method should have
+ * the following parameters. Within PROJ the azimuth, and pseudo
+ * standard parallel are hardcoded in the algorithm and can't be
+ * altered from outside. The others all have defaults to match the
+ * common usage with Krovak projection.
+ *
+ * lat_0 = latitude of centre of the projection
+ *
+ * lon_0 = longitude of centre of the projection
+ *
+ * ** = azimuth (true) of the centre line passing through the
+ * centre of the projection
+ *
+ * ** = latitude of pseudo standard parallel
+ *
+ * k = scale factor on the pseudo standard parallel
+ *
+ * x_0 = False Easting of the centre of the projection at the
+ * apex of the cone
+ *
+ * y_0 = False Northing of the centre of the projection at
+ * the apex of the cone
+ *
+ *****************************************************************************/
+
+#define PJ_LIB__
+
+#include <errno.h>
+#include <math.h>
+
+#include "projects.h"
+
+PROJ_HEAD(krovak, "Krovak") "\n\tPCyl, Ell";
+
+#define EPS 1e-15
+#define UQ 1.04216856380474 /* DU(2, 59, 42, 42.69689) */
+#define S0 1.37008346281555 /* Latitude of pseudo standard parallel 78deg 30'00" N */
+/* Not sure at all of the appropriate number for MAX_ITER... */
+#define MAX_ITER 100
+
+namespace { // anonymous namespace
+struct pj_opaque {
+ double alpha;
+ double k;
+ double n;
+ double rho0;
+ double ad;
+ int czech;
+};
+} // anonymous namespace
+
+
+static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */
+ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque);
+ XY xy = {0.0,0.0};
+
+ double gfi, u, deltav, s, d, eps, rho;
+
+ gfi = pow ( (1. + P->e * sin(lp.phi)) / (1. - P->e * sin(lp.phi)), Q->alpha * P->e / 2.);
+
+ u = 2. * (atan(Q->k * pow( tan(lp.phi / 2. + M_PI_4), Q->alpha) / gfi)-M_PI_4);
+ deltav = -lp.lam * Q->alpha;
+
+ s = asin(cos(Q->ad) * sin(u) + sin(Q->ad) * cos(u) * cos(deltav));
+ d = asin(cos(u) * sin(deltav) / cos(s));
+
+ eps = Q->n * d;
+ rho = Q->rho0 * pow(tan(S0 / 2. + M_PI_4) , Q->n) / pow(tan(s / 2. + M_PI_4) , Q->n);
+
+ xy.y = rho * cos(eps);
+ xy.x = rho * sin(eps);
+
+ xy.y *= Q->czech;
+ xy.x *= Q->czech;
+
+ return xy;
+}
+
+
+static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */
+ struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque);
+ LP lp = {0.0,0.0};
+
+ double u, deltav, s, d, eps, rho, fi1, xy0;
+ int i;
+
+ xy0 = xy.x;
+ xy.x = xy.y;
+ xy.y = xy0;
+
+ xy.x *= Q->czech;
+ xy.y *= Q->czech;
+
+ rho = sqrt(xy.x * xy.x + xy.y * xy.y);
+ eps = atan2(xy.y, xy.x);
+
+ d = eps / sin(S0);
+ s = 2. * (atan( pow(Q->rho0 / rho, 1. / Q->n) * tan(S0 / 2. + M_PI_4)) - M_PI_4);
+
+ u = asin(cos(Q->ad) * sin(s) - sin(Q->ad) * cos(s) * cos(d));
+ deltav = asin(cos(s) * sin(d) / cos(u));
+
+ lp.lam = P->lam0 - deltav / Q->alpha;
+
+ /* ITERATION FOR lp.phi */
+ fi1 = u;
+
+ for (i = MAX_ITER; i ; --i) {
+ lp.phi = 2. * ( atan( pow( Q->k, -1. / Q->alpha) *
+ pow( tan(u / 2. + M_PI_4) , 1. / Q->alpha) *
+ pow( (1. + P->e * sin(fi1)) / (1. - P->e * sin(fi1)) , P->e / 2.)
+ ) - M_PI_4);
+
+ if (fabs(fi1 - lp.phi) < EPS)
+ break;
+ fi1 = lp.phi;
+ }
+ if( i == 0 )
+ pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT );
+
+ lp.lam -= P->lam0;
+
+ return lp;
+}
+
+
+PJ *PROJECTION(krovak) {
+ double u0, n0, g;
+ 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;
+
+ /* we want Bessel as fixed ellipsoid */
+ P->a = 6377397.155;
+ P->e = sqrt(P->es = 0.006674372230614);
+
+ /* if latitude of projection center is not set, use 49d30'N */
+ if (!pj_param(P->ctx, P->params, "tlat_0").i)
+ P->phi0 = 0.863937979737193;
+
+ /* if center long is not set use 42d30'E of Ferro - 17d40' for Ferro */
+ /* that will correspond to using longitudes relative to greenwich */
+ /* as input and output, instead of lat/long relative to Ferro */
+ if (!pj_param(P->ctx, P->params, "tlon_0").i)
+ P->lam0 = 0.7417649320975901 - 0.308341501185665;
+
+ /* if scale not set default to 0.9999 */
+ if (!pj_param(P->ctx, P->params, "tk").i && !pj_param(P->ctx, P->params, "tk_0").i)
+ P->k0 = 0.9999;
+
+ Q->czech = 1;
+ if( !pj_param(P->ctx, P->params, "tczech").i )
+ Q->czech = -1;
+
+ /* Set up shared parameters between forward and inverse */
+ Q->alpha = sqrt(1. + (P->es * pow(cos(P->phi0), 4)) / (1. - P->es));
+ u0 = asin(sin(P->phi0) / Q->alpha);
+ g = pow( (1. + P->e * sin(P->phi0)) / (1. - P->e * sin(P->phi0)) , Q->alpha * P->e / 2. );
+ Q->k = tan( u0 / 2. + M_PI_4) / pow (tan(P->phi0 / 2. + M_PI_4) , Q->alpha) * g;
+ n0 = sqrt(1. - P->es) / (1. - P->es * pow(sin(P->phi0), 2));
+ Q->n = sin(S0);
+ Q->rho0 = P->k0 * n0 / tan(S0);
+ Q->ad = M_PI_2 - UQ;
+
+ P->inv = e_inverse;
+ P->fwd = e_forward;
+
+ return P;
+}