From df574ae332d57f556fd56314883b3354cab1d0ff Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 19 Dec 2018 13:00:37 +0100 Subject: cpp conversion: remove useless pj_, PJ_ and proj_ filename prefixes --- src/projections/PJ_aea.cpp | 224 -------- src/projections/PJ_aeqd.cpp | 327 ----------- src/projections/PJ_airy.cpp | 155 ------ src/projections/PJ_aitoff.cpp | 201 ------- src/projections/PJ_august.cpp | 34 -- src/projections/PJ_bacon.cpp | 81 --- src/projections/PJ_bertin1953.cpp | 96 ---- src/projections/PJ_bipc.cpp | 176 ------ src/projections/PJ_boggs.cpp | 43 -- src/projections/PJ_bonne.cpp | 136 ----- src/projections/PJ_calcofi.cpp | 163 ------ src/projections/PJ_cass.cpp | 123 ----- src/projections/PJ_cc.cpp | 41 -- src/projections/PJ_ccon.cpp | 109 ---- src/projections/PJ_cea.cpp | 103 ---- src/projections/PJ_chamb.cpp | 141 ----- src/projections/PJ_collg.cpp | 53 -- src/projections/PJ_comill.cpp | 84 --- src/projections/PJ_crast.cpp | 40 -- src/projections/PJ_denoy.cpp | 32 -- src/projections/PJ_eck1.cpp | 41 -- src/projections/PJ_eck2.cpp | 56 -- src/projections/PJ_eck3.cpp | 112 ---- src/projections/PJ_eck4.cpp | 63 --- src/projections/PJ_eck5.cpp | 40 -- src/projections/PJ_eqc.cpp | 54 -- src/projections/PJ_eqdc.cpp | 122 ----- src/projections/PJ_eqearth.cpp | 164 ------ src/projections/PJ_fahey.cpp | 41 -- src/projections/PJ_fouc_s.cpp | 72 --- src/projections/PJ_gall.cpp | 44 -- src/projections/PJ_geos.cpp | 238 -------- src/projections/PJ_gins8.cpp | 33 -- src/projections/PJ_gn_sinu.cpp | 189 ------- src/projections/PJ_gnom.cpp | 147 ----- src/projections/PJ_goode.cpp | 84 --- src/projections/PJ_gstmerc.cpp | 74 --- src/projections/PJ_hammer.cpp | 77 --- src/projections/PJ_hatano.cpp | 83 --- src/projections/PJ_healpix.cpp | 674 ----------------------- src/projections/PJ_igh.cpp | 227 -------- src/projections/PJ_imw_p.cpp | 217 -------- src/projections/PJ_isea.cpp | 1098 ------------------------------------- src/projections/PJ_krovak.cpp | 222 -------- src/projections/PJ_labrd.cpp | 132 ----- src/projections/PJ_laea.cpp | 300 ---------- src/projections/PJ_lagrng.cpp | 98 ---- src/projections/PJ_larr.cpp | 28 - src/projections/PJ_lask.cpp | 39 -- src/projections/PJ_latlong.cpp | 124 ----- src/projections/PJ_lcc.cpp | 130 ----- src/projections/PJ_lcca.cpp | 164 ------ src/projections/PJ_loxim.cpp | 77 --- src/projections/PJ_lsat.cpp | 212 ------- src/projections/PJ_mbt_fps.cpp | 57 -- src/projections/PJ_mbtfpp.cpp | 65 --- src/projections/PJ_mbtfpq.cpp | 74 --- src/projections/PJ_merc.cpp | 101 ---- src/projections/PJ_mill.cpp | 37 -- src/projections/PJ_misrsom.cpp | 219 -------- src/projections/PJ_mod_ster.cpp | 282 ---------- src/projections/PJ_moll.cpp | 112 ---- src/projections/PJ_natearth.cpp | 100 ---- src/projections/PJ_natearth2.cpp | 97 ---- src/projections/PJ_nell.cpp | 51 -- src/projections/PJ_nell_h.cpp | 53 -- src/projections/PJ_nocol.cpp | 54 -- src/projections/PJ_nsper.cpp | 202 ------- src/projections/PJ_nzmg.cpp | 123 ----- src/projections/PJ_ob_tran.cpp | 245 --------- src/projections/PJ_ocea.cpp | 102 ---- src/projections/PJ_oea.cpp | 87 --- src/projections/PJ_omerc.cpp | 229 -------- src/projections/PJ_ortho.cpp | 143 ----- src/projections/PJ_patterson.cpp | 117 ---- src/projections/PJ_poly.cpp | 171 ------ src/projections/PJ_putp2.cpp | 61 --- src/projections/PJ_putp3.cpp | 67 --- src/projections/PJ_putp4p.cpp | 76 --- src/projections/PJ_putp5.cpp | 75 --- src/projections/PJ_putp6.cpp | 97 ---- src/projections/PJ_qsc.cpp | 408 -------------- src/projections/PJ_robin.cpp | 161 ------ src/projections/PJ_rpoly.cpp | 58 -- src/projections/PJ_sch.cpp | 232 -------- src/projections/PJ_sconics.cpp | 220 -------- src/projections/PJ_somerc.cpp | 94 ---- src/projections/PJ_stere.cpp | 320 ----------- src/projections/PJ_sterea.cpp | 117 ---- src/projections/PJ_sts.cpp | 109 ---- src/projections/PJ_tcc.cpp | 34 -- src/projections/PJ_tcea.cpp | 36 -- src/projections/PJ_times.cpp | 79 --- src/projections/PJ_tmerc.cpp | 210 ------- src/projections/PJ_tobmerc.cpp | 51 -- src/projections/PJ_tpeqd.cpp | 109 ---- src/projections/PJ_urm5.cpp | 56 -- src/projections/PJ_urmfps.cpp | 76 --- src/projections/PJ_vandg.cpp | 106 ---- src/projections/PJ_vandg2.cpp | 76 --- src/projections/PJ_vandg4.cpp | 55 -- src/projections/PJ_wag2.cpp | 38 -- src/projections/PJ_wag3.cpp | 50 -- src/projections/PJ_wag7.cpp | 30 - src/projections/PJ_wink1.cpp | 46 -- src/projections/PJ_wink2.cpp | 56 -- src/projections/aea.cpp | 224 ++++++++ src/projections/aeqd.cpp | 327 +++++++++++ src/projections/airy.cpp | 155 ++++++ src/projections/aitoff.cpp | 201 +++++++ src/projections/august.cpp | 34 ++ src/projections/bacon.cpp | 81 +++ src/projections/bertin1953.cpp | 96 ++++ src/projections/bipc.cpp | 176 ++++++ src/projections/boggs.cpp | 43 ++ src/projections/bonne.cpp | 136 +++++ src/projections/calcofi.cpp | 163 ++++++ src/projections/cass.cpp | 123 +++++ src/projections/cc.cpp | 41 ++ src/projections/ccon.cpp | 109 ++++ src/projections/cea.cpp | 103 ++++ src/projections/chamb.cpp | 141 +++++ src/projections/collg.cpp | 53 ++ src/projections/comill.cpp | 84 +++ src/projections/crast.cpp | 40 ++ src/projections/denoy.cpp | 32 ++ src/projections/eck1.cpp | 41 ++ src/projections/eck2.cpp | 56 ++ src/projections/eck3.cpp | 112 ++++ src/projections/eck4.cpp | 63 +++ src/projections/eck5.cpp | 40 ++ src/projections/eqc.cpp | 54 ++ src/projections/eqdc.cpp | 122 +++++ src/projections/eqearth.cpp | 164 ++++++ src/projections/etmerc.cpp | 362 ++++++++++++ src/projections/fahey.cpp | 41 ++ src/projections/fouc_s.cpp | 72 +++ src/projections/gall.cpp | 44 ++ src/projections/geos.cpp | 238 ++++++++ src/projections/gins8.cpp | 33 ++ src/projections/gn_sinu.cpp | 189 +++++++ src/projections/gnom.cpp | 147 +++++ src/projections/goode.cpp | 84 +++ src/projections/gstmerc.cpp | 74 +++ src/projections/hammer.cpp | 77 +++ src/projections/hatano.cpp | 83 +++ src/projections/healpix.cpp | 674 +++++++++++++++++++++++ src/projections/igh.cpp | 227 ++++++++ src/projections/imw_p.cpp | 217 ++++++++ src/projections/isea.cpp | 1098 +++++++++++++++++++++++++++++++++++++ src/projections/krovak.cpp | 222 ++++++++ src/projections/labrd.cpp | 132 +++++ src/projections/laea.cpp | 300 ++++++++++ src/projections/lagrng.cpp | 98 ++++ src/projections/larr.cpp | 28 + src/projections/lask.cpp | 39 ++ src/projections/latlong.cpp | 124 +++++ src/projections/lcc.cpp | 130 +++++ src/projections/lcca.cpp | 164 ++++++ src/projections/loxim.cpp | 77 +++ src/projections/lsat.cpp | 212 +++++++ src/projections/mbt_fps.cpp | 57 ++ src/projections/mbtfpp.cpp | 65 +++ src/projections/mbtfpq.cpp | 74 +++ src/projections/merc.cpp | 101 ++++ src/projections/mill.cpp | 37 ++ src/projections/misrsom.cpp | 219 ++++++++ src/projections/mod_ster.cpp | 282 ++++++++++ src/projections/moll.cpp | 112 ++++ src/projections/natearth.cpp | 100 ++++ src/projections/natearth2.cpp | 97 ++++ src/projections/nell.cpp | 51 ++ src/projections/nell_h.cpp | 53 ++ src/projections/nocol.cpp | 54 ++ src/projections/nsper.cpp | 202 +++++++ src/projections/nzmg.cpp | 123 +++++ src/projections/ob_tran.cpp | 245 +++++++++ src/projections/ocea.cpp | 102 ++++ src/projections/oea.cpp | 87 +++ src/projections/omerc.cpp | 229 ++++++++ src/projections/ortho.cpp | 143 +++++ src/projections/patterson.cpp | 117 ++++ src/projections/poly.cpp | 171 ++++++ src/projections/proj_etmerc.cpp | 362 ------------ src/projections/proj_rouss.cpp | 158 ------ src/projections/putp2.cpp | 61 +++ src/projections/putp3.cpp | 67 +++ src/projections/putp4p.cpp | 76 +++ src/projections/putp5.cpp | 75 +++ src/projections/putp6.cpp | 97 ++++ src/projections/qsc.cpp | 408 ++++++++++++++ src/projections/robin.cpp | 161 ++++++ src/projections/rouss.cpp | 158 ++++++ src/projections/rpoly.cpp | 58 ++ src/projections/sch.cpp | 232 ++++++++ src/projections/sconics.cpp | 220 ++++++++ src/projections/somerc.cpp | 94 ++++ src/projections/stere.cpp | 320 +++++++++++ src/projections/sterea.cpp | 117 ++++ src/projections/sts.cpp | 109 ++++ src/projections/tcc.cpp | 34 ++ src/projections/tcea.cpp | 36 ++ src/projections/times.cpp | 79 +++ src/projections/tmerc.cpp | 210 +++++++ src/projections/tobmerc.cpp | 51 ++ src/projections/tpeqd.cpp | 109 ++++ src/projections/urm5.cpp | 56 ++ src/projections/urmfps.cpp | 76 +++ src/projections/vandg.cpp | 106 ++++ src/projections/vandg2.cpp | 76 +++ src/projections/vandg4.cpp | 55 ++ src/projections/wag2.cpp | 38 ++ src/projections/wag3.cpp | 50 ++ src/projections/wag7.cpp | 30 + src/projections/wink1.cpp | 46 ++ src/projections/wink2.cpp | 56 ++ 216 files changed, 14282 insertions(+), 14282 deletions(-) delete mode 100644 src/projections/PJ_aea.cpp delete mode 100644 src/projections/PJ_aeqd.cpp delete mode 100644 src/projections/PJ_airy.cpp delete mode 100644 src/projections/PJ_aitoff.cpp delete mode 100644 src/projections/PJ_august.cpp delete mode 100644 src/projections/PJ_bacon.cpp delete mode 100644 src/projections/PJ_bertin1953.cpp delete mode 100644 src/projections/PJ_bipc.cpp delete mode 100644 src/projections/PJ_boggs.cpp delete mode 100644 src/projections/PJ_bonne.cpp delete mode 100644 src/projections/PJ_calcofi.cpp delete mode 100644 src/projections/PJ_cass.cpp delete mode 100644 src/projections/PJ_cc.cpp delete mode 100644 src/projections/PJ_ccon.cpp delete mode 100644 src/projections/PJ_cea.cpp delete mode 100644 src/projections/PJ_chamb.cpp delete mode 100644 src/projections/PJ_collg.cpp delete mode 100644 src/projections/PJ_comill.cpp delete mode 100644 src/projections/PJ_crast.cpp delete mode 100644 src/projections/PJ_denoy.cpp delete mode 100644 src/projections/PJ_eck1.cpp delete mode 100644 src/projections/PJ_eck2.cpp delete mode 100644 src/projections/PJ_eck3.cpp delete mode 100644 src/projections/PJ_eck4.cpp delete mode 100644 src/projections/PJ_eck5.cpp delete mode 100644 src/projections/PJ_eqc.cpp delete mode 100644 src/projections/PJ_eqdc.cpp delete mode 100644 src/projections/PJ_eqearth.cpp delete mode 100644 src/projections/PJ_fahey.cpp delete mode 100644 src/projections/PJ_fouc_s.cpp delete mode 100644 src/projections/PJ_gall.cpp delete mode 100644 src/projections/PJ_geos.cpp delete mode 100644 src/projections/PJ_gins8.cpp delete mode 100644 src/projections/PJ_gn_sinu.cpp delete mode 100644 src/projections/PJ_gnom.cpp delete mode 100644 src/projections/PJ_goode.cpp delete mode 100644 src/projections/PJ_gstmerc.cpp delete mode 100644 src/projections/PJ_hammer.cpp delete mode 100644 src/projections/PJ_hatano.cpp delete mode 100644 src/projections/PJ_healpix.cpp delete mode 100644 src/projections/PJ_igh.cpp delete mode 100644 src/projections/PJ_imw_p.cpp delete mode 100644 src/projections/PJ_isea.cpp delete mode 100644 src/projections/PJ_krovak.cpp delete mode 100644 src/projections/PJ_labrd.cpp delete mode 100644 src/projections/PJ_laea.cpp delete mode 100644 src/projections/PJ_lagrng.cpp delete mode 100644 src/projections/PJ_larr.cpp delete mode 100644 src/projections/PJ_lask.cpp delete mode 100644 src/projections/PJ_latlong.cpp delete mode 100644 src/projections/PJ_lcc.cpp delete mode 100644 src/projections/PJ_lcca.cpp delete mode 100644 src/projections/PJ_loxim.cpp delete mode 100644 src/projections/PJ_lsat.cpp delete mode 100644 src/projections/PJ_mbt_fps.cpp delete mode 100644 src/projections/PJ_mbtfpp.cpp delete mode 100644 src/projections/PJ_mbtfpq.cpp delete mode 100644 src/projections/PJ_merc.cpp delete mode 100644 src/projections/PJ_mill.cpp delete mode 100644 src/projections/PJ_misrsom.cpp delete mode 100644 src/projections/PJ_mod_ster.cpp delete mode 100644 src/projections/PJ_moll.cpp delete mode 100644 src/projections/PJ_natearth.cpp delete mode 100644 src/projections/PJ_natearth2.cpp delete mode 100644 src/projections/PJ_nell.cpp delete mode 100644 src/projections/PJ_nell_h.cpp delete mode 100644 src/projections/PJ_nocol.cpp delete mode 100644 src/projections/PJ_nsper.cpp delete mode 100644 src/projections/PJ_nzmg.cpp delete mode 100644 src/projections/PJ_ob_tran.cpp delete mode 100644 src/projections/PJ_ocea.cpp delete mode 100644 src/projections/PJ_oea.cpp delete mode 100644 src/projections/PJ_omerc.cpp delete mode 100644 src/projections/PJ_ortho.cpp delete mode 100644 src/projections/PJ_patterson.cpp delete mode 100644 src/projections/PJ_poly.cpp delete mode 100644 src/projections/PJ_putp2.cpp delete mode 100644 src/projections/PJ_putp3.cpp delete mode 100644 src/projections/PJ_putp4p.cpp delete mode 100644 src/projections/PJ_putp5.cpp delete mode 100644 src/projections/PJ_putp6.cpp delete mode 100644 src/projections/PJ_qsc.cpp delete mode 100644 src/projections/PJ_robin.cpp delete mode 100644 src/projections/PJ_rpoly.cpp delete mode 100644 src/projections/PJ_sch.cpp delete mode 100644 src/projections/PJ_sconics.cpp delete mode 100644 src/projections/PJ_somerc.cpp delete mode 100644 src/projections/PJ_stere.cpp delete mode 100644 src/projections/PJ_sterea.cpp delete mode 100644 src/projections/PJ_sts.cpp delete mode 100644 src/projections/PJ_tcc.cpp delete mode 100644 src/projections/PJ_tcea.cpp delete mode 100644 src/projections/PJ_times.cpp delete mode 100644 src/projections/PJ_tmerc.cpp delete mode 100644 src/projections/PJ_tobmerc.cpp delete mode 100644 src/projections/PJ_tpeqd.cpp delete mode 100644 src/projections/PJ_urm5.cpp delete mode 100644 src/projections/PJ_urmfps.cpp delete mode 100644 src/projections/PJ_vandg.cpp delete mode 100644 src/projections/PJ_vandg2.cpp delete mode 100644 src/projections/PJ_vandg4.cpp delete mode 100644 src/projections/PJ_wag2.cpp delete mode 100644 src/projections/PJ_wag3.cpp delete mode 100644 src/projections/PJ_wag7.cpp delete mode 100644 src/projections/PJ_wink1.cpp delete mode 100644 src/projections/PJ_wink2.cpp create mode 100644 src/projections/aea.cpp create mode 100644 src/projections/aeqd.cpp create mode 100644 src/projections/airy.cpp create mode 100644 src/projections/aitoff.cpp create mode 100644 src/projections/august.cpp create mode 100644 src/projections/bacon.cpp create mode 100644 src/projections/bertin1953.cpp create mode 100644 src/projections/bipc.cpp create mode 100644 src/projections/boggs.cpp create mode 100644 src/projections/bonne.cpp create mode 100644 src/projections/calcofi.cpp create mode 100644 src/projections/cass.cpp create mode 100644 src/projections/cc.cpp create mode 100644 src/projections/ccon.cpp create mode 100644 src/projections/cea.cpp create mode 100644 src/projections/chamb.cpp create mode 100644 src/projections/collg.cpp create mode 100644 src/projections/comill.cpp create mode 100644 src/projections/crast.cpp create mode 100644 src/projections/denoy.cpp create mode 100644 src/projections/eck1.cpp create mode 100644 src/projections/eck2.cpp create mode 100644 src/projections/eck3.cpp create mode 100644 src/projections/eck4.cpp create mode 100644 src/projections/eck5.cpp create mode 100644 src/projections/eqc.cpp create mode 100644 src/projections/eqdc.cpp create mode 100644 src/projections/eqearth.cpp create mode 100644 src/projections/etmerc.cpp create mode 100644 src/projections/fahey.cpp create mode 100644 src/projections/fouc_s.cpp create mode 100644 src/projections/gall.cpp create mode 100644 src/projections/geos.cpp create mode 100644 src/projections/gins8.cpp create mode 100644 src/projections/gn_sinu.cpp create mode 100644 src/projections/gnom.cpp create mode 100644 src/projections/goode.cpp create mode 100644 src/projections/gstmerc.cpp create mode 100644 src/projections/hammer.cpp create mode 100644 src/projections/hatano.cpp create mode 100644 src/projections/healpix.cpp create mode 100644 src/projections/igh.cpp create mode 100644 src/projections/imw_p.cpp create mode 100644 src/projections/isea.cpp create mode 100644 src/projections/krovak.cpp create mode 100644 src/projections/labrd.cpp create mode 100644 src/projections/laea.cpp create mode 100644 src/projections/lagrng.cpp create mode 100644 src/projections/larr.cpp create mode 100644 src/projections/lask.cpp create mode 100644 src/projections/latlong.cpp create mode 100644 src/projections/lcc.cpp create mode 100644 src/projections/lcca.cpp create mode 100644 src/projections/loxim.cpp create mode 100644 src/projections/lsat.cpp create mode 100644 src/projections/mbt_fps.cpp create mode 100644 src/projections/mbtfpp.cpp create mode 100644 src/projections/mbtfpq.cpp create mode 100644 src/projections/merc.cpp create mode 100644 src/projections/mill.cpp create mode 100644 src/projections/misrsom.cpp create mode 100644 src/projections/mod_ster.cpp create mode 100644 src/projections/moll.cpp create mode 100644 src/projections/natearth.cpp create mode 100644 src/projections/natearth2.cpp create mode 100644 src/projections/nell.cpp create mode 100644 src/projections/nell_h.cpp create mode 100644 src/projections/nocol.cpp create mode 100644 src/projections/nsper.cpp create mode 100644 src/projections/nzmg.cpp create mode 100644 src/projections/ob_tran.cpp create mode 100644 src/projections/ocea.cpp create mode 100644 src/projections/oea.cpp create mode 100644 src/projections/omerc.cpp create mode 100644 src/projections/ortho.cpp create mode 100644 src/projections/patterson.cpp create mode 100644 src/projections/poly.cpp delete mode 100644 src/projections/proj_etmerc.cpp delete mode 100644 src/projections/proj_rouss.cpp create mode 100644 src/projections/putp2.cpp create mode 100644 src/projections/putp3.cpp create mode 100644 src/projections/putp4p.cpp create mode 100644 src/projections/putp5.cpp create mode 100644 src/projections/putp6.cpp create mode 100644 src/projections/qsc.cpp create mode 100644 src/projections/robin.cpp create mode 100644 src/projections/rouss.cpp create mode 100644 src/projections/rpoly.cpp create mode 100644 src/projections/sch.cpp create mode 100644 src/projections/sconics.cpp create mode 100644 src/projections/somerc.cpp create mode 100644 src/projections/stere.cpp create mode 100644 src/projections/sterea.cpp create mode 100644 src/projections/sts.cpp create mode 100644 src/projections/tcc.cpp create mode 100644 src/projections/tcea.cpp create mode 100644 src/projections/times.cpp create mode 100644 src/projections/tmerc.cpp create mode 100644 src/projections/tobmerc.cpp create mode 100644 src/projections/tpeqd.cpp create mode 100644 src/projections/urm5.cpp create mode 100644 src/projections/urmfps.cpp create mode 100644 src/projections/vandg.cpp create mode 100644 src/projections/vandg2.cpp create mode 100644 src/projections/vandg4.cpp create mode 100644 src/projections/wag2.cpp create mode 100644 src/projections/wag3.cpp create mode 100644 src/projections/wag7.cpp create mode 100644 src/projections/wink1.cpp create mode 100644 src/projections/wink2.cpp (limited to 'src/projections') diff --git a/src/projections/PJ_aea.cpp b/src/projections/PJ_aea.cpp deleted file mode 100644 index c4a4a72a..00000000 --- a/src/projections/PJ_aea.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the aea (Albers Equal Area) projection. - * and the leac (Lambert Equal Area Conic) projection - * Author: Gerald Evenden (1995) - * Thomas Knudsen (2016) - revise/add regression tests - * - ****************************************************************************** - * Copyright (c) 1995, Gerald Evenden - * - * 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. - *****************************************************************************/ - -#define PJ_LIB__ -#include "proj.h" -#include -#include "projects.h" -#include "proj_math.h" - - -# define EPS10 1.e-10 -# define TOL7 1.e-7 - -PROJ_HEAD(aea, "Albers Equal Area") "\n\tConic Sph&Ell\n\tlat_1= lat_2="; -PROJ_HEAD(leac, "Lambert Equal Area Conic") "\n\tConic, Sph&Ell\n\tlat_1= south"; - - -/* determine latitude angle phi-1 */ -# define N_ITER 15 -# define EPSILON 1.0e-7 -# define TOL 1.0e-10 -static double phi1_(double qs, double Te, double Tone_es) { - int i; - double Phi, sinpi, cospi, con, com, dphi; - - Phi = asin (.5 * qs); - if (Te < EPSILON) - return( Phi ); - i = N_ITER; - do { - sinpi = sin (Phi); - cospi = cos (Phi); - con = Te * sinpi; - com = 1. - con * con; - dphi = .5 * com * com / cospi * (qs / Tone_es - - sinpi / com + .5 / Te * log ((1. - con) / - (1. + con))); - Phi += dphi; - } while (fabs(dphi) > TOL && --i); - return( i ? Phi : HUGE_VAL ); -} - - -namespace { // anonymous namespace -struct pj_opaque { - double ec; - double n; - double c; - double dd; - double n2; - double rho0; - double rho; - double phi1; - double phi2; - double *en; - int ellips; -}; -} // anonymous namespace - - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - - - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoid/spheroid, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - Q->rho = Q->c - (Q->ellips ? Q->n * pj_qsfn(sin(lp.phi), P->e, P->one_es) : Q->n2 * sin(lp.phi));; - if (Q->rho < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - Q->rho = Q->dd * sqrt(Q->rho); - xy.x = Q->rho * sin( lp.lam *= Q->n ); - xy.y = Q->rho0 - Q->rho * cos(lp.lam); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoid/spheroid, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - if( (Q->rho = hypot(xy.x, xy.y = Q->rho0 - xy.y)) != 0.0 ) { - if (Q->n < 0.) { - Q->rho = -Q->rho; - xy.x = -xy.x; - xy.y = -xy.y; - } - lp.phi = Q->rho / Q->dd; - if (Q->ellips) { - lp.phi = (Q->c - lp.phi * lp.phi) / Q->n; - if (fabs(Q->ec - fabs(lp.phi)) > TOL7) { - if ((lp.phi = phi1_(lp.phi, P->e, P->one_es)) == HUGE_VAL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - } else - lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; - } else if (fabs(lp.phi = (Q->c - lp.phi * lp.phi) / Q->n2) <= 1.) - lp.phi = asin(lp.phi); - else - lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; - lp.lam = atan2(xy.x, xy.y) / Q->n; - } else { - lp.lam = 0.; - lp.phi = Q->n > 0. ? M_HALFPI : - M_HALFPI; - } - return lp; -} - - - -static PJ *setup(PJ *P) { - double cosphi, sinphi; - int secant; - struct pj_opaque *Q = static_cast(P->opaque); - - P->inv = e_inverse; - P->fwd = e_forward; - - if (fabs(Q->phi1 + Q->phi2) < EPS10) - return destructor(P, PJD_ERR_CONIC_LAT_EQUAL); - Q->n = sinphi = sin(Q->phi1); - cosphi = cos(Q->phi1); - secant = fabs(Q->phi1 - Q->phi2) >= EPS10; - if( (Q->ellips = (P->es > 0.))) { - double ml1, m1; - - if (!(Q->en = pj_enfn(P->es))) - return destructor(P, 0); - m1 = pj_msfn(sinphi, cosphi, P->es); - ml1 = pj_qsfn(sinphi, P->e, P->one_es); - if (secant) { /* secant cone */ - double ml2, m2; - - sinphi = sin(Q->phi2); - cosphi = cos(Q->phi2); - m2 = pj_msfn(sinphi, cosphi, P->es); - ml2 = pj_qsfn(sinphi, P->e, P->one_es); - if (ml2 == ml1) - return destructor(P, 0); - - Q->n = (m1 * m1 - m2 * m2) / (ml2 - ml1); - } - Q->ec = 1. - .5 * P->one_es * log((1. - P->e) / - (1. + P->e)) / P->e; - Q->c = m1 * m1 + Q->n * ml1; - Q->dd = 1. / Q->n; - Q->rho0 = Q->dd * sqrt(Q->c - Q->n * pj_qsfn(sin(P->phi0), - P->e, P->one_es)); - } else { - if (secant) Q->n = .5 * (Q->n + sin(Q->phi2)); - Q->n2 = Q->n + Q->n; - Q->c = cosphi * cosphi + Q->n2 * sinphi; - Q->dd = 1. / Q->n; - Q->rho0 = Q->dd * sqrt(Q->c - Q->n2 * sin(P->phi0)); - } - - return P; -} - - -PJ *PROJECTION(aea) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; - Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; - return setup(P); -} - - -PJ *PROJECTION(leac) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - Q->phi2 = pj_param(P->ctx, P->params, "rlat_1").f; - Q->phi1 = pj_param(P->ctx, P->params, "bsouth").i ? - M_HALFPI: M_HALFPI; - return setup(P); -} - diff --git a/src/projections/PJ_aeqd.cpp b/src/projections/PJ_aeqd.cpp deleted file mode 100644 index 1a350d90..00000000 --- a/src/projections/PJ_aeqd.cpp +++ /dev/null @@ -1,327 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the aeqd (Azimuthal Equidistant) projection. - * Author: Gerald Evenden - * - ****************************************************************************** - * Copyright (c) 1995, Gerald Evenden - * - * 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. - *****************************************************************************/ - -#define PJ_LIB__ -#include "geodesic.h" -#include "proj.h" -#include -#include "projects.h" -#include "proj_math.h" - -namespace { // anonymous namespace -enum Mode { - N_POLE = 0, - S_POLE = 1, - EQUIT = 2, - OBLIQ = 3 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double sinph0; - double cosph0; - double *en; - double M1; - double N1; - double Mp; - double He; - double G; - enum Mode mode; - struct geod_geodesic g; -}; -} // anonymous namespace - -PROJ_HEAD(aeqd, "Azimuthal Equidistant") "\n\tAzi, Sph&Ell\n\tlat_0 guam"; - -#define EPS10 1.e-10 -#define TOL 1.e-14 - - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - - -static XY e_guam_fwd(LP lp, PJ *P) { /* Guam elliptical */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cosphi, sinphi, t; - - cosphi = cos(lp.phi); - sinphi = sin(lp.phi); - t = 1. / sqrt(1. - P->es * sinphi * sinphi); - xy.x = lp.lam * cosphi * t; - xy.y = pj_mlfn(lp.phi, sinphi, cosphi, Q->en) - Q->M1 + - .5 * lp.lam * lp.lam * cosphi * sinphi * t; - - return xy; -} - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, cosphi, sinphi, rho; - double azi1, azi2, s12; - double lam1, phi1, lam2, phi2; - - coslam = cos(lp.lam); - cosphi = cos(lp.phi); - sinphi = sin(lp.phi); - switch (Q->mode) { - case N_POLE: - coslam = - coslam; - /*-fallthrough*/ - case S_POLE: - xy.x = (rho = fabs(Q->Mp - pj_mlfn(lp.phi, sinphi, cosphi, Q->en))) * - sin(lp.lam); - xy.y = rho * coslam; - break; - case EQUIT: - case OBLIQ: - if (fabs(lp.lam) < EPS10 && fabs(lp.phi - P->phi0) < EPS10) { - xy.x = xy.y = 0.; - break; - } - - phi1 = P->phi0 / DEG_TO_RAD; lam1 = P->lam0 / DEG_TO_RAD; - phi2 = lp.phi / DEG_TO_RAD; lam2 = (lp.lam+P->lam0) / DEG_TO_RAD; - - geod_inverse(&Q->g, phi1, lam1, phi2, lam2, &s12, &azi1, &azi2); - azi1 *= DEG_TO_RAD; - xy.x = s12 * sin(azi1) / P->a; - xy.y = s12 * cos(azi1) / P->a; - break; - } - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, cosphi, sinphi; - - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - coslam = cos(lp.lam); - switch (Q->mode) { - case EQUIT: - xy.y = cosphi * coslam; - goto oblcon; - case OBLIQ: - xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam; -oblcon: - if (fabs(fabs(xy.y) - 1.) < TOL) - if (xy.y < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - else - xy.x = xy.y = 0.; - else { - xy.y = acos(xy.y); - xy.y /= sin(xy.y); - xy.x = xy.y * cosphi * sin(lp.lam); - xy.y *= (Q->mode == EQUIT) ? sinphi : - Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam; - } - break; - case N_POLE: - lp.phi = -lp.phi; - coslam = -coslam; - /*-fallthrough*/ - case S_POLE: - if (fabs(lp.phi - M_HALFPI) < EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.x = (xy.y = (M_HALFPI + lp.phi)) * sin(lp.lam); - xy.y *= coslam; - break; - } - return xy; -} - - -static LP e_guam_inv(XY xy, PJ *P) { /* Guam elliptical */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double x2, t = 0.0; - int i; - - x2 = 0.5 * xy.x * xy.x; - lp.phi = P->phi0; - for (i = 0; i < 3; ++i) { - t = P->e * sin(lp.phi); - lp.phi = pj_inv_mlfn(P->ctx, Q->M1 + xy.y - - x2 * tan(lp.phi) * (t = sqrt(1. - t * t)), P->es, Q->en); - } - lp.lam = xy.x * t / cos(lp.phi); - return lp; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double c; - double azi1, azi2, s12, x2, y2, lat1, lon1, lat2, lon2; - - if ((c = hypot(xy.x, xy.y)) < EPS10) { - lp.phi = P->phi0; - lp.lam = 0.; - return (lp); - } - if (Q->mode == OBLIQ || Q->mode == EQUIT) { - - x2 = xy.x * P->a; - y2 = xy.y * P->a; - lat1 = P->phi0 / DEG_TO_RAD; - lon1 = P->lam0 / DEG_TO_RAD; - azi1 = atan2(x2, y2) / DEG_TO_RAD; - s12 = sqrt(x2 * x2 + y2 * y2); - geod_direct(&Q->g, lat1, lon1, azi1, s12, &lat2, &lon2, &azi2); - lp.phi = lat2 * DEG_TO_RAD; - lp.lam = lon2 * DEG_TO_RAD; - lp.lam -= P->lam0; - } else { /* Polar */ - lp.phi = pj_inv_mlfn(P->ctx, Q->mode == N_POLE ? Q->Mp - c : Q->Mp + c, - P->es, Q->en); - lp.lam = atan2(xy.x, Q->mode == N_POLE ? -xy.y : xy.y); - } - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cosc, c_rh, sinc; - - if ((c_rh = hypot(xy.x, xy.y)) > M_PI) { - if (c_rh - EPS10 > M_PI) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - c_rh = M_PI; - } else if (c_rh < EPS10) { - lp.phi = P->phi0; - lp.lam = 0.; - return (lp); - } - if (Q->mode == OBLIQ || Q->mode == EQUIT) { - sinc = sin(c_rh); - cosc = cos(c_rh); - if (Q->mode == EQUIT) { - lp.phi = aasin(P->ctx, xy.y * sinc / c_rh); - xy.x *= sinc; - xy.y = cosc * c_rh; - } else { - lp.phi = aasin(P->ctx,cosc * Q->sinph0 + xy.y * sinc * Q->cosph0 / - c_rh); - xy.y = (cosc - Q->sinph0 * sin(lp.phi)) * c_rh; - xy.x *= sinc * Q->cosph0; - } - lp.lam = xy.y == 0. ? 0. : atan2(xy.x, xy.y); - } else if (Q->mode == N_POLE) { - lp.phi = M_HALFPI - c_rh; - lp.lam = atan2(xy.x, -xy.y); - } else { - lp.phi = c_rh - M_HALFPI; - lp.lam = atan2(xy.x, xy.y); - } - return lp; -} - - -PJ *PROJECTION(aeqd) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - geod_init(&Q->g, P->a, P->es / (1 + sqrt(P->one_es))); - - if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) { - Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - Q->sinph0 = P->phi0 < 0. ? -1. : 1.; - Q->cosph0 = 0.; - } else if (fabs(P->phi0) < EPS10) { - Q->mode = EQUIT; - Q->sinph0 = 0.; - Q->cosph0 = 1.; - } else { - Q->mode = OBLIQ; - Q->sinph0 = sin(P->phi0); - Q->cosph0 = cos(P->phi0); - } - if (P->es == 0.0) { - P->inv = s_inverse; - P->fwd = s_forward; - } else { - if (!(Q->en = pj_enfn(P->es))) - return pj_default_destructor (P, 0); - if (pj_param(P->ctx, P->params, "bguam").i) { - Q->M1 = pj_mlfn(P->phi0, Q->sinph0, Q->cosph0, Q->en); - P->inv = e_guam_inv; - P->fwd = e_guam_fwd; - } else { - switch (Q->mode) { - case N_POLE: - Q->Mp = pj_mlfn(M_HALFPI, 1., 0., Q->en); - break; - case S_POLE: - Q->Mp = pj_mlfn(-M_HALFPI, -1., 0., Q->en); - break; - case EQUIT: - case OBLIQ: - P->inv = e_inverse; P->fwd = e_forward; - Q->N1 = 1. / sqrt(1. - P->es * Q->sinph0 * Q->sinph0); - Q->G = Q->sinph0 * (Q->He = P->e / sqrt(P->one_es)); - Q->He *= Q->cosph0; - break; - } - P->inv = e_inverse; - P->fwd = e_forward; - } - } - - return P; -} - - diff --git a/src/projections/PJ_airy.cpp b/src/projections/PJ_airy.cpp deleted file mode 100644 index 0eb5efd7..00000000 --- a/src/projections/PJ_airy.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the airy (Airy) projection. - * Author: Gerald Evenden (1995) - * Thomas Knudsen (2016) - revise/add regression tests - * - ****************************************************************************** - * Copyright (c) 1995, Gerald Evenden - * - * 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. - *****************************************************************************/ - -#define PJ_LIB__ -#include "proj.h" -#include -#include "projects.h" - -PROJ_HEAD(airy, "Airy") "\n\tMisc Sph, no inv\n\tno_cut lat_b="; - - -namespace { // anonymous namespace -enum Mode { - N_POLE = 0, - S_POLE = 1, - EQUIT = 2, - OBLIQ = 3 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double p_halfpi; - double sinph0; - double cosph0; - double Cb; - enum Mode mode; - int no_cut; /* do not cut at hemisphere limit */ -}; -} // anonymous namespace - - -# define EPS 1.e-10 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double sinlam, coslam, cosphi, sinphi, t, s, Krho, cosz; - - sinlam = sin(lp.lam); - coslam = cos(lp.lam); - switch (Q->mode) { - case EQUIT: - case OBLIQ: - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - cosz = cosphi * coslam; - if (Q->mode == OBLIQ) - cosz = Q->sinph0 * sinphi + Q->cosph0 * cosz; - if (!Q->no_cut && cosz < -EPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - if (fabs(s = 1. - cosz) > EPS) { - t = 0.5 * (1. + cosz); - Krho = -log(t)/s - Q->Cb / t; - } else - Krho = 0.5 - Q->Cb; - xy.x = Krho * cosphi * sinlam; - if (Q->mode == OBLIQ) - xy.y = Krho * (Q->cosph0 * sinphi - - Q->sinph0 * cosphi * coslam); - else - xy.y = Krho * sinphi; - break; - case S_POLE: - case N_POLE: - lp.phi = fabs(Q->p_halfpi - lp.phi); - if (!Q->no_cut && (lp.phi - EPS) > M_HALFPI) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - if ((lp.phi *= 0.5) > EPS) { - t = tan(lp.phi); - Krho = -2.*(log(cos(lp.phi)) / t + t * Q->Cb); - xy.x = Krho * sinlam; - xy.y = Krho * coslam; - if (Q->mode == N_POLE) - xy.y = -xy.y; - } else - xy.x = xy.y = 0.; - } - return xy; -} - - - - -PJ *PROJECTION(airy) { - double beta; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - - P->opaque = Q; - - Q->no_cut = pj_param(P->ctx, P->params, "bno_cut").i; - beta = 0.5 * (M_HALFPI - pj_param(P->ctx, P->params, "rlat_b").f); - if (fabs(beta) < EPS) - Q->Cb = -0.5; - else { - Q->Cb = 1./tan(beta); - Q->Cb *= Q->Cb * log(cos(beta)); - } - - if (fabs(fabs(P->phi0) - M_HALFPI) < EPS) - if (P->phi0 < 0.) { - Q->p_halfpi = -M_HALFPI; - Q->mode = S_POLE; - } else { - Q->p_halfpi = M_HALFPI; - Q->mode = N_POLE; - } - else { - if (fabs(P->phi0) < EPS) - Q->mode = EQUIT; - else { - Q->mode = OBLIQ; - Q->sinph0 = sin(P->phi0); - Q->cosph0 = cos(P->phi0); - } - } - P->fwd = s_forward; - P->es = 0.; - return P; -} - - diff --git a/src/projections/PJ_aitoff.cpp b/src/projections/PJ_aitoff.cpp deleted file mode 100644 index effd2c29..00000000 --- a/src/projections/PJ_aitoff.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the aitoff (Aitoff) and wintri (Winkel Tripel) - * projections. - * Author: Gerald Evenden (1995) - * Drazen Tutic, Lovro Gradiser (2015) - add inverse - * Thomas Knudsen (2016) - revise/add regression tests - * - ****************************************************************************** - * Copyright (c) 1995, Gerald Evenden - * - * 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - - -namespace { // anonymous namespace -enum Mode { - AITOFF = 0, - WINKEL_TRIPEL = 1 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double cosphi1; - enum Mode mode; -}; -} // anonymous namespace - - -PROJ_HEAD(aitoff, "Aitoff") "\n\tMisc Sph"; -PROJ_HEAD(wintri, "Winkel Tripel") "\n\tMisc Sph\n\tlat_1"; - - - -#if 0 -FORWARD(s_forward); /* spheroid */ -#endif - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double c, d; - - if((d = acos(cos(lp.phi) * cos(c = 0.5 * lp.lam))) != 0.0) {/* basic Aitoff */ - xy.x = 2. * d * cos(lp.phi) * sin(c) * (xy.y = 1. / sin(d)); - xy.y *= d * sin(lp.phi); - } else - xy.x = xy.y = 0.; - if (Q->mode == WINKEL_TRIPEL) { - xy.x = (xy.x + lp.lam * Q->cosphi1) * 0.5; - xy.y = (xy.y + lp.phi) * 0.5; - } - return (xy); -} - -/*********************************************************************************** -* -* Inverse functions added by Drazen Tutic and Lovro Gradiser based on paper: -* -* I.Özbug Biklirici and Cengizhan Ipbüker. A General Algorithm for the Inverse -* Transformation of Map Projections Using Jacobian Matrices. In Proceedings of the -* Third International Symposium Mathematical & Computational Applications, -* pages 175{182, Turkey, September 2002. -* -* Expected accuracy is defined by EPSILON = 1e-12. Should be appropriate for -* most applications of Aitoff and Winkel Tripel projections. -* -* Longitudes of 180W and 180E can be mixed in solution obtained. -* -* Inverse for Aitoff projection in poles is undefined, longitude value of 0 is assumed. -* -* Contact : dtutic@geof.hr -* Date: 2015-02-16 -* -************************************************************************************/ - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - int iter, MAXITER = 10, round = 0, MAXROUND = 20; - double EPSILON = 1e-12, D, C, f1, f2, f1p, f1l, f2p, f2l, dp, dl, sl, sp, cp, cl, x, y; - - if ((fabs(xy.x) < EPSILON) && (fabs(xy.y) < EPSILON )) { lp.phi = 0.; lp.lam = 0.; return lp; } - - /* initial values for Newton-Raphson method */ - lp.phi = xy.y; lp.lam = xy.x; - do { - iter = 0; - do { - sl = sin(lp.lam * 0.5); cl = cos(lp.lam * 0.5); - sp = sin(lp.phi); cp = cos(lp.phi); - D = cp * cl; - C = 1. - D * D; - D = acos(D) / pow(C, 1.5); - f1 = 2. * D * C * cp * sl; - f2 = D * C * sp; - f1p = 2.* (sl * cl * sp * cp / C - D * sp * sl); - f1l = cp * cp * sl * sl / C + D * cp * cl * sp * sp; - f2p = sp * sp * cl / C + D * sl * sl * cp; - f2l = 0.5 * (sp * cp * sl / C - D * sp * cp * cp * sl * cl); - if (Q->mode == WINKEL_TRIPEL) { - f1 = 0.5 * (f1 + lp.lam * Q->cosphi1); - f2 = 0.5 * (f2 + lp.phi); - f1p *= 0.5; - f1l = 0.5 * (f1l + Q->cosphi1); - f2p = 0.5 * (f2p + 1.); - f2l *= 0.5; - } - f1 -= xy.x; f2 -= xy.y; - dl = (f2 * f1p - f1 * f2p) / (dp = f1p * f2l - f2p * f1l); - dp = (f1 * f2l - f2 * f1l) / dp; - dl = fmod(dl, M_PI); /* set to interval [-M_PI, M_PI] */ - lp.phi -= dp; lp.lam -= dl; - } while ((fabs(dp) > EPSILON || fabs(dl) > EPSILON) && (iter++ < MAXITER)); - if (lp.phi > M_PI_2) lp.phi -= 2.*(lp.phi-M_PI_2); /* correct if symmetrical solution for Aitoff */ - if (lp.phi < -M_PI_2) lp.phi -= 2.*(lp.phi+M_PI_2); /* correct if symmetrical solution for Aitoff */ - if ((fabs(fabs(lp.phi) - M_PI_2) < EPSILON) && (Q->mode == AITOFF)) lp.lam = 0.; /* if pole in Aitoff, return longitude of 0 */ - - /* calculate x,y coordinates with solution obtained */ - if((D = acos(cos(lp.phi) * cos(C = 0.5 * lp.lam))) != 0.0) {/* Aitoff */ - x = 2. * D * cos(lp.phi) * sin(C) * (y = 1. / sin(D)); - y *= D * sin(lp.phi); - } else - x = y = 0.; - if (Q->mode == WINKEL_TRIPEL) { - x = (x + lp.lam * Q->cosphi1) * 0.5; - y = (y + lp.phi) * 0.5; - } - /* if too far from given values of x,y, repeat with better approximation of phi,lam */ - } while (((fabs(xy.x-x) > EPSILON) || (fabs(xy.y-y) > EPSILON)) && (round++ < MAXROUND)); - - if (iter == MAXITER && round == MAXROUND) - { - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); - /* fprintf(stderr, "Warning: Accuracy of 1e-12 not reached. Last increments: dlat=%e and dlon=%e\n", dp, dl); */ - } - - return lp; -} - - -static PJ *setup(PJ *P) { - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - return P; -} - - -PJ *PROJECTION(aitoff) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - Q->mode = AITOFF; - return setup(P); -} - - -PJ *PROJECTION(wintri) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - Q->mode = WINKEL_TRIPEL; - if (pj_param(P->ctx, P->params, "tlat_1").i) { - if ((Q->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f)) == 0.) - return pj_default_destructor (P, PJD_ERR_LAT_LARGER_THAN_90); - } - else /* 50d28' or acos(2/pi) */ - Q->cosphi1 = 0.636619772367581343; - return setup(P); -} diff --git a/src/projections/PJ_august.cpp b/src/projections/PJ_august.cpp deleted file mode 100644 index b5a21ef7..00000000 --- a/src/projections/PJ_august.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(august, "August Epicycloidal") "\n\tMisc Sph, no inv"; -#define M 1.333333333333333 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double t, c1, c, x1, x12, y1, y12; - (void) P; - - t = tan(.5 * lp.phi); - c1 = sqrt(1. - t * t); - c = 1. + c1 * cos(lp.lam *= .5); - x1 = sin(lp.lam) * c1 / c; - y1 = t / c; - xy.x = M * x1 * (3. + (x12 = x1 * x1) - 3. * (y12 = y1 * y1)); - xy.y = M * y1 * (3. + 3. * x12 - y12); - return (xy); -} - - - - -PJ *PROJECTION(august) { - P->inv = nullptr; - P->fwd = s_forward; - P->es = 0.; - return P; -} diff --git a/src/projections/PJ_bacon.cpp b/src/projections/PJ_bacon.cpp deleted file mode 100644 index 6c6350fe..00000000 --- a/src/projections/PJ_bacon.cpp +++ /dev/null @@ -1,81 +0,0 @@ -# define HLFPI2 2.46740110027233965467 /* (pi/2)^2 */ -# define EPS 1e-10 -#define PJ_LIB__ -#include -#include - -#include "projects.h" - - -namespace { // anonymous namespace -struct pj_opaque { - int bacn; - int ortl; -}; -} // anonymous namespace - -PROJ_HEAD(apian, "Apian Globular I") "\n\tMisc Sph, no inv"; -PROJ_HEAD(ortel, "Ortelius Oval") "\n\tMisc Sph, no inv"; -PROJ_HEAD(bacon, "Bacon Globular") "\n\tMisc Sph, no inv"; - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double ax, f; - - xy.y = Q->bacn ? M_HALFPI * sin(lp.phi) : lp.phi; - if ((ax = fabs(lp.lam)) >= EPS) { - if (Q->ortl && ax >= M_HALFPI) - xy.x = sqrt(HLFPI2 - lp.phi * lp.phi + EPS) + ax - M_HALFPI; - else { - f = 0.5 * (HLFPI2 / ax + ax); - xy.x = ax - f + sqrt(f * f - xy.y * xy.y); - } - if (lp.lam < 0.) xy.x = - xy.x; - } else - xy.x = 0.; - return (xy); -} - - - -PJ *PROJECTION(bacon) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->bacn = 1; - Q->ortl = 0; - P->es = 0.; - P->fwd = s_forward; - return P; -} - - -PJ *PROJECTION(apian) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->bacn = Q->ortl = 0; - P->es = 0.; - P->fwd = s_forward; - return P; -} - - -PJ *PROJECTION(ortel) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->bacn = 0; - Q->ortl = 1; - P->es = 0.; - P->fwd = s_forward; - return P; -} diff --git a/src/projections/PJ_bertin1953.cpp b/src/projections/PJ_bertin1953.cpp deleted file mode 100644 index 2203d6f1..00000000 --- a/src/projections/PJ_bertin1953.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - Created by Jacques Bertin in 1953, this projection was the go-to choice - of the French cartographic school when they wished to represent phenomena - on a global scale. - - Formula designed by Philippe Rivière, 2017. - https://visionscarto.net/bertin-projection-1953 - - Port to PROJ by Philippe Rivière, 21 September 2018 -*/ - -#define PJ_LIB__ - -#include -#include - -#include "proj_internal.h" -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(bertin1953, "Bertin 1953") - "\n\tMisc Sph no inv."; - -namespace { // anonymous namespace -struct pj_opaque { - double cos_delta_phi, sin_delta_phi, cos_delta_gamma, sin_delta_gamma, deltaLambda; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - double fu = 1.4, k = 12., w = 1.68, d; - - /* Rotate */ - double cosphi, x, y, z, z0; - lp.lam += PJ_TORAD(-16.5); - cosphi = cos(lp.phi); - x = cos(lp.lam) * cosphi; - y = sin(lp.lam) * cosphi; - z = sin(lp.phi); - z0 = z * Q->cos_delta_phi + x * Q->sin_delta_phi; - lp.lam = atan2(y * Q->cos_delta_gamma - z0 * Q->sin_delta_gamma, - x * Q->cos_delta_phi - z * Q->sin_delta_phi); - z0 = z0 * Q->cos_delta_gamma + y * Q->sin_delta_gamma; - lp.phi = asin(z0); - - lp.lam = adjlon(lp.lam); - - /* Adjust pre-projection */ - if (lp.lam + lp.phi < -fu) { - d = (lp.lam - lp.phi + 1.6) * (lp.lam + lp.phi + fu) / 8.; - lp.lam += d; - lp.phi -= 0.8 * d * sin(lp.phi + M_PI / 2.); - } - - /* Project with Hammer (1.68,2) */ - cosphi = cos(lp.phi); - d = sqrt(2./(1. + cosphi * cos(lp.lam / 2.))); - xy.x = w * d * cosphi * sin(lp.lam / 2.); - xy.y = d * sin(lp.phi); - - /* Adjust post-projection */ - d = (1. - cos(lp.lam * lp.phi)) / k; - if (xy.y < 0.) { - xy.x *= 1. + d; - } - if (xy.y > 0.) { - xy.x *= 1. + d / 1.5 * xy.x * xy.x; - } - - return xy; -} - - -PJ *PROJECTION(bertin1953) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - P->lam0 = 0; - P->phi0 = PJ_TORAD(-42.); - - Q->cos_delta_phi = cos(P->phi0); - Q->sin_delta_phi = sin(P->phi0); - Q->cos_delta_gamma = 1.; - Q->sin_delta_gamma = 0.; - - P->es = 0.; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_bipc.cpp b/src/projections/PJ_bipc.cpp deleted file mode 100644 index 19a6bbe1..00000000 --- a/src/projections/PJ_bipc.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#define PJ_LIB__ -#include -#include - -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -PROJ_HEAD(bipc, "Bipolar conic of western hemisphere") "\n\tConic Sph"; - -# define EPS 1e-10 -# define EPS10 1e-10 -# define ONEEPS 1.000000001 -# define NITER 10 -# define lamB -.34894976726250681539 -# define n .63055844881274687180 -# define F 1.89724742567461030582 -# define Azab .81650043674686363166 -# define Azba 1.82261843856185925133 -# define T 1.27246578267089012270 -# define rhoc 1.20709121521568721927 -# define cAzc .69691523038678375519 -# define sAzc .71715351331143607555 -# define C45 .70710678118654752469 -# define S45 .70710678118654752410 -# define C20 .93969262078590838411 -# define S20 -.34202014332566873287 -# define R110 1.91986217719376253360 -# define R104 1.81514242207410275904 - - -namespace { // anonymous namespace -struct pj_opaque { - int noskew; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r; - int tag; - - cphi = cos(lp.phi); - sphi = sin(lp.phi); - cdlam = cos(sdlam = lamB - lp.lam); - sdlam = sin(sdlam); - if (fabs(fabs(lp.phi) - M_HALFPI) < EPS10) { - Az = lp.phi < 0. ? M_PI : 0.; - tphi = HUGE_VAL; - } else { - tphi = sphi / cphi; - Az = atan2(sdlam , C45 * (tphi - cdlam)); - } - if( (tag = (Az > Azba)) ) { - cdlam = cos(sdlam = lp.lam + R110); - sdlam = sin(sdlam); - z = S20 * sphi + C20 * cphi * cdlam; - if (fabs(z) > 1.) { - if (fabs(z) > ONEEPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - else z = z < 0. ? -1. : 1.; - } else - z = acos(z); - if (tphi != HUGE_VAL) - Az = atan2(sdlam, (C20 * tphi - S20 * cdlam)); - Av = Azab; - xy.y = rhoc; - } else { - z = S45 * (sphi + cphi * cdlam); - if (fabs(z) > 1.) { - if (fabs(z) > ONEEPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - else z = z < 0. ? -1. : 1.; - } else - z = acos(z); - Av = Azba; - xy.y = -rhoc; - } - if (z < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - r = F * (t = pow(tan(.5 * z), n)); - if ((al = .5 * (R104 - z)) < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - al = (t + pow(al, n)) / T; - if (fabs(al) > 1.) { - if (fabs(al) > ONEEPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - else al = al < 0. ? -1. : 1.; - } else - al = acos(al); - if (fabs(t = n * (Av - Az)) < al) - r /= cos(al + (tag ? t : -t)); - xy.x = r * sin(t); - xy.y += (tag ? -r : r) * cos(t); - if (Q->noskew) { - t = xy.x; - xy.x = -xy.x * cAzc - xy.y * sAzc; - xy.y = -xy.y * cAzc + t * sAzc; - } - return (xy); -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double t, r, rp, rl, al, z = 0.0, fAz, Az, s, c, Av; - int neg, i; - - if (Q->noskew) { - t = xy.x; - xy.x = -xy.x * cAzc + xy.y * sAzc; - xy.y = -xy.y * cAzc - t * sAzc; - } - if( (neg = (xy.x < 0.)) ) { - xy.y = rhoc - xy.y; - s = S20; - c = C20; - Av = Azab; - } else { - xy.y += rhoc; - s = S45; - c = C45; - Av = Azba; - } - rl = rp = r = hypot(xy.x, xy.y); - fAz = fabs(Az = atan2(xy.x, xy.y)); - for (i = NITER; i ; --i) { - z = 2. * atan(pow(r / F,1 / n)); - al = acos((pow(tan(.5 * z), n) + - pow(tan(.5 * (R104 - z)), n)) / T); - if (fAz < al) - r = rp * cos(al + (neg ? Az : -Az)); - if (fabs(rl - r) < EPS) - break; - rl = r; - } - if (! i) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - Az = Av - Az / n; - lp.phi = asin(s * cos(z) + c * sin(z) * cos(Az)); - lp.lam = atan2(sin(Az), c / tan(z) - s * cos(Az)); - if (neg) - lp.lam -= R110; - else - lp.lam = lamB - lp.lam; - return (lp); -} - - -PJ *PROJECTION(bipc) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->noskew = pj_param(P->ctx, P->params, "bns").i; - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - return P; -} diff --git a/src/projections/PJ_boggs.cpp b/src/projections/PJ_boggs.cpp deleted file mode 100644 index 119357c0..00000000 --- a/src/projections/PJ_boggs.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#define PJ_LIB__ -#include - -#include "projects.h" - -PROJ_HEAD(boggs, "Boggs Eumorphic") "\n\tPCyl, no inv, Sph"; -# define NITER 20 -# define EPS 1e-7 -# define FXC 2.00276 -# define FXC2 1.11072 -# define FYC 0.49931 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double theta, th1, c; - int i; - (void) P; - - theta = lp.phi; - if (fabs(fabs(lp.phi) - M_HALFPI) < EPS) - xy.x = 0.; - else { - c = sin(theta) * M_PI; - for (i = NITER; i; --i) { - theta -= th1 = (theta + sin(theta) - c) / - (1. + cos(theta)); - if (fabs(th1) < EPS) break; - } - theta *= 0.5; - xy.x = FXC * lp.lam / (1. / cos(lp.phi) + FXC2 / cos(theta)); - } - xy.y = FYC * (lp.phi + M_SQRT2 * sin(theta)); - return (xy); -} - - - -PJ *PROJECTION(boggs) { - P->es = 0.; - P->fwd = s_forward; - return P; -} diff --git a/src/projections/PJ_bonne.cpp b/src/projections/PJ_bonne.cpp deleted file mode 100644 index 385c1c4b..00000000 --- a/src/projections/PJ_bonne.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - - -PROJ_HEAD(bonne, "Bonne (Werner lat_1=90)") - "\n\tConic Sph&Ell\n\tlat_1="; -#define EPS10 1e-10 - -namespace { // anonymous namespace -struct pj_opaque { - double phi1; - double cphi1; - double am1; - double m1; - double *en; -}; -} // anonymous namespace - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double rh, E, c; - - rh = Q->am1 + Q->m1 - pj_mlfn(lp.phi, E = sin(lp.phi), c = cos(lp.phi), Q->en); - E = c * lp.lam / (rh * sqrt(1. - P->es * E * E)); - xy.x = rh * sin(E); - xy.y = Q->am1 - rh * cos(E); - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double E, rh; - - rh = Q->cphi1 + Q->phi1 - lp.phi; - if (fabs(rh) > EPS10) { - xy.x = rh * sin(E = lp.lam * cos(lp.phi) / rh); - xy.y = Q->cphi1 - rh * cos(E); - } else - xy.x = xy.y = 0.; - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double rh; - - rh = hypot(xy.x, xy.y = Q->cphi1 - xy.y); - lp.phi = Q->cphi1 + Q->phi1 - rh; - if (fabs(lp.phi) > M_HALFPI) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) - lp.lam = 0.; - else - lp.lam = rh * atan2(xy.x, xy.y) / cos(lp.phi); - return lp; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double s, rh; - - rh = hypot(xy.x, xy.y = Q->am1 - xy.y); - lp.phi = pj_inv_mlfn(P->ctx, Q->am1 + Q->m1 - rh, P->es, Q->en); - if ((s = fabs(lp.phi)) < M_HALFPI) { - s = sin(lp.phi); - lp.lam = rh * atan2(xy.x, xy.y) * - sqrt(1. - P->es * s * s) / cos(lp.phi); - } else if (fabs(s - M_HALFPI) <= EPS10) - lp.lam = 0.; - else { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - return lp; -} - - - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - -PJ *PROJECTION(bonne) { - double c; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; - if (fabs(Q->phi1) < EPS10) - return destructor (P, PJD_ERR_LAT1_IS_ZERO); - - if (P->es != 0.0) { - Q->en = pj_enfn(P->es); - if (nullptr==Q->en) - return destructor(P, ENOMEM); - Q->m1 = pj_mlfn(Q->phi1, Q->am1 = sin(Q->phi1), - c = cos(Q->phi1), Q->en); - Q->am1 = c / (sqrt(1. - P->es * Q->am1 * Q->am1) * Q->am1); - P->inv = e_inverse; - P->fwd = e_forward; - } else { - if (fabs(Q->phi1) + EPS10 >= M_HALFPI) - Q->cphi1 = 0.; - else - Q->cphi1 = 1. / tan(Q->phi1); - P->inv = s_inverse; - P->fwd = s_forward; - } - return P; -} - - diff --git a/src/projections/PJ_calcofi.cpp b/src/projections/PJ_calcofi.cpp deleted file mode 100644 index e81e4d2a..00000000 --- a/src/projections/PJ_calcofi.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" -#include "proj_api.h" - -PROJ_HEAD(calcofi, - "Cal Coop Ocean Fish Invest Lines/Stations") "\n\tCyl, Sph&Ell"; - - -/* Conversions for the California Cooperative Oceanic Fisheries Investigations -Line/Station coordinate system following the algorithm of: -Eber, L.E., and R.P. Hewitt. 1979. Conversion algorithms for the CalCOFI -station grid. California Cooperative Oceanic Fisheries Investigations Reports -20:135-137. (corrected for typographical errors). -http://www.calcofi.org/publications/calcofireports/v20/Vol_20_Eber___Hewitt.pdf -They assume 1 unit of CalCOFI Line == 1/5 degree in longitude or -meridional units at reference point O, and similarly 1 unit of CalCOFI -Station == 1/15 of a degree at O. -By convention, CalCOFI Line/Station conversions use Clarke 1866 but we use -whatever ellipsoid is provided. */ - - -#define EPS10 1.e-10 -#define DEG_TO_LINE 5 -#define DEG_TO_STATION 15 -#define LINE_TO_RAD 0.0034906585039886592 -#define STATION_TO_RAD 0.0011635528346628863 -#define PT_O_LINE 80 /* reference point O is at line 80, */ -#define PT_O_STATION 60 /* station 60, */ -#define PT_O_LAMBDA -2.1144663887911301 /* lon -121.15 and */ -#define PT_O_PHI 0.59602993955606354 /* lat 34.15 */ -#define ROTATION_ANGLE 0.52359877559829882 /*CalCOFI angle of 30 deg in rad */ - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - double oy; /* pt O y value in Mercator */ - double l1; /* l1 and l2 are distances calculated using trig that sum - to the east/west distance between point O and point xy */ - double l2; - double ry; /* r is the point on the same station as o (60) and the same - line as xy xy, r, o form a right triangle */ - - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - - xy.x = lp.lam; - xy.y = -log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); /* Mercator transform xy*/ - oy = -log(pj_tsfn(PT_O_PHI, sin(PT_O_PHI), P->e)); - l1 = (xy.y - oy) * tan(ROTATION_ANGLE); - l2 = -xy.x - l1 + PT_O_LAMBDA; - ry = l2 * cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE) + xy.y; - ry = pj_phi2(P->ctx, exp(-ry), P->e); /*inverse Mercator*/ - xy.x = PT_O_LINE - RAD_TO_DEG * - (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE); - xy.y = PT_O_STATION + RAD_TO_DEG * - (ry - lp.phi) * DEG_TO_STATION / sin(ROTATION_ANGLE); - /* set a = 1, x0 = 0, and y0 = 0 so that no further unit adjustments - are done */ - - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double oy; - double l1; - double l2; - double ry; - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.x = lp.lam; - xy.y = log(tan(M_FORTPI + .5 * lp.phi)); - oy = log(tan(M_FORTPI + .5 * PT_O_PHI)); - l1 = (xy.y - oy) * tan(ROTATION_ANGLE); - l2 = -xy.x - l1 + PT_O_LAMBDA; - ry = l2 * cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE) + xy.y; - ry = M_HALFPI - 2. * atan(exp(-ry)); - xy.x = PT_O_LINE - RAD_TO_DEG * - (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE); - xy.y = PT_O_STATION + RAD_TO_DEG * - (ry - lp.phi) * DEG_TO_STATION / sin(ROTATION_ANGLE); - - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - double ry; /* y value of point r */ - double oymctr; /* Mercator-transformed y value of point O */ - double rymctr; /* Mercator-transformed ry */ - double xymctr; /* Mercator-transformed xy.y */ - double l1; - double l2; - - ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) * - cos(ROTATION_ANGLE); - lp.phi = ry - STATION_TO_RAD * (xy.y - PT_O_STATION) * sin(ROTATION_ANGLE); - oymctr = -log(pj_tsfn(PT_O_PHI, sin(PT_O_PHI), P->e)); - rymctr = -log(pj_tsfn(ry, sin(ry), P->e)); - xymctr = -log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); - l1 = (xymctr - oymctr) * tan(ROTATION_ANGLE); - l2 = (rymctr - xymctr) / (cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE)); - lp.lam = PT_O_LAMBDA - (l1 + l2); - - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double ry; - double oymctr; - double rymctr; - double xymctr; - double l1; - double l2; - (void) P; - - ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) * - cos(ROTATION_ANGLE); - lp.phi = ry - STATION_TO_RAD * (xy.y - PT_O_STATION) * sin(ROTATION_ANGLE); - oymctr = log(tan(M_FORTPI + .5 * PT_O_PHI)); - rymctr = log(tan(M_FORTPI + .5 * ry)); - xymctr = log(tan(M_FORTPI + .5 * lp.phi)); - l1 = (xymctr - oymctr) * tan(ROTATION_ANGLE); - l2 = (rymctr - xymctr) / (cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE)); - lp.lam = PT_O_LAMBDA - (l1 + l2); - - return lp; -} - - -PJ *PROJECTION(calcofi) { - P->opaque = nullptr; - - /* if the user has specified +lon_0 or +k0 for some reason, - we're going to ignore it so that xy is consistent with point O */ - P->lam0 = 0; - P->ra = 1; - P->a = 1; - P->x0 = 0; - P->y0 = 0; - P->over = 1; - - if (P->es != 0.0) { /* ellipsoid */ - P->inv = e_inverse; - P->fwd = e_forward; - } else { /* sphere */ - P->inv = s_inverse; - P->fwd = s_forward; - } - return P; -} diff --git a/src/projections/PJ_cass.cpp b/src/projections/PJ_cass.cpp deleted file mode 100644 index c831558c..00000000 --- a/src/projections/PJ_cass.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(cass, "Cassini") "\n\tCyl, Sph&Ell"; - - -# define C1 .16666666666666666666 -# define C2 .00833333333333333333 -# define C3 .04166666666666666666 -# define C4 .33333333333333333333 -# define C5 .06666666666666666666 - - -namespace { // anonymous namespace -struct pj_opaque { - double *en; - double m0; -}; -} // anonymous namespace - - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - double n, t, a1, c, a2, tn; - XY xy = {0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - xy.y = pj_mlfn (lp.phi, n = sin (lp.phi), c = cos (lp.phi), Q->en); - - n = 1./sqrt(1. - P->es * n*n); - tn = tan(lp.phi); t = tn * tn; - a1 = lp.lam * c; - c *= P->es * c / (1 - P->es); - a2 = a1 * a1; - - xy.x = n * a1 * (1. - a2 * t * - (C1 - (8. - t + 8. * c) * a2 * C2)); - xy.y -= Q->m0 - n * tn * a2 * - (.5 + (5. - t + 6. * c) * a2 * C3); - - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - xy.x = asin (cos (lp.phi) * sin (lp.lam)); - xy.y = atan2 (tan (lp.phi), cos (lp.lam)) - P->phi0; - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - double n, t, r, dd, d2, tn, ph1; - LP lp = {0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - ph1 = pj_inv_mlfn (P->ctx, Q->m0 + xy.y, P->es, Q->en); - tn = tan (ph1); t = tn*tn; - n = sin (ph1); - r = 1. / (1. - P->es * n * n); - n = sqrt (r); - r *= (1. - P->es) * n; - dd = xy.x / n; - d2 = dd * dd; - lp.phi = ph1 - (n * tn / r) * d2 * - (.5 - (1. + 3. * t) * d2 * C3); - lp.lam = dd * (1. + t * d2 * - (-C4 + (1. + 3. * t) * d2 * C5)) / cos (ph1); - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double dd; - lp.phi = asin(sin(dd = xy.y + P->phi0) * cos(xy.x)); - lp.lam = atan2(tan(xy.x), cos(dd)); - return lp; -} - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - - -PJ *PROJECTION(cass) { - - /* Spheroidal? */ - if (0==P->es) { - P->inv = s_inverse; - P->fwd = s_forward; - return P; - } - - /* otherwise it's ellipsoidal */ - P->opaque = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==P->opaque) - return pj_default_destructor (P, ENOMEM); - P->destructor = destructor; - - static_cast(P->opaque)->en = pj_enfn (P->es); - if (nullptr==static_cast(P->opaque)->en) - return pj_default_destructor (P, ENOMEM); - - static_cast(P->opaque)->m0 = pj_mlfn (P->phi0, sin (P->phi0), cos (P->phi0), static_cast(P->opaque)->en); - P->inv = e_inverse; - P->fwd = e_forward; - - return P; -} diff --git a/src/projections/PJ_cc.cpp b/src/projections/PJ_cc.cpp deleted file mode 100644 index 152e6e4a..00000000 --- a/src/projections/PJ_cc.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(cc, "Central Cylindrical") "\n\tCyl, Sph"; -#define EPS10 1.e-10 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - if (fabs (fabs(lp.phi) - M_HALFPI) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.x = lp.lam; - xy.y = tan(lp.phi); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - (void) P; - lp.phi = atan(xy.y); - lp.lam = xy.x; - return lp; -} - - - -PJ *PROJECTION(cc) { - P->es = 0.; - - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_ccon.cpp b/src/projections/PJ_ccon.cpp deleted file mode 100644 index 4f7dedb4..00000000 --- a/src/projections/PJ_ccon.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/****************************************************************************** - * Copyright (c) 2017, Lukasz Komsta - * - * 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. - *****************************************************************************/ - -#define PJ_LIB__ -#include -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -#define EPS10 1e-10 - -namespace { // anonymous namespace -struct pj_opaque { - double phi1; - double ctgphi1; - double sinphi1; - double cosphi1; - double *en; -}; -} // anonymous namespace - -PROJ_HEAD(ccon, "Central Conic") - "\n\tCentral Conic, Sph\n\tlat_1="; - - - -static XY forward (LP lp, PJ *P) { - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double r; - - r = Q->ctgphi1 - tan(lp.phi - Q->phi1); - xy.x = r * sin(lp.lam * Q->sinphi1); - xy.y = Q->ctgphi1 - r * cos(lp.lam * Q->sinphi1); - - return xy; -} - - -static LP inverse (XY xy, PJ *P) { - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - xy.y = Q->ctgphi1 - xy.y; - lp.phi = Q->phi1 - atan(hypot(xy.x,xy.y) - Q->ctgphi1); - lp.lam = atan2(xy.x,xy.y)/Q->sinphi1; - - return lp; -} - - -static PJ *destructor (PJ *P, int errlev) { - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - -PJ *PROJECTION(ccon) { - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; - if (fabs(Q->phi1) < EPS10) - return destructor (P, PJD_ERR_LAT1_IS_ZERO); - - if (!(Q->en = pj_enfn(P->es))) - return destructor(P, ENOMEM); - - Q->sinphi1 = sin(Q->phi1); - Q->cosphi1 = cos(Q->phi1); - Q->ctgphi1 = Q->cosphi1/Q->sinphi1; - - - P->inv = inverse; - P->fwd = forward; - - return P; -} - - diff --git a/src/projections/PJ_cea.cpp b/src/projections/PJ_cea.cpp deleted file mode 100644 index f8275b62..00000000 --- a/src/projections/PJ_cea.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - double qp; - double *apa; -}; -} // anonymous namespace - -PROJ_HEAD(cea, "Equal Area Cylindrical") "\n\tCyl, Sph&Ell\n\tlat_ts="; -# define EPS 1e-10 - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - xy.x = P->k0 * lp.lam; - xy.y = 0.5 * pj_qsfn (sin (lp.phi), P->e, P->one_es) / P->k0; - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - xy.x = P->k0 * lp.lam; - xy.y = sin(lp.phi) / P->k0; - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - lp.phi = pj_authlat(asin( 2. * xy.y * P->k0 / static_cast(P->opaque)->qp), static_cast(P->opaque)->apa); - lp.lam = xy.x / P->k0; - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double t; - - if ((t = fabs(xy.y *= P->k0)) - EPS <= 1.) { - if (t >= 1.) - lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; - else - lp.phi = asin(xy.y); - lp.lam = xy.x / P->k0; - } else { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - return (lp); -} - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->apa); - return pj_default_destructor (P, errlev); -} - - -PJ *PROJECTION(cea) { - double t = 0.0; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - - if (pj_param(P->ctx, P->params, "tlat_ts").i) { - P->k0 = cos(t = pj_param(P->ctx, P->params, "rlat_ts").f); - if (P->k0 < 0.) - return pj_default_destructor (P, PJD_ERR_LAT_TS_LARGER_THAN_90); - } - if (P->es != 0.0) { - t = sin(t); - P->k0 /= sqrt(1. - P->es * t * t); - P->e = sqrt(P->es); - if (!(Q->apa = pj_authset(P->es))) - return pj_default_destructor(P, ENOMEM); - - Q->qp = pj_qsfn(1., P->e, P->one_es); - P->inv = e_inverse; - P->fwd = e_forward; - } else { - P->inv = s_inverse; - P->fwd = s_forward; - } - - return P; -} diff --git a/src/projections/PJ_chamb.cpp b/src/projections/PJ_chamb.cpp deleted file mode 100644 index a490e817..00000000 --- a/src/projections/PJ_chamb.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -typedef struct { double r, Az; } VECT; -namespace { // anonymous namespace -struct pj_opaque { - struct { /* control point data */ - double phi, lam; - double cosphi, sinphi; - VECT v; - XY p; - double Az; - } c[3]; - XY p; - double beta_0, beta_1, beta_2; -}; -} // anonymous namespace - -PROJ_HEAD(chamb, "Chamberlin Trimetric") "\n\tMisc Sph, no inv" -"\n\tlat_1= lon_1= lat_2= lon_2= lat_3= lon_3="; - -#include -#define THIRD 0.333333333333333333 -#define TOL 1e-9 - -/* distance and azimuth from point 1 to point 2 */ -static VECT vect(projCtx ctx, double dphi, double c1, double s1, double c2, double s2, double dlam) { - VECT v; - double cdl, dp, dl; - - cdl = cos(dlam); - if (fabs(dphi) > 1. || fabs(dlam) > 1.) - v.r = aacos(ctx, s1 * s2 + c1 * c2 * cdl); - else { /* more accurate for smaller distances */ - dp = sin(.5 * dphi); - dl = sin(.5 * dlam); - v.r = 2. * aasin(ctx,sqrt(dp * dp + c1 * c2 * dl * dl)); - } - if (fabs(v.r) > TOL) - v.Az = atan2(c2 * sin(dlam), c1 * s2 - s1 * c2 * cdl); - else - v.r = v.Az = 0.; - return v; -} - -/* law of cosines */ -static double lc(projCtx ctx, double b,double c,double a) { - return aacos(ctx, .5 * (b * b + c * c - a * a) / (b * c)); -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy; - struct pj_opaque *Q = static_cast(P->opaque); - double sinphi, cosphi, a; - VECT v[3]; - int i, j; - - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - for (i = 0; i < 3; ++i) { /* dist/azimiths from control */ - v[i] = vect(P->ctx, lp.phi - Q->c[i].phi, Q->c[i].cosphi, Q->c[i].sinphi, - cosphi, sinphi, lp.lam - Q->c[i].lam); - if (v[i].r == 0.0) - break; - v[i].Az = adjlon(v[i].Az - Q->c[i].v.Az); - } - if (i < 3) /* current point at control point */ - xy = Q->c[i].p; - else { /* point mean of intersepts */ - xy = Q->p; - for (i = 0; i < 3; ++i) { - j = i == 2 ? 0 : i + 1; - a = lc(P->ctx,Q->c[i].v.r, v[i].r, v[j].r); - if (v[i].Az < 0.) - a = -a; - if (! i) { /* coord comp unique to each arc */ - xy.x += v[i].r * cos(a); - xy.y -= v[i].r * sin(a); - } else if (i == 1) { - a = Q->beta_1 - a; - xy.x -= v[i].r * cos(a); - xy.y -= v[i].r * sin(a); - } else { - a = Q->beta_2 - a; - xy.x += v[i].r * cos(a); - xy.y += v[i].r * sin(a); - } - } - xy.x *= THIRD; /* mean of arc intercepts */ - xy.y *= THIRD; - } - return xy; -} - - - -PJ *PROJECTION(chamb) { - int i, j; - char line[10]; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - - for (i = 0; i < 3; ++i) { /* get control point locations */ - (void)sprintf(line, "rlat_%d", i+1); - Q->c[i].phi = pj_param(P->ctx, P->params, line).f; - (void)sprintf(line, "rlon_%d", i+1); - Q->c[i].lam = pj_param(P->ctx, P->params, line).f; - Q->c[i].lam = adjlon(Q->c[i].lam - P->lam0); - Q->c[i].cosphi = cos(Q->c[i].phi); - Q->c[i].sinphi = sin(Q->c[i].phi); - } - for (i = 0; i < 3; ++i) { /* inter ctl pt. distances and azimuths */ - j = i == 2 ? 0 : i + 1; - Q->c[i].v = vect(P->ctx,Q->c[j].phi - Q->c[i].phi, Q->c[i].cosphi, Q->c[i].sinphi, - Q->c[j].cosphi, Q->c[j].sinphi, Q->c[j].lam - Q->c[i].lam); - if (Q->c[i].v.r == 0.0) - return pj_default_destructor (P, PJD_ERR_CONTROL_POINT_NO_DIST); - /* co-linearity problem ignored for now */ - } - Q->beta_0 = lc(P->ctx,Q->c[0].v.r, Q->c[2].v.r, Q->c[1].v.r); - Q->beta_1 = lc(P->ctx,Q->c[0].v.r, Q->c[1].v.r, Q->c[2].v.r); - Q->beta_2 = M_PI - Q->beta_0; - Q->p.y = 2. * (Q->c[0].p.y = Q->c[1].p.y = Q->c[2].v.r * sin(Q->beta_0)); - Q->c[2].p.y = 0.; - Q->c[0].p.x = - (Q->c[1].p.x = 0.5 * Q->c[0].v.r); - Q->p.x = Q->c[2].p.x = Q->c[0].p.x + Q->c[2].v.r * cos(Q->beta_0); - - P->es = 0.; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_collg.cpp b/src/projections/PJ_collg.cpp deleted file mode 100644 index 7904de29..00000000 --- a/src/projections/PJ_collg.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(collg, "Collignon") "\n\tPCyl, Sph"; -#define FXC 1.12837916709551257390 -#define FYC 1.77245385090551602729 -#define ONEEPS 1.0000001 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - if ((xy.y = 1. - sin(lp.phi)) <= 0.) - xy.y = 0.; - else - xy.y = sqrt(xy.y); - xy.x = FXC * lp.lam * xy.y; - xy.y = FYC * (1. - xy.y); - return (xy); -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - lp.phi = xy.y / FYC - 1.; - if (fabs(lp.phi = 1. - lp.phi * lp.phi) < 1.) - lp.phi = asin(lp.phi); - else if (fabs(lp.phi) > ONEEPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } else { - lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; - } - - if ((lp.lam = 1. - sin(lp.phi)) <= 0.) - lp.lam = 0.; - else - lp.lam = xy.x / (FXC * sqrt(lp.lam)); - return (lp); -} - - -PJ *PROJECTION(collg) { - P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_comill.cpp b/src/projections/PJ_comill.cpp deleted file mode 100644 index b6e0192e..00000000 --- a/src/projections/PJ_comill.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* -The Compact Miller projection was designed by Tom Patterson, US National -Park Service, in 2014. The polynomial equation was developed by Bojan -Savric and Bernhard Jenny, College of Earth, Ocean, and Atmospheric -Sciences, Oregon State University. -Port to PROJ.4 by Bojan Savric, 4 April 2016 -*/ - -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(comill, "Compact Miller") "\n\tCyl, Sph"; - -#define K1 0.9902 -#define K2 0.1604 -#define K3 -0.03054 -#define C1 K1 -#define C2 (3 * K2) -#define C3 (5 * K3) -#define EPS 1e-11 -#define MAX_Y (0.6000207669862655 * M_PI) -/* Not sure at all of the appropriate number for MAX_ITER... */ -#define MAX_ITER 100 - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double lat_sq; - - (void) P; /* silence unused parameter warnings */ - - lat_sq = lp.phi * lp.phi; - xy.x = lp.lam; - xy.y = lp.phi * (K1 + lat_sq * (K2 + K3 * lat_sq)); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double yc, tol, y2, f, fder; - int i; - - (void) P; /* silence unused parameter warnings */ - - /* make sure y is inside valid range */ - if (xy.y > MAX_Y) { - xy.y = MAX_Y; - } else if (xy.y < -MAX_Y) { - xy.y = -MAX_Y; - } - - /* latitude */ - yc = xy.y; - for (i = MAX_ITER; i ; --i) { /* Newton-Raphson */ - y2 = yc * yc; - f = (yc * (K1 + y2 * (K2 + K3 * y2))) - xy.y; - fder = C1 + y2 * (C2 + C3 * y2); - yc -= tol = f / fder; - if (fabs(tol) < EPS) { - break; - } - } - if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); - lp.phi = yc; - - /* longitude */ - lp.lam = xy.x; - - return lp; -} - - -PJ *PROJECTION(comill) { - P->es = 0; - - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_crast.cpp b/src/projections/PJ_crast.cpp deleted file mode 100644 index 4e4dee8b..00000000 --- a/src/projections/PJ_crast.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#define PJ_LIB__ -#include - -#include "projects.h" - -PROJ_HEAD(crast, "Craster Parabolic (Putnins P4)") "\n\tPCyl, Sph"; - -#define XM 0.97720502380583984317 -#define RXM 1.02332670794648848847 -#define YM 3.06998012383946546542 -#define RYM 0.32573500793527994772 -#define THIRD 0.333333333333333333 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - lp.phi *= THIRD; - xy.x = XM * lp.lam * (2. * cos(lp.phi + lp.phi) - 1.); - xy.y = YM * sin(lp.phi); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - (void) P; - lp.phi = 3. * asin(xy.y * RYM); - lp.lam = xy.x * RXM / (2. * cos((lp.phi + lp.phi) * THIRD) - 1); - return lp; -} - - -PJ *PROJECTION(crast) { - P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_denoy.cpp b/src/projections/PJ_denoy.cpp deleted file mode 100644 index 5c337c45..00000000 --- a/src/projections/PJ_denoy.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#define PJ_LIB__ -#include - -#include "projects.h" - -PROJ_HEAD(denoy, "Denoyer Semi-Elliptical") "\n\tPCyl, no inv, Sph"; - -#define C0 0.95 -#define C1 -0.08333333333333333333 -#define C3 0.00166666666666666666 -#define D1 0.9 -#define D5 0.03 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - (void) P; - xy.y = lp.phi; - xy.x = lp.lam; - lp.lam = fabs(lp.lam); - xy.x *= cos((C0 + lp.lam * (C1 + lp.lam * lp.lam * C3)) * - (lp.phi * (D1 + D5 * lp.phi * lp.phi * lp.phi * lp.phi))); - return xy; -} - - -PJ *PROJECTION(denoy) { - P->es = 0.0; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_eck1.cpp b/src/projections/PJ_eck1.cpp deleted file mode 100644 index 88a7430c..00000000 --- a/src/projections/PJ_eck1.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#define PJ_LIB__ -#include - -#include "projects.h" - -PROJ_HEAD(eck1, "Eckert I") "\n\tPCyl, Sph"; -#define FC 0.92131773192356127802 -#define RP 0.31830988618379067154 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - xy.x = FC * lp.lam * (1. - RP * fabs(lp.phi)); - xy.y = FC * lp.phi; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - (void) P; - - lp.phi = xy.y / FC; - lp.lam = xy.x / (FC * (1. - RP * fabs(lp.phi))); - - return (lp); -} - - - -PJ *PROJECTION(eck1) { - P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P -; -} diff --git a/src/projections/PJ_eck2.cpp b/src/projections/PJ_eck2.cpp deleted file mode 100644 index f76ab4ec..00000000 --- a/src/projections/PJ_eck2.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(eck2, "Eckert II") "\n\tPCyl, Sph"; - -#define FXC 0.46065886596178063902 -#define FYC 1.44720250911653531871 -#define C13 0.33333333333333333333 -#define ONEEPS 1.0000001 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - xy.x = FXC * lp.lam * (xy.y = sqrt(4. - 3. * sin(fabs(lp.phi)))); - xy.y = FYC * (2. - xy.y); - if ( lp.phi < 0.) xy.y = -xy.y; - - return (xy); -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - (void) P; - - lp.lam = xy.x / (FXC * ( lp.phi = 2. - fabs(xy.y) / FYC) ); - lp.phi = (4. - lp.phi * lp.phi) * C13; - if (fabs(lp.phi) >= 1.) { - if (fabs(lp.phi) > ONEEPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } else { - lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; - } - } else - lp.phi = asin(lp.phi); - if (xy.y < 0) - lp.phi = -lp.phi; - return (lp); -} - - - -PJ *PROJECTION(eck2) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_eck3.cpp b/src/projections/PJ_eck3.cpp deleted file mode 100644 index 90376631..00000000 --- a/src/projections/PJ_eck3.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(eck3, "Eckert III") "\n\tPCyl, Sph"; -PROJ_HEAD(putp1, "Putnins P1") "\n\tPCyl, Sph"; -PROJ_HEAD(wag6, "Wagner VI") "\n\tPCyl, Sph"; -PROJ_HEAD(kav7, "Kavraisky VII") "\n\tPCyl, Sph"; - -namespace { // anonymous namespace -struct pj_opaque { - double C_x, C_y, A, B; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - xy.y = Q->C_y * lp.phi; - xy.x = Q->C_x * lp.lam * (Q->A + asqrt(1. - Q->B * lp.phi * lp.phi)); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double denominator; - - lp.phi = xy.y / Q->C_y; - denominator = (Q->C_x * (Q->A + asqrt(1. - Q->B * lp.phi * lp.phi))); - if ( denominator == 0.0) - lp.lam = HUGE_VAL; - else - lp.lam = xy.x / denominator; - return lp; -} - - -static PJ *setup(PJ *P) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - return P; -} - - -PJ *PROJECTION(eck3) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->C_x = 0.42223820031577120149; - Q->C_y = 0.84447640063154240298; - Q->A = 1.0; - Q->B = 0.4052847345693510857755; - - return setup(P); -} - - -PJ *PROJECTION(kav7) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - /* Defined twice in original code - Using 0.866..., - * but leaving the other one here as a safety measure. - * Q->C_x = 0.2632401569273184856851; */ - Q->C_x = 0.8660254037844; - Q->C_y = 1.; - Q->A = 0.; - Q->B = 0.30396355092701331433; - - return setup(P); -} - - -PJ *PROJECTION(wag6) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->C_x = Q->C_y = 0.94745; - Q->A = 0.0; - Q->B = 0.30396355092701331433; - - return setup(P); -} - - -PJ *PROJECTION(putp1) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->C_x = 1.89490; - Q->C_y = 0.94745; - Q->A = -0.5; - Q->B = 0.30396355092701331433; - - return setup(P); -} diff --git a/src/projections/PJ_eck4.cpp b/src/projections/PJ_eck4.cpp deleted file mode 100644 index 4fa4c21f..00000000 --- a/src/projections/PJ_eck4.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(eck4, "Eckert IV") "\n\tPCyl, Sph"; - -#define C_x .42223820031577120149 -#define C_y 1.32650042817700232218 -#define RC_y .75386330736002178205 -#define C_p 3.57079632679489661922 -#define RC_p .28004957675577868795 -#define EPS 1e-7 -#define NITER 6 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double p, V, s, c; - int i; - (void) P; - - p = C_p * sin(lp.phi); - V = lp.phi * lp.phi; - lp.phi *= 0.895168 + V * ( 0.0218849 + V * 0.00826809 ); - for (i = NITER; i ; --i) { - c = cos(lp.phi); - s = sin(lp.phi); - lp.phi -= V = (lp.phi + s * (c + 2.) - p) / - (1. + c * (c + 2.) - s * s); - if (fabs(V) < EPS) - break; - } - if (!i) { - xy.x = C_x * lp.lam; - xy.y = lp.phi < 0. ? -C_y : C_y; - } else { - xy.x = C_x * lp.lam * (1. + cos(lp.phi)); - xy.y = C_y * sin(lp.phi); - } - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double c; - - lp.phi = aasin(P->ctx,xy.y * RC_y); - lp.lam = xy.x / (C_x * (1. + (c = cos(lp.phi)))); - lp.phi = aasin(P->ctx,(lp.phi + sin(lp.phi) * (c + 2.)) * RC_p); - return lp; -} - - -PJ *PROJECTION(eck4) { - P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_eck5.cpp b/src/projections/PJ_eck5.cpp deleted file mode 100644 index f9f28460..00000000 --- a/src/projections/PJ_eck5.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(eck5, "Eckert V") "\n\tPCyl, Sph"; - -#define XF 0.44101277172455148219 -#define RXF 2.26750802723822639137 -#define YF 0.88202554344910296438 -#define RYF 1.13375401361911319568 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - xy.x = XF * (1. + cos(lp.phi)) * lp.lam; - xy.y = YF * lp.phi; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - (void) P; - lp.lam = RXF * xy.x / (1. + cos( lp.phi = RYF * xy.y)); - - return lp; -} - - -PJ *PROJECTION(eck5) { - P->es = 0.0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_eqc.cpp b/src/projections/PJ_eqc.cpp deleted file mode 100644 index 3fdb6dc0..00000000 --- a/src/projections/PJ_eqc.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - double rc; -}; -} // anonymous namespace - -PROJ_HEAD(eqc, "Equidistant Cylindrical (Plate Carree)") - "\n\tCyl, Sph\n\tlat_ts=[, lat_0=0]"; - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - xy.x = Q->rc * lp.lam; - xy.y = lp.phi - P->phi0; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - lp.lam = xy.x / Q->rc; - lp.phi = xy.y + P->phi0; - - return lp; -} - - -PJ *PROJECTION(eqc) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - if ((Q->rc = cos(pj_param(P->ctx, P->params, "rlat_ts").f)) <= 0.) - return pj_default_destructor (P, PJD_ERR_LAT_TS_LARGER_THAN_90); - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - - return P; -} diff --git a/src/projections/PJ_eqdc.cpp b/src/projections/PJ_eqdc.cpp deleted file mode 100644 index 0831fca4..00000000 --- a/src/projections/PJ_eqdc.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -namespace { // anonymous namespace -struct pj_opaque { - double phi1; - double phi2; - double n; - double rho; - double rho0; - double c; - double *en; - int ellips; -}; -} // anonymous namespace - -PROJ_HEAD(eqdc, "Equidistant Conic") - "\n\tConic, Sph&Ell\n\tlat_1= lat_2="; -# define EPS10 1.e-10 - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - Q->rho = Q->c - (Q->ellips ? pj_mlfn(lp.phi, sin(lp.phi), - cos(lp.phi), Q->en) : lp.phi); - xy.x = Q->rho * sin( lp.lam *= Q->n ); - xy.y = Q->rho0 - Q->rho * cos(lp.lam); - - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - if ((Q->rho = hypot(xy.x, xy.y = Q->rho0 - xy.y)) != 0.0 ) { - if (Q->n < 0.) { - Q->rho = -Q->rho; - xy.x = -xy.x; - xy.y = -xy.y; - } - lp.phi = Q->c - Q->rho; - if (Q->ellips) - lp.phi = pj_inv_mlfn(P->ctx, lp.phi, P->es, Q->en); - lp.lam = atan2(xy.x, xy.y) / Q->n; - } else { - lp.lam = 0.; - lp.phi = Q->n > 0. ? M_HALFPI : -M_HALFPI; - } - return lp; -} - - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - -PJ *PROJECTION(eqdc) { - double cosphi, sinphi; - int secant; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; - Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; - - if (fabs(Q->phi1 + Q->phi2) < EPS10) - return pj_default_destructor (P, PJD_ERR_CONIC_LAT_EQUAL); - - if (!(Q->en = pj_enfn(P->es))) - return pj_default_destructor(P, ENOMEM); - - Q->n = sinphi = sin(Q->phi1); - cosphi = cos(Q->phi1); - secant = fabs(Q->phi1 - Q->phi2) >= EPS10; - if( (Q->ellips = (P->es > 0.)) ) { - double ml1, m1; - - m1 = pj_msfn(sinphi, cosphi, P->es); - ml1 = pj_mlfn(Q->phi1, sinphi, cosphi, Q->en); - if (secant) { /* secant cone */ - sinphi = sin(Q->phi2); - cosphi = cos(Q->phi2); - Q->n = (m1 - pj_msfn(sinphi, cosphi, P->es)) / - (pj_mlfn(Q->phi2, sinphi, cosphi, Q->en) - ml1); - } - Q->c = ml1 + m1 / Q->n; - Q->rho0 = Q->c - pj_mlfn(P->phi0, sin(P->phi0), - cos(P->phi0), Q->en); - } else { - if (secant) - Q->n = (cosphi - cos(Q->phi2)) / (Q->phi2 - Q->phi1); - Q->c = Q->phi1 + cos(Q->phi1) / Q->n; - Q->rho0 = Q->c - P->phi0; - } - - P->inv = e_inverse; - P->fwd = e_forward; - - return P; -} diff --git a/src/projections/PJ_eqearth.cpp b/src/projections/PJ_eqearth.cpp deleted file mode 100644 index e5c1f974..00000000 --- a/src/projections/PJ_eqearth.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* -Equal Earth is a projection inspired by the Robinson projection, but unlike -the Robinson projection retains the relative size of areas. The projection -was designed in 2018 by Bojan Savric, Tom Patterson and Bernhard Jenny. - -Publication: -Bojan Savric, Tom Patterson & Bernhard Jenny (2018). The Equal Earth map -projection, International Journal of Geographical Information Science, -DOI: 10.1080/13658816.2018.1504949 - -Port to PROJ by Juernjakob Dugge, 16 August 2018 -Added ellipsoidal equations by Bojan Savric, 22 August 2018 -*/ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(eqearth, "Equal Earth") "\n\tPCyl, Sph&Ell"; - -/* A1..A4, polynomial coefficients */ -#define A1 1.340264 -#define A2 -0.081106 -#define A3 0.000893 -#define A4 0.003796 -#define M (sqrt(3) / 2.0) - -#define MAX_Y 1.3173627591574 /* 90° latitude on a sphere with radius 1 */ -#define EPS 1e-11 -#define MAX_ITER 12 - -namespace { // anonymous namespace -struct pj_opaque { - double qp; - double rqda; - double *apa; -}; -} // anonymous namespace - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal/spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double sbeta; - double psi, psi2, psi6; - - /* Spheroidal case, using sine latitude */ - sbeta = sin(lp.phi); - - /* In the ellipsoidal case, we convert sbeta to sine of authalic latitude */ - if (P->es != 0.0) { - sbeta = pj_qsfn(sbeta, P->e, 1.0 - P->es) / Q->qp; - - /* Rounding error. */ - if (fabs(sbeta) > 1) - sbeta = sbeta > 0 ? 1 : -1; - } - - /* Equal Earth projection */ - psi = asin(M * sbeta); - psi2 = psi * psi; - psi6 = psi2 * psi2 * psi2; - - xy.x = lp.lam * cos(psi) / (M * (A1 + 3 * A2 * psi2 + psi6 * (7 * A3 + 9 * A4 * psi2))); - xy.y = psi * (A1 + A2 * psi2 + psi6 * (A3 + A4 * psi2)); - - /* Adjusting x and y for authalic radius */ - xy.x *= Q->rqda; - xy.y *= Q->rqda; - - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal/spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double yc, y2, y6; - int i; - - /* Adjusting x and y for authalic radius */ - xy.x /= Q->rqda; - xy.y /= Q->rqda; - - /* Make sure y is inside valid range */ - if (xy.y > MAX_Y) - xy.y = MAX_Y; - else if (xy.y < -MAX_Y) - xy.y = -MAX_Y; - - yc = xy.y; - - /* Newton-Raphson */ - for (i = MAX_ITER; i ; --i) { - double f, fder, tol; - - y2 = yc * yc; - y6 = y2 * y2 * y2; - - f = yc * (A1 + A2 * y2 + y6 * (A3 + A4 * y2)) - xy.y; - fder = A1 + 3 * A2 * y2 + y6 * (7 * A3 + 9 * A4 * y2); - - tol = f / fder; - yc -= tol; - - if (fabs(tol) < EPS) - break; - } - - if( i == 0 ) { - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); - return lp; - } - - /* Longitude */ - y2 = yc * yc; - y6 = y2 * y2 * y2; - - lp.lam = M * xy.x * (A1 + 3 * A2 * y2 + y6 * (7 * A3 + 9 * A4 * y2)) / cos(yc); - - /* Latitude (for spheroidal case, this is latitude */ - lp.phi = asin(sin(yc) / M); - - /* Ellipsoidal case, converting auth. latitude */ - if (P->es != 0.0) - lp.phi = pj_authlat(lp.phi, Q->apa); - - return lp; -} - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->apa); - return pj_default_destructor (P, errlev); -} - - -PJ *PROJECTION(eqearth) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - P->fwd = e_forward; - P->inv = e_inverse; - Q->rqda = 1.0; - - /* Ellipsoidal case */ - if (P->es != 0.0) { - Q->apa = pj_authset(P->es); /* For auth_lat(). */ - if (nullptr == Q->apa) - return destructor(P, ENOMEM); - Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */ - Q->rqda = sqrt(0.5*Q->qp); /* Authalic radius divided by major axis */ - } - - return P; -} diff --git a/src/projections/PJ_fahey.cpp b/src/projections/PJ_fahey.cpp deleted file mode 100644 index 85e0ab69..00000000 --- a/src/projections/PJ_fahey.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(fahey, "Fahey") "\n\tPcyl, Sph"; - -#define TOL 1e-6 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - xy.x = tan(0.5 * lp.phi); - xy.y = 1.819152 * xy.x; - xy.x = 0.819152 * lp.lam * asqrt(1 - xy.x * xy.x); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - (void) P; - - xy.y /= 1.819152; - lp.phi = 2. * atan(xy.y); - xy.y = 1. - xy.y * xy.y; - lp.lam = fabs(xy.y) < TOL ? 0. : xy.x / (0.819152 * sqrt(xy.y)); - return lp; -} - - -PJ *PROJECTION(fahey) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_fouc_s.cpp b/src/projections/PJ_fouc_s.cpp deleted file mode 100644 index c5e711de..00000000 --- a/src/projections/PJ_fouc_s.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(fouc_s, "Foucaut Sinusoidal") "\n\tPCyl, Sph"; - -#define MAX_ITER 10 -#define LOOP_TOL 1e-7 - -namespace { // anonymous namespace -struct pj_opaque { - double n, n1; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double t; - - t = cos(lp.phi); - xy.x = lp.lam * t / (Q->n + Q->n1 * t); - xy.y = Q->n * lp.phi + Q->n1 * sin(lp.phi); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double V; - int i; - - if (Q->n != 0.0) { - lp.phi = xy.y; - for (i = MAX_ITER; i ; --i) { - lp.phi -= V = (Q->n * lp.phi + Q->n1 * sin(lp.phi) - xy.y ) / - (Q->n + Q->n1 * cos(lp.phi)); - if (fabs(V) < LOOP_TOL) - break; - } - if (!i) - lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; - } else - lp.phi = aasin(P->ctx,xy.y); - V = cos(lp.phi); - lp.lam = xy.x * (Q->n + Q->n1 * V) / V; - return lp; -} - - -PJ *PROJECTION(fouc_s) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->n = pj_param(P->ctx, P->params, "dn").f; - if (Q->n < 0. || Q->n > 1.) - return pj_default_destructor (P, PJD_ERR_N_OUT_OF_RANGE); - - Q->n1 = 1. - Q->n; - P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; - return P; -} diff --git a/src/projections/PJ_gall.cpp b/src/projections/PJ_gall.cpp deleted file mode 100644 index a8697482..00000000 --- a/src/projections/PJ_gall.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(gall, "Gall (Gall Stereographic)") "\n\tCyl, Sph"; - -#define YF 1.70710678118654752440 -#define XF 0.70710678118654752440 -#define RYF 0.58578643762690495119 -#define RXF 1.41421356237309504880 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - xy.x = XF * lp.lam; - xy.y = YF * tan(.5 * lp.phi); - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - (void) P; - - lp.lam = RXF * xy.x; - lp.phi = 2. * atan(xy.y * RYF); - - return lp; -} - - -PJ *PROJECTION(gall) { - P->es = 0.0; - - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_geos.cpp b/src/projections/PJ_geos.cpp deleted file mode 100644 index 90fb01ab..00000000 --- a/src/projections/PJ_geos.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* -** libproj -- library of cartographic projections -** -** Copyright (c) 2004 Gerald I. Evenden -** Copyright (c) 2012 Martin Raspaud -** -** See also (section 4.4.3.2): -** http://www.eumetsat.int/en/area4/msg/news/us_doc/cgms_03_26.pdf -** -** 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. -*/ - -#define PJ_LIB__ -#include -#include -#include - -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -namespace { // anonymous namespace -struct pj_opaque { - double h; - double radius_p; - double radius_p2; - double radius_p_inv2; - double radius_g; - double radius_g_1; - double C; - int flip_axis; -}; -} // anonymous namespace - -PROJ_HEAD(geos, "Geostationary Satellite View") "\n\tAzi, Sph&Ell\n\th="; - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double Vx, Vy, Vz, tmp; - - /* Calculation of the three components of the vector from satellite to - ** position on earth surface (lon,lat).*/ - tmp = cos(lp.phi); - Vx = cos (lp.lam) * tmp; - Vy = sin (lp.lam) * tmp; - Vz = sin (lp.phi); - - /* Check visibility*/ - - - /* Calculation based on view angles from satellite.*/ - tmp = Q->radius_g - Vx; - - if(Q->flip_axis) { - xy.x = Q->radius_g_1 * atan(Vy / hypot(Vz, tmp)); - xy.y = Q->radius_g_1 * atan(Vz / tmp); - } else { - xy.x = Q->radius_g_1 * atan(Vy / tmp); - xy.y = Q->radius_g_1 * atan(Vz / hypot(Vy, tmp)); - } - - return xy; -} - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double r, Vx, Vy, Vz, tmp; - - /* Calculation of geocentric latitude. */ - lp.phi = atan (Q->radius_p2 * tan (lp.phi)); - - /* Calculation of the three components of the vector from satellite to - ** position on earth surface (lon,lat).*/ - r = (Q->radius_p) / hypot(Q->radius_p * cos (lp.phi), sin (lp.phi)); - Vx = r * cos (lp.lam) * cos (lp.phi); - Vy = r * sin (lp.lam) * cos (lp.phi); - Vz = r * sin (lp.phi); - - /* Check visibility. */ - if (((Q->radius_g - Vx) * Vx - Vy * Vy - Vz * Vz * Q->radius_p_inv2) < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - - /* Calculation based on view angles from satellite. */ - tmp = Q->radius_g - Vx; - - if(Q->flip_axis) { - xy.x = Q->radius_g_1 * atan (Vy / hypot (Vz, tmp)); - xy.y = Q->radius_g_1 * atan (Vz / tmp); - } else { - xy.x = Q->radius_g_1 * atan (Vy / tmp); - xy.y = Q->radius_g_1 * atan (Vz / hypot (Vy, tmp)); - } - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double Vx, Vy, Vz, a, b, det, k; - - /* Setting three components of vector from satellite to position.*/ - Vx = -1.0; - if(Q->flip_axis) { - Vz = tan (xy.y / (Q->radius_g - 1.0)); - Vy = tan (xy.x / (Q->radius_g - 1.0)) * sqrt (1.0 + Vz * Vz); - } else { - Vy = tan (xy.x / (Q->radius_g - 1.0)); - Vz = tan (xy.y / (Q->radius_g - 1.0)) * sqrt (1.0 + Vy * Vy); - } - - /* Calculation of terms in cubic equation and determinant.*/ - a = Vy * Vy + Vz * Vz + Vx * Vx; - b = 2 * Q->radius_g * Vx; - if ((det = (b * b) - 4 * a * Q->C) < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - - /* Calculation of three components of vector from satellite to position.*/ - k = (-b - sqrt(det)) / (2 * a); - Vx = Q->radius_g + k * Vx; - Vy *= k; - Vz *= k; - - /* Calculation of longitude and latitude.*/ - lp.lam = atan2 (Vy, Vx); - lp.phi = atan (Vz * cos (lp.lam) / Vx); - - return lp; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double Vx, Vy, Vz, a, b, det, k; - - /* Setting three components of vector from satellite to position.*/ - Vx = -1.0; - - if(Q->flip_axis) { - Vz = tan (xy.y / Q->radius_g_1); - Vy = tan (xy.x / Q->radius_g_1) * hypot(1.0, Vz); - } else { - Vy = tan (xy.x / Q->radius_g_1); - Vz = tan (xy.y / Q->radius_g_1) * hypot(1.0, Vy); - } - - /* Calculation of terms in cubic equation and determinant.*/ - a = Vz / Q->radius_p; - a = Vy * Vy + a * a + Vx * Vx; - b = 2 * Q->radius_g * Vx; - if ((det = (b * b) - 4 * a * Q->C) < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - - /* Calculation of three components of vector from satellite to position.*/ - k = (-b - sqrt(det)) / (2. * a); - Vx = Q->radius_g + k * Vx; - Vy *= k; - Vz *= k; - - /* Calculation of longitude and latitude.*/ - lp.lam = atan2 (Vy, Vx); - lp.phi = atan (Vz * cos (lp.lam) / Vx); - lp.phi = atan (Q->radius_p_inv2 * tan (lp.phi)); - - return lp; -} - - -PJ *PROJECTION(geos) { - char *sweep_axis; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - if ((Q->h = pj_param(P->ctx, P->params, "dh").f) <= 0.) - return pj_default_destructor (P, PJD_ERR_H_LESS_THAN_ZERO); - - sweep_axis = pj_param(P->ctx, P->params, "ssweep").s; - if (sweep_axis == nullptr) - Q->flip_axis = 0; - else { - if ((sweep_axis[0] != 'x' && sweep_axis[0] != 'y') || - sweep_axis[1] != '\0') - return pj_default_destructor (P, PJD_ERR_INVALID_SWEEP_AXIS); - - if (sweep_axis[0] == 'x') - Q->flip_axis = 1; - else - Q->flip_axis = 0; - } - - Q->radius_g_1 = Q->h / P->a; - Q->radius_g = 1. + Q->radius_g_1; - Q->C = Q->radius_g * Q->radius_g - 1.0; - if (P->es != 0.0) { - Q->radius_p = sqrt (P->one_es); - Q->radius_p2 = P->one_es; - Q->radius_p_inv2 = P->rone_es; - P->inv = e_inverse; - P->fwd = e_forward; - } else { - Q->radius_p = Q->radius_p2 = Q->radius_p_inv2 = 1.0; - P->inv = s_inverse; - P->fwd = s_forward; - } - - return P; -} diff --git a/src/projections/PJ_gins8.cpp b/src/projections/PJ_gins8.cpp deleted file mode 100644 index cc422437..00000000 --- a/src/projections/PJ_gins8.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#define PJ_LIB__ -#include "projects.h" - -PROJ_HEAD(gins8, "Ginsburg VIII (TsNIIGAiK)") "\n\tPCyl, Sph, no inv"; - -#define Cl 0.000952426 -#define Cp 0.162388 -#define C12 0.08333333333333333 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double t = lp.phi * lp.phi; - (void) P; - - xy.y = lp.phi * (1. + t * C12); - xy.x = lp.lam * (1. - Cp * t); - t = lp.lam * lp.lam; - xy.x *= (0.87 - Cl * t * t); - - return xy; -} - - -PJ *PROJECTION(gins8) { - P->es = 0.0; - P->inv = nullptr; - P->fwd = s_forward; - - return P; -} - - diff --git a/src/projections/PJ_gn_sinu.cpp b/src/projections/PJ_gn_sinu.cpp deleted file mode 100644 index 530de229..00000000 --- a/src/projections/PJ_gn_sinu.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(gn_sinu, "General Sinusoidal Series") "\n\tPCyl, Sph\n\tm= n="; -PROJ_HEAD(sinu, "Sinusoidal (Sanson-Flamsteed)") "\n\tPCyl, Sph&Ell"; -PROJ_HEAD(eck6, "Eckert VI") "\n\tPCyl, Sph"; -PROJ_HEAD(mbtfps, "McBryde-Thomas Flat-Polar Sinusoidal") "\n\tPCyl, Sph"; - -#define EPS10 1e-10 -#define MAX_ITER 8 -#define LOOP_TOL 1e-7 - -namespace { // anonymous namespace -struct pj_opaque { - double *en; - double m, n, C_x, C_y; -}; -} // anonymous namespace - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - double s, c; - - xy.y = pj_mlfn(lp.phi, s = sin(lp.phi), c = cos(lp.phi), static_cast(P->opaque)->en); - xy.x = lp.lam * c / sqrt(1. - P->es * s * s); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - double s; - - if ((s = fabs(lp.phi = pj_inv_mlfn(P->ctx, xy.y, P->es, static_cast(P->opaque)->en))) < M_HALFPI) { - s = sin(lp.phi); - lp.lam = xy.x * sqrt(1. - P->es * s * s) / cos(lp.phi); - } else if ((s - EPS10) < M_HALFPI) { - lp.lam = 0.; - } else { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - } - - return lp; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - if (Q->m == 0.0) - lp.phi = Q->n != 1. ? aasin(P->ctx,Q->n * sin(lp.phi)): lp.phi; - else { - double k, V; - int i; - - k = Q->n * sin(lp.phi); - for (i = MAX_ITER; i ; --i) { - lp.phi -= V = (Q->m * lp.phi + sin(lp.phi) - k) / - (Q->m + cos(lp.phi)); - if (fabs(V) < LOOP_TOL) - break; - } - if (!i) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - - } - xy.x = Q->C_x * lp.lam * (Q->m + cos(lp.phi)); - xy.y = Q->C_y * lp.phi; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - xy.y /= Q->C_y; - lp.phi = (Q->m != 0.0) ? aasin(P->ctx,(Q->m * xy.y + sin(xy.y)) / Q->n) : - ( Q->n != 1. ? aasin(P->ctx,sin(xy.y) / Q->n) : xy.y ); - lp.lam = xy.x / (Q->C_x * (Q->m + cos(xy.y))); - return lp; -} - - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - - -/* for spheres, only */ -static void setup(PJ *P) { - struct pj_opaque *Q = static_cast(P->opaque); - P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; - - Q->C_x = (Q->C_y = sqrt((Q->m + 1.) / Q->n))/(Q->m + 1.); -} - - -PJ *PROJECTION(sinu) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - if (!(Q->en = pj_enfn(P->es))) - return pj_default_destructor (P, ENOMEM); - - if (P->es != 0.0) { - P->inv = e_inverse; - P->fwd = e_forward; - } else { - Q->n = 1.; - Q->m = 0.; - setup(P); - } - return P; -} - - -PJ *PROJECTION(eck6) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - Q->m = 1.; - Q->n = 2.570796326794896619231321691; - setup(P); - - return P; -} - - -PJ *PROJECTION(mbtfps) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - Q->m = 0.5; - Q->n = 1.785398163397448309615660845; - setup(P); - - return P; -} - - -PJ *PROJECTION(gn_sinu) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - if (pj_param(P->ctx, P->params, "tn").i && pj_param(P->ctx, P->params, "tm").i) { - Q->n = pj_param(P->ctx, P->params, "dn").f; - Q->m = pj_param(P->ctx, P->params, "dm").f; - if (Q->n <= 0 || Q->m < 0) - return destructor (P, PJD_ERR_INVALID_M_OR_N); - } else - return destructor (P, PJD_ERR_INVALID_M_OR_N); - - setup(P); - - return P; -} diff --git a/src/projections/PJ_gnom.cpp b/src/projections/PJ_gnom.cpp deleted file mode 100644 index a4b5e35d..00000000 --- a/src/projections/PJ_gnom.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -PROJ_HEAD(gnom, "Gnomonic") "\n\tAzi, Sph"; - -#define EPS10 1.e-10 - -namespace { // anonymous namespace -enum Mode { - N_POLE = 0, - S_POLE = 1, - EQUIT = 2, - OBLIQ = 3 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double sinph0; - double cosph0; - enum Mode mode; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, cosphi, sinphi; - - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - coslam = cos(lp.lam); - - switch (Q->mode) { - case EQUIT: - xy.y = cosphi * coslam; - break; - case OBLIQ: - xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam; - break; - case S_POLE: - xy.y = - sinphi; - break; - case N_POLE: - xy.y = sinphi; - break; - } - - if (xy.y <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - - xy.x = (xy.y = 1. / xy.y) * cosphi * sin(lp.lam); - switch (Q->mode) { - case EQUIT: - xy.y *= sinphi; - break; - case OBLIQ: - xy.y *= Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam; - break; - case N_POLE: - coslam = - coslam; - /*-fallthrough*/ - case S_POLE: - xy.y *= cosphi * coslam; - break; - } - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double rh, cosz, sinz; - - rh = hypot(xy.x, xy.y); - sinz = sin(lp.phi = atan(rh)); - cosz = sqrt(1. - sinz * sinz); - - if (fabs(rh) <= EPS10) { - lp.phi = P->phi0; - lp.lam = 0.; - } else { - switch (Q->mode) { - case OBLIQ: - lp.phi = cosz * Q->sinph0 + xy.y * sinz * Q->cosph0 / rh; - if (fabs(lp.phi) >= 1.) - lp.phi = lp.phi > 0. ? M_HALFPI : - M_HALFPI; - else - lp.phi = asin(lp.phi); - xy.y = (cosz - Q->sinph0 * sin(lp.phi)) * rh; - xy.x *= sinz * Q->cosph0; - break; - case EQUIT: - lp.phi = xy.y * sinz / rh; - if (fabs(lp.phi) >= 1.) - lp.phi = lp.phi > 0. ? M_HALFPI : - M_HALFPI; - else - lp.phi = asin(lp.phi); - xy.y = cosz * rh; - xy.x *= sinz; - break; - case S_POLE: - lp.phi -= M_HALFPI; - break; - case N_POLE: - lp.phi = M_HALFPI - lp.phi; - xy.y = -xy.y; - break; - } - lp.lam = atan2(xy.x, xy.y); - } - return lp; -} - - -PJ *PROJECTION(gnom) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) { - Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - } else if (fabs(P->phi0) < EPS10) { - Q->mode = EQUIT; - } else { - Q->mode = OBLIQ; - Q->sinph0 = sin(P->phi0); - Q->cosph0 = cos(P->phi0); - } - - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - - return P; -} diff --git a/src/projections/PJ_goode.cpp b/src/projections/PJ_goode.cpp deleted file mode 100644 index c79d125e..00000000 --- a/src/projections/PJ_goode.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(goode, "Goode Homolosine") "\n\tPCyl, Sph"; - -#define Y_COR 0.05280 -#define PHI_LIM 0.71093078197902358062 - -C_NAMESPACE PJ *pj_sinu(PJ *), *pj_moll(PJ *); - -namespace { // anonymous namespace -struct pj_opaque { - PJ *sinu; - PJ *moll; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy; - struct pj_opaque *Q = static_cast(P->opaque); - - if (fabs(lp.phi) <= PHI_LIM) - xy = Q->sinu->fwd(lp, Q->sinu); - else { - xy = Q->moll->fwd(lp, Q->moll); - xy.y -= lp.phi >= 0.0 ? Y_COR : -Y_COR; - } - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp; - struct pj_opaque *Q = static_cast(P->opaque); - - if (fabs(xy.y) <= PHI_LIM) - lp = Q->sinu->inv(xy, Q->sinu); - else { - xy.y += xy.y >= 0.0 ? Y_COR : -Y_COR; - lp = Q->moll->inv(xy, Q->moll); - } - return lp; -} - - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - pj_free (static_cast(P->opaque)->sinu); - pj_free (static_cast(P->opaque)->moll); - return pj_default_destructor (P, errlev); -} - - - -PJ *PROJECTION(goode) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - P->es = 0.; - if (!(Q->sinu = pj_sinu(nullptr)) || !(Q->moll = pj_moll(nullptr))) - return destructor (P, ENOMEM); - Q->sinu->es = 0.; - Q->sinu->ctx = P->ctx; - Q->moll->ctx = P->ctx; - if (!(Q->sinu = pj_sinu(Q->sinu)) || !(Q->moll = pj_moll(Q->moll))) - return destructor (P, ENOMEM); - - P->fwd = s_forward; - P->inv = s_inverse; - - return P; -} diff --git a/src/projections/PJ_gstmerc.cpp b/src/projections/PJ_gstmerc.cpp deleted file mode 100644 index 9b819bac..00000000 --- a/src/projections/PJ_gstmerc.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(gstmerc, "Gauss-Schreiber Transverse Mercator (aka Gauss-Laborde Reunion)") - "\n\tCyl, Sph&Ell\n\tlat_0= lon_0= k_0="; - -namespace { // anonymous namespace -struct pj_opaque { - double lamc; - double phic; - double c; - double n1; - double n2; - double XS; - double YS; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double L, Ls, sinLs1, Ls1; - - L = Q->n1*lp.lam; - Ls = Q->c + Q->n1 * log(pj_tsfn(-1.0 * lp.phi, -1.0 * sin(lp.phi), P->e)); - sinLs1 = sin(L) / cosh(Ls); - Ls1 = log(pj_tsfn(-1.0 * asin(sinLs1), 0.0, 0.0)); - xy.x = (Q->XS + Q->n2*Ls1) * P->ra; - xy.y = (Q->YS + Q->n2*atan(sinh(Ls) / cos(L))) * P->ra; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double L, LC, sinC; - - L = atan(sinh((xy.x * P->a - Q->XS) / Q->n2) / cos((xy.y * P->a - Q->YS) / Q->n2)); - sinC = sin((xy.y * P->a - Q->YS) / Q->n2) / cosh((xy.x * P->a - Q->XS) / Q->n2); - LC = log(pj_tsfn(-1.0 * asin(sinC), 0.0, 0.0)); - lp.lam = L / Q->n1; - lp.phi = -1.0 * pj_phi2(P->ctx, exp((LC - Q->c) / Q->n1), P->e); - - return lp; -} - - -PJ *PROJECTION(gstmerc) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->lamc = P->lam0; - Q->n1 = sqrt(1.0 + P->es * pow(cos(P->phi0), 4.0) / (1.0 - P->es)); - Q->phic = asin(sin(P->phi0) / Q->n1); - Q->c = log(pj_tsfn(-1.0 * Q->phic, 0.0, 0.0)) - - Q->n1 * log(pj_tsfn(-1.0 * P->phi0, -1.0 * sin(P->phi0), P->e)); - Q->n2 = P->k0 * P->a * sqrt(1.0 - P->es) / (1.0 - P->es * sin(P->phi0) * sin(P->phi0)); - Q->XS = 0; - Q->YS = -1.0 * Q->n2 * Q->phic; - - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_hammer.cpp b/src/projections/PJ_hammer.cpp deleted file mode 100644 index d4caa656..00000000 --- a/src/projections/PJ_hammer.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(hammer, "Hammer & Eckert-Greifendorff") - "\n\tMisc Sph, \n\tW= M="; - -#define EPS 1.0e-10 - -namespace { // anonymous namespace -struct pj_opaque { - double w; - double m, rm; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cosphi, d; - - d = sqrt(2./(1. + (cosphi = cos(lp.phi)) * cos(lp.lam *= Q->w))); - xy.x = Q->m * d * cosphi * sin(lp.lam); - xy.y = Q->rm * d * sin(lp.phi); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double z; - - z = sqrt(1. - 0.25*Q->w*Q->w*xy.x*xy.x - 0.25*xy.y*xy.y); - if (fabs(2.*z*z-1.) < EPS) { - lp.lam = HUGE_VAL; - lp.phi = HUGE_VAL; - proj_errno_set(P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); - } else { - lp.lam = aatan2(Q->w * xy.x * z,2. * z * z - 1)/Q->w; - lp.phi = aasin(P->ctx,z * xy.y); - } - return lp; -} - - -PJ *PROJECTION(hammer) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - if (pj_param(P->ctx, P->params, "tW").i) { - if ((Q->w = fabs(pj_param(P->ctx, P->params, "dW").f)) <= 0.) - return pj_default_destructor (P, PJD_ERR_W_OR_M_ZERO_OR_LESS); - } else - Q->w = .5; - if (pj_param(P->ctx, P->params, "tM").i) { - if ((Q->m = fabs(pj_param(P->ctx, P->params, "dM").f)) <= 0.) - return pj_default_destructor (P, PJD_ERR_W_OR_M_ZERO_OR_LESS); - } else - Q->m = 1.; - - Q->rm = 1. / Q->m; - Q->m /= Q->w; - - P->es = 0.; - P->fwd = s_forward; - P->inv = s_inverse; - - return P; -} diff --git a/src/projections/PJ_hatano.cpp b/src/projections/PJ_hatano.cpp deleted file mode 100644 index 019671cc..00000000 --- a/src/projections/PJ_hatano.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(hatano, "Hatano Asymmetrical Equal Area") "\n\tPCyl, Sph"; - -#define NITER 20 -#define EPS 1e-7 -#define ONETOL 1.000001 -#define CN 2.67595 -#define CS 2.43763 -#define RCN 0.37369906014686373063 -#define RCS 0.41023453108141924738 -#define FYCN 1.75859 -#define FYCS 1.93052 -#define RYCN 0.56863737426006061674 -#define RYCS 0.51799515156538134803 -#define FXC 0.85 -#define RXC 1.17647058823529411764 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double th1, c; - int i; - (void) P; - - c = sin(lp.phi) * (lp.phi < 0. ? CS : CN); - for (i = NITER; i; --i) { - lp.phi -= th1 = (lp.phi + sin(lp.phi) - c) / (1. + cos(lp.phi)); - if (fabs(th1) < EPS) break; - } - xy.x = FXC * lp.lam * cos(lp.phi *= .5); - xy.y = sin(lp.phi) * (lp.phi < 0. ? FYCS : FYCN); - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double th; - - th = xy.y * ( xy.y < 0. ? RYCS : RYCN); - if (fabs(th) > 1.) { - if (fabs(th) > ONETOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } else { - th = th > 0. ? M_HALFPI : - M_HALFPI; - } - } else { - th = asin(th); - } - - lp.lam = RXC * xy.x / cos(th); - th += th; - lp.phi = (th + sin(th)) * (xy.y < 0. ? RCS : RCN); - if (fabs(lp.phi) > 1.) { - if (fabs(lp.phi) > ONETOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } else { - lp.phi = lp.phi > 0. ? M_HALFPI : - M_HALFPI; - } - } else { - lp.phi = asin(lp.phi); - } - - return (lp); -} - - -PJ *PROJECTION(hatano) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_healpix.cpp b/src/projections/PJ_healpix.cpp deleted file mode 100644 index 7f0b3e83..00000000 --- a/src/projections/PJ_healpix.cpp +++ /dev/null @@ -1,674 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the HEALPix and rHEALPix projections. - * For background see . - * Authors: Alex Raichev (raichev@cs.auckland.ac.nz) - * Michael Speth (spethm@landcareresearch.co.nz) - * Notes: Raichev implemented these projections in Python and - * Speth translated them into C here. - ****************************************************************************** - * 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 substcounteral 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. - *****************************************************************************/ -#define PJ_LIB__ - -#include -#include - -#include "proj_internal.h" -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(healpix, "HEALPix") "\n\tSph&Ell"; -PROJ_HEAD(rhealpix, "rHEALPix") "\n\tSph&Ell\n\tnorth_square= south_square="; - -/* Matrix for counterclockwise rotation by pi/2: */ -# define R1 {{ 0,-1},{ 1, 0}} -/* Matrix for counterclockwise rotation by pi: */ -# define R2 {{-1, 0},{ 0,-1}} -/* Matrix for counterclockwise rotation by 3*pi/2: */ -# define R3 {{ 0, 1},{-1, 0}} -/* Identity matrix */ -# define IDENT {{1, 0},{0, 1}} -/* IDENT, R1, R2, R3, R1 inverse, R2 inverse, R3 inverse:*/ -# define ROT {IDENT, R1, R2, R3, R3, R2, R1} -/* Fuzz to handle rounding errors: */ -# define EPS 1e-15 - -namespace { // anonymous namespace -struct pj_opaque { - int north_square; - int south_square; - double qp; - double *apa; -}; -} // anonymous namespace - -typedef struct { - int cn; /* An integer 0--3 indicating the position of the polar cap. */ - double x, y; /* Coordinates of the pole point (point of most extreme latitude on the polar caps). */ - enum Region {north, south, equatorial} region; -} CapMap; - -static const double rot[7][2][2] = ROT; - -/** - * Returns the sign of the double. - * @param v the parameter whose sign is returned. - * @return 1 for positive number, -1 for negative, and 0 for zero. - **/ -static double sign (double v) { - return v > 0 ? 1 : (v < 0 ? -1 : 0); -} - - -/** - * Return the index of the matrix in ROT. - * @param index ranges from -3 to 3. - */ -static int get_rotate_index(int index) { - switch(index) { - case 0: - return 0; - case 1: - return 1; - case 2: - return 2; - case 3: - return 3; - case -1: - return 4; - case -2: - return 5; - case -3: - return 6; - } - return 0; -} - - -/** - * Return 1 if point (testx, testy) lies in the interior of the polygon - * determined by the vertices in vert, and return 0 otherwise. - * See http://paulbourke.net/geometry/polygonmesh/ for more details. - * @param nvert the number of vertices in the polygon. - * @param vert the (x, y)-coordinates of the polygon's vertices - **/ -static int pnpoly(int nvert, double vert[][2], double testx, double testy) { - int i; - int counter = 0; - double xinters; - XY p1, p2; - - /* Check for boundrary cases */ - for (i = 0; i < nvert; i++) { - if (testx == vert[i][0] && testy == vert[i][1]) { - return 1; - } - } - - p1.x = vert[0][0]; - p1.y = vert[0][1]; - - for (i = 1; i < nvert; i++) { - p2.x = vert[i % nvert][0]; - p2.y = vert[i % nvert][1]; - if (testy > MIN(p1.y, p2.y) && - testy <= MAX(p1.y, p2.y) && - testx <= MAX(p1.x, p2.x) && - p1.y != p2.y) - { - xinters = (testy-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x; - if (p1.x == p2.x || testx <= xinters) - counter++; - } - p1 = p2; - } - - if (counter % 2 == 0) { - return 0; - } else { - return 1; - } -} - - -/** - * Return 1 if (x, y) lies in (the interior or boundary of) the image of the - * HEALPix projection (in case proj=0) or in the image the rHEALPix projection - * (in case proj=1), and return 0 otherwise. - * @param north_square the position of the north polar square (rHEALPix only) - * @param south_square the position of the south polar square (rHEALPix only) - **/ -static int in_image(double x, double y, int proj, int north_square, - int south_square) { - if (proj == 0) { - double healpixVertsJit[][2] = { - {-M_PI - EPS, M_FORTPI}, - {-3*M_FORTPI, M_HALFPI + EPS}, - {-M_HALFPI, M_FORTPI + EPS}, - {-M_FORTPI, M_HALFPI + EPS}, - {0.0, M_FORTPI + EPS}, - {M_FORTPI, M_HALFPI + EPS}, - {M_HALFPI, M_FORTPI + EPS}, - {3*M_FORTPI, M_HALFPI + EPS}, - {M_PI + EPS, M_FORTPI}, - {M_PI + EPS, -M_FORTPI}, - {3*M_FORTPI, -M_HALFPI - EPS}, - {M_HALFPI, -M_FORTPI - EPS}, - {M_FORTPI, -M_HALFPI - EPS}, - {0.0, -M_FORTPI - EPS}, - {-M_FORTPI, -M_HALFPI - EPS}, - {-M_HALFPI, -M_FORTPI - EPS}, - {-3*M_FORTPI, -M_HALFPI - EPS}, - {-M_PI - EPS, -M_FORTPI} - }; - return pnpoly((int)sizeof(healpixVertsJit)/ - sizeof(healpixVertsJit[0]), healpixVertsJit, x, y); - } else { - /** - * Assigning each element by index to avoid warnings such as - * 'initializer element is not computable at load time'. - * Before C99 this was not allowed and to keep as portable as - * possible we do it the C89 way here. - * We need to assign the array this way because the input is - * dynamic (north_square and south_square vars are unknown at - * compile time). - **/ - double rhealpixVertsJit[12][2]; - rhealpixVertsJit[0][0] = -M_PI - EPS; - rhealpixVertsJit[0][1] = M_FORTPI + EPS; - rhealpixVertsJit[1][0] = -M_PI + north_square*M_HALFPI- EPS; - rhealpixVertsJit[1][1] = M_FORTPI + EPS; - rhealpixVertsJit[2][0] = -M_PI + north_square*M_HALFPI- EPS; - rhealpixVertsJit[2][1] = 3*M_FORTPI + EPS; - rhealpixVertsJit[3][0] = -M_PI + (north_square + 1.0)*M_HALFPI + EPS; - rhealpixVertsJit[3][1] = 3*M_FORTPI + EPS; - rhealpixVertsJit[4][0] = -M_PI + (north_square + 1.0)*M_HALFPI + EPS; - rhealpixVertsJit[4][1] = M_FORTPI + EPS; - rhealpixVertsJit[5][0] = M_PI + EPS; - rhealpixVertsJit[5][1] = M_FORTPI + EPS; - rhealpixVertsJit[6][0] = M_PI + EPS; - rhealpixVertsJit[6][1] = -M_FORTPI - EPS; - rhealpixVertsJit[7][0] = -M_PI + (south_square + 1.0)*M_HALFPI + EPS; - rhealpixVertsJit[7][1] = -M_FORTPI - EPS; - rhealpixVertsJit[8][0] = -M_PI + (south_square + 1.0)*M_HALFPI + EPS; - rhealpixVertsJit[8][1] = -3*M_FORTPI - EPS; - rhealpixVertsJit[9][0] = -M_PI + south_square*M_HALFPI - EPS; - rhealpixVertsJit[9][1] = -3*M_FORTPI - EPS; - rhealpixVertsJit[10][0] = -M_PI + south_square*M_HALFPI - EPS; - rhealpixVertsJit[10][1] = -M_FORTPI - EPS; - rhealpixVertsJit[11][0] = -M_PI - EPS; - rhealpixVertsJit[11][1] = -M_FORTPI - EPS; - - return pnpoly((int)sizeof(rhealpixVertsJit)/ - sizeof(rhealpixVertsJit[0]), rhealpixVertsJit, x, y); - } -} - - -/** - * Return the authalic latitude of latitude alpha (if inverse=0) or - * return the approximate latitude of authalic latitude alpha (if inverse=1). - * P contains the relevant ellipsoid parameters. - **/ -static double auth_lat(PJ *P, double alpha, int inverse) { - struct pj_opaque *Q = static_cast(P->opaque); - if (inverse == 0) { - /* Authalic latitude. */ - double q = pj_qsfn(sin(alpha), P->e, 1.0 - P->es); - double qp = Q->qp; - double ratio = q/qp; - - if (fabs(ratio) > 1) { - /* Rounding error. */ - ratio = sign(ratio); - } - return asin(ratio); - } else { - /* Approximation to inverse authalic latitude. */ - return pj_authlat(alpha, Q->apa); - } -} - - -/** - * Return the HEALPix projection of the longitude-latitude point lp on - * the unit sphere. -**/ -static XY healpix_sphere(LP lp) { - double lam = lp.lam; - double phi = lp.phi; - double phi0 = asin(2.0/3.0); - XY xy; - - /* equatorial region */ - if ( fabs(phi) <= phi0) { - xy.x = lam; - xy.y = 3*M_PI/8*sin(phi); - } else { - double lamc; - double sigma = sqrt(3*(1 - fabs(sin(phi)))); - double cn = floor(2*lam / M_PI + 2); - if (cn >= 4) { - cn = 3; - } - lamc = -3*M_FORTPI + M_HALFPI*cn; - xy.x = lamc + (lam - lamc)*sigma; - xy.y = sign(phi)*M_FORTPI*(2 - sigma); - } - return xy; -} - - -/** - * Return the inverse of healpix_sphere(). -**/ -static LP healpix_sphere_inverse(XY xy) { - LP lp; - double x = xy.x; - double y = xy.y; - double y0 = M_FORTPI; - - /* Equatorial region. */ - if (fabs(y) <= y0) { - lp.lam = x; - lp.phi = asin(8*y/(3*M_PI)); - } else if (fabs(y) < M_HALFPI) { - double cn = floor(2*x/M_PI + 2); - double xc, tau; - if (cn >= 4) { - cn = 3; - } - xc = -3*M_FORTPI + M_HALFPI*cn; - tau = 2.0 - 4*fabs(y)/M_PI; - lp.lam = xc + (x - xc)/tau; - lp.phi = sign(y)*asin(1.0 - pow(tau, 2)/3.0); - } else { - lp.lam = -M_PI; - lp.phi = sign(y)*M_HALFPI; - } - return (lp); -} - - -/** - * Return the vector sum a + b, where a and b are 2-dimensional vectors. - * @param ret holds a + b. - **/ -static void vector_add(const double a[2], const double b[2], double *ret) { - int i; - for(i = 0; i < 2; i++) { - ret[i] = a[i] + b[i]; - } -} - - -/** - * Return the vector difference a - b, where a and b are 2-dimensional vectors. - * @param ret holds a - b. - **/ -static void vector_sub(const double a[2], const double b[2], double*ret) { - int i; - for(i = 0; i < 2; i++) { - ret[i] = a[i] - b[i]; - } -} - - -/** - * Return the 2 x 1 matrix product a*b, where a is a 2 x 2 matrix and - * b is a 2 x 1 matrix. - * @param ret holds a*b. - **/ -static void dot_product(const double a[2][2], const double b[2], double *ret) { - int i, j; - int length = 2; - for(i = 0; i < length; i++) { - ret[i] = 0; - for(j = 0; j < length; j++) { - ret[i] += a[i][j]*b[j]; - } - } -} - - -/** - * Return the number of the polar cap, the pole point coordinates, and - * the region that (x, y) lies in. - * If inverse=0, then assume (x,y) lies in the image of the HEALPix - * projection of the unit sphere. - * If inverse=1, then assume (x,y) lies in the image of the - * (north_square, south_square)-rHEALPix projection of the unit sphere. - **/ -static CapMap get_cap(double x, double y, int north_square, int south_square, - int inverse) { - CapMap capmap; - double c; - - capmap.x = x; - capmap.y = y; - if (inverse == 0) { - if (y > M_FORTPI) { - capmap.region = CapMap::north; - c = M_HALFPI; - } else if (y < -M_FORTPI) { - capmap.region = CapMap::south; - c = -M_HALFPI; - } else { - capmap.region = CapMap::equatorial; - capmap.cn = 0; - return capmap; - } - /* polar region */ - if (x < -M_HALFPI) { - capmap.cn = 0; - capmap.x = (-3*M_FORTPI); - capmap.y = c; - } else if (x >= -M_HALFPI && x < 0) { - capmap.cn = 1; - capmap.x = -M_FORTPI; - capmap.y = c; - } else if (x >= 0 && x < M_HALFPI) { - capmap.cn = 2; - capmap.x = M_FORTPI; - capmap.y = c; - } else { - capmap.cn = 3; - capmap.x = 3*M_FORTPI; - capmap.y = c; - } - } else { - if (y > M_FORTPI) { - capmap.region = CapMap::north; - capmap.x = -3*M_FORTPI + north_square*M_HALFPI; - capmap.y = M_HALFPI; - x = x - north_square*M_HALFPI; - } else if (y < -M_FORTPI) { - capmap.region = CapMap::south; - capmap.x = -3*M_FORTPI + south_square*M_HALFPI; - capmap.y = -M_HALFPI; - x = x - south_square*M_HALFPI; - } else { - capmap.region = CapMap::equatorial; - capmap.cn = 0; - return capmap; - } - /* Polar Region, find the HEALPix polar cap number that - x, y moves to when rHEALPix polar square is disassembled. */ - if (capmap.region == CapMap::north) { - if (y >= -x - M_FORTPI - EPS && y < x + 5*M_FORTPI - EPS) { - capmap.cn = (north_square + 1) % 4; - } else if (y > -x -M_FORTPI + EPS && y >= x + 5*M_FORTPI - EPS) { - capmap.cn = (north_square + 2) % 4; - } else if (y <= -x -M_FORTPI + EPS && y > x + 5*M_FORTPI + EPS) { - capmap.cn = (north_square + 3) % 4; - } else { - capmap.cn = north_square; - } - } else if (capmap.region == CapMap::south) { - if (y <= x + M_FORTPI + EPS && y > -x - 5*M_FORTPI + EPS) { - capmap.cn = (south_square + 1) % 4; - } else if (y < x + M_FORTPI - EPS && y <= -x - 5*M_FORTPI + EPS) { - capmap.cn = (south_square + 2) % 4; - } else if (y >= x + M_FORTPI - EPS && y < -x - 5*M_FORTPI - EPS) { - capmap.cn = (south_square + 3) % 4; - } else { - capmap.cn = south_square; - } - } - } - return capmap; -} - - -/** - * Rearrange point (x, y) in the HEALPix projection by - * combining the polar caps into two polar squares. - * Put the north polar square in position north_square and - * the south polar square in position south_square. - * If inverse=1, then uncombine the polar caps. - * @param north_square integer between 0 and 3. - * @param south_square integer between 0 and 3. - **/ -static XY combine_caps(double x, double y, int north_square, int south_square, - int inverse) { - XY xy; - double v[2]; - double c[2]; - double vector[2]; - double v_min_c[2]; - double ret_dot[2]; - const double (*tmpRot)[2]; - int pole = 0; - - CapMap capmap = get_cap(x, y, north_square, south_square, inverse); - if (capmap.region == CapMap::equatorial) { - xy.x = capmap.x; - xy.y = capmap.y; - return xy; - } - - v[0] = x; v[1] = y; - c[0] = capmap.x; c[1] = capmap.y; - - if (inverse == 0) { - /* Rotate (x, y) about its polar cap tip and then translate it to - north_square or south_square. */ - - if (capmap.region == CapMap::north) { - pole = north_square; - tmpRot = rot[get_rotate_index(capmap.cn - pole)]; - } else { - pole = south_square; - tmpRot = rot[get_rotate_index(-1*(capmap.cn - pole))]; - } - } else { - /* Inverse function. - Unrotate (x, y) and then translate it back. */ - - /* disassemble */ - if (capmap.region == CapMap::north) { - pole = north_square; - tmpRot = rot[get_rotate_index(-1*(capmap.cn - pole))]; - } else { - pole = south_square; - tmpRot = rot[get_rotate_index(capmap.cn - pole)]; - } - } - - vector_sub(v, c, v_min_c); - dot_product(tmpRot, v_min_c, ret_dot); - { - double a[2]; - /* Workaround cppcheck git issue */ - double* pa = a; - pa[0] = -3*M_FORTPI + ((inverse == 0) ? pole : capmap.cn) *M_HALFPI; - pa[1] = ((capmap.region == CapMap::north) ? 1 : -1) *M_HALFPI; - vector_add(ret_dot, a, vector); - } - - xy.x = vector[0]; - xy.y = vector[1]; - return xy; -} - - -static XY s_healpix_forward(LP lp, PJ *P) { /* sphere */ - (void) P; - return healpix_sphere(lp); -} - - -static XY e_healpix_forward(LP lp, PJ *P) { /* ellipsoid */ - lp.phi = auth_lat(P, lp.phi, 0); - return healpix_sphere(lp); -} - - -static LP s_healpix_inverse(XY xy, PJ *P) { /* sphere */ - /* Check whether (x, y) lies in the HEALPix image */ - if (in_image(xy.x, xy.y, 0, 0, 0) == 0) { - LP lp; - lp.lam = HUGE_VAL; - lp.phi = HUGE_VAL; - pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); - return lp; - } - return healpix_sphere_inverse(xy); -} - - -static LP e_healpix_inverse(XY xy, PJ *P) { /* ellipsoid */ - LP lp = {0.0,0.0}; - - /* Check whether (x, y) lies in the HEALPix image. */ - if (in_image(xy.x, xy.y, 0, 0, 0) == 0) { - lp.lam = HUGE_VAL; - lp.phi = HUGE_VAL; - pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); - return lp; - } - lp = healpix_sphere_inverse(xy); - lp.phi = auth_lat(P, lp.phi, 1); - return lp; -} - - -static XY s_rhealpix_forward(LP lp, PJ *P) { /* sphere */ - struct pj_opaque *Q = static_cast(P->opaque); - - XY xy = healpix_sphere(lp); - return combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 0); -} - - -static XY e_rhealpix_forward(LP lp, PJ *P) { /* ellipsoid */ - struct pj_opaque *Q = static_cast(P->opaque); - XY xy; - lp.phi = auth_lat(P, lp.phi, 0); - xy = healpix_sphere(lp); - return combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 0); -} - - -static LP s_rhealpix_inverse(XY xy, PJ *P) { /* sphere */ - struct pj_opaque *Q = static_cast(P->opaque); - - /* Check whether (x, y) lies in the rHEALPix image. */ - if (in_image(xy.x, xy.y, 1, Q->north_square, Q->south_square) == 0) { - LP lp; - lp.lam = HUGE_VAL; - lp.phi = HUGE_VAL; - pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); - return lp; - } - xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); - return healpix_sphere_inverse(xy); -} - - -static LP e_rhealpix_inverse(XY xy, PJ *P) { /* ellipsoid */ - struct pj_opaque *Q = static_cast(P->opaque); - LP lp = {0.0,0.0}; - - /* Check whether (x, y) lies in the rHEALPix image. */ - if (in_image(xy.x, xy.y, 1, Q->north_square, Q->south_square) == 0) { - lp.lam = HUGE_VAL; - lp.phi = HUGE_VAL; - pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); - return lp; - } - xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); - lp = healpix_sphere_inverse(xy); - lp.phi = auth_lat(P, lp.phi, 1); - return lp; -} - - -static PJ *destructor (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->apa); - return pj_default_destructor (P, errlev); -} - - -PJ *PROJECTION(healpix) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - if (P->es != 0.0) { - Q->apa = pj_authset(P->es); /* For auth_lat(). */ - if (nullptr==Q->apa) - return destructor(P, ENOMEM); - Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */ - P->a = P->a*sqrt(0.5*Q->qp); /* Set P->a to authalic radius. */ - pj_calc_ellipsoid_params (P, P->a, P->es); /* Ensure we have a consistent parameter set */ - P->fwd = e_healpix_forward; - P->inv = e_healpix_inverse; - } else { - P->fwd = s_healpix_forward; - P->inv = s_healpix_inverse; - } - - return P; -} - - -PJ *PROJECTION(rhealpix) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - Q->north_square = pj_param(P->ctx, P->params,"inorth_square").i; - Q->south_square = pj_param(P->ctx, P->params,"isouth_square").i; - - /* Check for valid north_square and south_square inputs. */ - if (Q->north_square < 0 || Q->north_square > 3) - return destructor (P, PJD_ERR_AXIS); - if (Q->south_square < 0 || Q->south_square > 3) - return destructor (P, PJD_ERR_AXIS); - if (P->es != 0.0) { - Q->apa = pj_authset(P->es); /* For auth_lat(). */ - if (nullptr==Q->apa) - return destructor(P, ENOMEM); - Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */ - P->a = P->a*sqrt(0.5*Q->qp); /* Set P->a to authalic radius. */ - P->ra = 1.0/P->a; - P->fwd = e_rhealpix_forward; - P->inv = e_rhealpix_inverse; - } else { - P->fwd = s_rhealpix_forward; - P->inv = s_rhealpix_inverse; - } - - return P; -} diff --git a/src/projections/PJ_igh.cpp b/src/projections/PJ_igh.cpp deleted file mode 100644 index e3576861..00000000 --- a/src/projections/PJ_igh.cpp +++ /dev/null @@ -1,227 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#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(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(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(P->opaque)->pj[i]) - static_cast(P->opaque)->pj[i]->destructor(static_cast(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(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; -} diff --git a/src/projections/PJ_imw_p.cpp b/src/projections/PJ_imw_p.cpp deleted file mode 100644 index 012c5caa..00000000 --- a/src/projections/PJ_imw_p.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(imw_p, "International Map of the World Polyconic") - "\n\tMod. Polyconic, Ell\n\tlat_1= and lat_2= [lon_1=]"; - -#define TOL 1e-10 -#define EPS 1e-10 - -namespace { // anonymous namespace -enum Mode { - NONE_IS_ZERO = 0, /* phi_1 and phi_2 != 0 */ - PHI_1_IS_ZERO = 1, /* phi_1 = 0 */ - PHI_2_IS_ZERO = -1 /* phi_2 = 0 */ -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double P, Pp, Q, Qp, R_1, R_2, sphi_1, sphi_2, C2; - double phi_1, phi_2, lam_1; - double *en; - enum Mode mode; -}; -} // anonymous namespace - - -static int phi12(PJ *P, double *del, double *sig) { - struct pj_opaque *Q = static_cast(P->opaque); - int err = 0; - - if (!pj_param(P->ctx, P->params, "tlat_1").i || - !pj_param(P->ctx, P->params, "tlat_2").i) { - err = PJD_ERR_LAT_1_2_UNSPECIFIED; - } else { - Q->phi_1 = pj_param(P->ctx, P->params, "rlat_1").f; - Q->phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; - *del = 0.5 * (Q->phi_2 - Q->phi_1); - *sig = 0.5 * (Q->phi_2 + Q->phi_1); - err = (fabs(*del) < EPS || fabs(*sig) < EPS) ? PJD_ERR_ABS_LAT1_EQ_ABS_LAT2 : 0; - } - return err; -} - - -static XY loc_for(LP lp, PJ *P, double *yc) { - struct pj_opaque *Q = static_cast(P->opaque); - XY xy; - - if (lp.phi == 0.0) { - xy.x = lp.lam; - xy.y = 0.; - } else { - double xa, ya, xb, yb, xc, D, B, m, sp, t, R, C; - - sp = sin(lp.phi); - m = pj_mlfn(lp.phi, sp, cos(lp.phi), Q->en); - xa = Q->Pp + Q->Qp * m; - ya = Q->P + Q->Q * m; - R = 1. / (tan(lp.phi) * sqrt(1. - P->es * sp * sp)); - C = sqrt(R * R - xa * xa); - if (lp.phi < 0.) C = - C; - C += ya - R; - if (Q->mode == PHI_2_IS_ZERO) { - xb = lp.lam; - yb = Q->C2; - } else { - t = lp.lam * Q->sphi_2; - xb = Q->R_2 * sin(t); - yb = Q->C2 + Q->R_2 * (1. - cos(t)); - } - if (Q->mode == PHI_1_IS_ZERO) { - xc = lp.lam; - *yc = 0.; - } else { - t = lp.lam * Q->sphi_1; - xc = Q->R_1 * sin(t); - *yc = Q->R_1 * (1. - cos(t)); - } - D = (xb - xc)/(yb - *yc); - B = xc + D * (C + R - *yc); - xy.x = D * sqrt(R * R * (1 + D * D) - B * B); - if (lp.phi > 0) - xy.x = - xy.x; - xy.x = (B + xy.x) / (1. + D * D); - xy.y = sqrt(R * R - xy.x * xy.x); - if (lp.phi > 0) - xy.y = - xy.y; - xy.y += C + R; - } - return xy; -} - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - double yc; - XY xy = loc_for(lp, P, &yc); - return (xy); -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - XY t; - double yc = 0.0; - int i = 0; - const int N_MAX_ITER = 1000; /* Arbitrarily chosen number... */ - - lp.phi = Q->phi_2; - lp.lam = xy.x / cos(lp.phi); - do { - t = loc_for(lp, P, &yc); - lp.phi = ((lp.phi - Q->phi_1) * (xy.y - yc) / (t.y - yc)) + Q->phi_1; - lp.lam = lp.lam * xy.x / t.x; - i ++; - } while (i < N_MAX_ITER && - (fabs(t.x - xy.x) > TOL || fabs(t.y - xy.y) > TOL)); - - if( i == N_MAX_ITER ) - { - lp.lam = lp.phi = HUGE_VAL; - } - - return lp; -} - - -static void xy(PJ *P, double phi, double *x, double *y, double *sp, double *R) { - double F; - - *sp = sin(phi); - *R = 1./(tan(phi) * sqrt(1. - P->es * *sp * *sp )); - F = static_cast(P->opaque)->lam_1 * *sp; - *y = *R * (1 - cos(F)); - *x = *R * sin(F); -} - - -static PJ *destructor (PJ *P, int errlev) { - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - if( static_cast(P->opaque)->en ) - pj_dealloc (static_cast(P->opaque)->en); - - return pj_default_destructor(P, errlev); -} - - -PJ *PROJECTION(imw_p) { - double del, sig, s, t, x1, x2, T2, y1, m1, m2, y2; - int err; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - if (!(Q->en = pj_enfn(P->es))) return pj_default_destructor (P, ENOMEM); - if( (err = phi12(P, &del, &sig)) != 0) { - return destructor(P, err); - } - if (Q->phi_2 < Q->phi_1) { /* make sure P->phi_1 most southerly */ - del = Q->phi_1; - Q->phi_1 = Q->phi_2; - Q->phi_2 = del; - } - if (pj_param(P->ctx, P->params, "tlon_1").i) - Q->lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; - else { /* use predefined based upon latitude */ - sig = fabs(sig * RAD_TO_DEG); - if (sig <= 60) sig = 2.; - else if (sig <= 76) sig = 4.; - else sig = 8.; - Q->lam_1 = sig * DEG_TO_RAD; - } - Q->mode = NONE_IS_ZERO; - if (Q->phi_1 != 0.0) - xy(P, Q->phi_1, &x1, &y1, &Q->sphi_1, &Q->R_1); - else { - Q->mode = PHI_1_IS_ZERO; - y1 = 0.; - x1 = Q->lam_1; - } - if (Q->phi_2 != 0.0) - xy(P, Q->phi_2, &x2, &T2, &Q->sphi_2, &Q->R_2); - else { - Q->mode = PHI_2_IS_ZERO; - T2 = 0.; - x2 = Q->lam_1; - } - m1 = pj_mlfn(Q->phi_1, Q->sphi_1, cos(Q->phi_1), Q->en); - m2 = pj_mlfn(Q->phi_2, Q->sphi_2, cos(Q->phi_2), Q->en); - t = m2 - m1; - s = x2 - x1; - y2 = sqrt(t * t - s * s) + y1; - Q->C2 = y2 - T2; - t = 1. / t; - Q->P = (m2 * y1 - m1 * y2) * t; - Q->Q = (y2 - y1) * t; - Q->Pp = (m2 * x1 - m1 * x2) * t; - Q->Qp = (x2 - x1) * t; - - P->fwd = e_forward; - P->inv = e_inverse; - P->destructor = destructor; - - return P; -} diff --git a/src/projections/PJ_isea.cpp b/src/projections/PJ_isea.cpp deleted file mode 100644 index 522e6813..00000000 --- a/src/projections/PJ_isea.cpp +++ /dev/null @@ -1,1098 +0,0 @@ -/* - * This code was entirely written by Nathan Wagner - * and is in the public domain. - */ - -#include -#include -#include -#include -#include -#include - -#define PJ_LIB__ -#include "proj_internal.h" -#include "proj_math.h" -#include "proj.h" -#include "projects.h" - -#define DEG36 0.62831853071795864768 -#define DEG72 1.25663706143591729537 -#define DEG90 M_PI_2 -#define DEG108 1.88495559215387594306 -#define DEG120 2.09439510239319549229 -#define DEG144 2.51327412287183459075 -#define DEG180 M_PI - -/* sqrt(5)/M_PI */ -#define ISEA_SCALE 0.8301572857837594396028083 - -/* 26.565051177 degrees */ -#define V_LAT 0.46364760899944494524 - -/* 52.62263186 */ -#define E_RAD 0.91843818702186776133 - -/* 10.81231696 */ -#define F_RAD 0.18871053072122403508 - -/* R tan(g) sin(60) */ -#define TABLE_G 0.6615845383 - -/* H = 0.25 R tan g = */ -#define TABLE_H 0.1909830056 - -/* in radians */ -#define ISEA_STD_LAT 1.01722196792335072101 -#define ISEA_STD_LON .19634954084936207740 - -namespace { // anonymous namespace -struct hex { - int iso; - long x, y, z; -}; -} // anonymous namespace - -/* y *must* be positive down as the xy /iso conversion assumes this */ -static void hex_xy(struct hex *h) { - if (!h->iso) return; - if (h->x >= 0) { - h->y = -h->y - (h->x+1)/2; - } else { - /* need to round toward -inf, not toward zero, so x-1 */ - h->y = -h->y - h->x/2; - } - h->iso = 0; -} - -static void hex_iso(struct hex *h) { - if (h->iso) return; - - if (h->x >= 0) { - h->y = (-h->y - (h->x+1)/2); - } else { - /* need to round toward -inf, not toward zero, so x-1 */ - h->y = (-h->y - (h->x)/2); - } - - h->z = -h->x - h->y; - h->iso = 1; -} - -static void hexbin2(double width, double x, double y, long *i, long *j) { - double z, rx, ry, rz; - double abs_dx, abs_dy, abs_dz; - long ix, iy, iz, s; - struct hex h; - - x = x / cos(30 * M_PI / 180.0); /* rotated X coord */ - y = y - x / 2.0; /* adjustment for rotated X */ - - /* adjust for actual hexwidth */ - x /= width; - y /= width; - - z = -x - y; - - rx = floor(x + 0.5); - ix = lround(rx); - ry = floor(y + 0.5); - iy = lround(ry); - rz = floor(z + 0.5); - iz = lround(rz); - - s = ix + iy + iz; - - if (s) { - abs_dx = fabs(rx - x); - abs_dy = fabs(ry - y); - abs_dz = fabs(rz - z); - - if (abs_dx >= abs_dy && abs_dx >= abs_dz) { - ix -= s; - } else if (abs_dy >= abs_dx && abs_dy >= abs_dz) { - iy -= s; - } else { - iz -= s; - } - } - h.x = ix; - h.y = iy; - h.z = iz; - h.iso = 1; - - hex_xy(&h); - *i = h.x; - *j = h.y; -} - -namespace { // anonymous namespace -enum isea_poly { ISEA_NONE, ISEA_ICOSAHEDRON = 20 }; -enum isea_topology { ISEA_HEXAGON=6, ISEA_TRIANGLE=3, ISEA_DIAMOND=4 }; -enum isea_address_form { ISEA_GEO, ISEA_Q2DI, ISEA_SEQNUM, ISEA_INTERLEAVE, - ISEA_PLANE, ISEA_Q2DD, ISEA_PROJTRI, ISEA_VERTEX2DD, ISEA_HEX -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct isea_dgg { - int polyhedron; /* ignored, icosahedron */ - double o_lat, o_lon, o_az; /* orientation, radians */ - int pole; /* true if standard snyder */ - int topology; /* ignored, hexagon */ - int aperture; /* valid values depend on partitioning method */ - int resolution; - double radius; /* radius of the earth in meters, ignored 1.0 */ - int output; /* an isea_address_form */ - int triangle; /* triangle of last transformed point */ - int quad; /* quad of last transformed point */ - unsigned long serial; -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct isea_pt { - double x, y; -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct isea_geo { - double lon, lat; -}; -} // anonymous namespace - -/* ENDINC */ - -namespace { // anonymous namespace -enum snyder_polyhedron { - SNYDER_POLY_HEXAGON, SNYDER_POLY_PENTAGON, - SNYDER_POLY_TETRAHEDRON, SNYDER_POLY_CUBE, - SNYDER_POLY_OCTAHEDRON, SNYDER_POLY_DODECAHEDRON, - SNYDER_POLY_ICOSAHEDRON -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct snyder_constants { - double g, G, theta; - /* cppcheck-suppress unusedStructMember */ - double ea_w, ea_a, ea_b, g_w, g_a, g_b; -}; -} // anonymous namespace - -/* TODO put these in radians to avoid a later conversion */ -static const struct snyder_constants constants[] = { - {23.80018260, 62.15458023, 60.0, 3.75, 1.033, 0.968, 5.09, 1.195, 1.0}, - {20.07675127, 55.69063953, 54.0, 2.65, 1.030, 0.983, 3.59, 1.141, 1.027}, - {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {37.37736814, 36.0, 30.0, 17.27, 1.163, 0.860, 13.14, 1.584, 1.0}, -}; - -static struct isea_geo vertex[] = { - {0.0, DEG90}, - {DEG180, V_LAT}, - {-DEG108, V_LAT}, - {-DEG36, V_LAT}, - {DEG36, V_LAT}, - {DEG108, V_LAT}, - {-DEG144, -V_LAT}, - {-DEG72, -V_LAT}, - {0.0, -V_LAT}, - {DEG72, -V_LAT}, - {DEG144, -V_LAT}, - {0.0, -DEG90} -}; - -/* TODO make an isea_pt array of the vertices as well */ - -static int tri_v1[] = {0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 2, 3, 4, 5, 1, 11, 11, 11, 11, 11}; - -/* triangle Centers */ -static const struct isea_geo icostriangles[] = { - {0.0, 0.0}, - {-DEG144, E_RAD}, - {-DEG72, E_RAD}, - {0.0, E_RAD}, - {DEG72, E_RAD}, - {DEG144, E_RAD}, - {-DEG144, F_RAD}, - {-DEG72, F_RAD}, - {0.0, F_RAD}, - {DEG72, F_RAD}, - {DEG144, F_RAD}, - {-DEG108, -F_RAD}, - {-DEG36, -F_RAD}, - {DEG36, -F_RAD}, - {DEG108, -F_RAD}, - {DEG180, -F_RAD}, - {-DEG108, -E_RAD}, - {-DEG36, -E_RAD}, - {DEG36, -E_RAD}, - {DEG108, -E_RAD}, - {DEG180, -E_RAD}, -}; - -static double az_adjustment(int triangle) -{ - double adj; - - struct isea_geo v; - struct isea_geo c; - - v = vertex[tri_v1[triangle]]; - c = icostriangles[triangle]; - - /* TODO looks like the adjustment is always either 0 or 180 */ - /* at least if you pick your vertex carefully */ - adj = atan2(cos(v.lat) * sin(v.lon - c.lon), - cos(c.lat) * sin(v.lat) - - sin(c.lat) * cos(v.lat) * cos(v.lon - c.lon)); - return adj; -} - -static struct isea_pt isea_triangle_xy(int triangle) -{ - struct isea_pt c; - const double Rprime = 0.91038328153090290025; - - triangle = (triangle - 1) % 20; - - c.x = TABLE_G * ((triangle % 5) - 2) * 2.0; - if (triangle > 9) { - c.x += TABLE_G; - } - switch (triangle / 5) { - case 0: - c.y = 5.0 * TABLE_H; - break; - case 1: - c.y = TABLE_H; - break; - case 2: - c.y = -TABLE_H; - break; - case 3: - c.y = -5.0 * TABLE_H; - break; - default: - /* should be impossible */ - exit(EXIT_FAILURE); - }; - c.x *= Rprime; - c.y *= Rprime; - - return c; -} - -/* snyder eq 14 */ -static double sph_azimuth(double f_lon, double f_lat, - double t_lon, double t_lat) -{ - double az; - - az = atan2(cos(t_lat) * sin(t_lon - f_lon), - cos(f_lat) * sin(t_lat) - - sin(f_lat) * cos(t_lat) * cos(t_lon - f_lon) - ); - return az; -} - -#ifdef _MSC_VER -#pragma warning( push ) -/* disable unreachable code warning for return 0 */ -#pragma warning( disable : 4702 ) -#endif - -/* coord needs to be in radians */ -static int isea_snyder_forward(struct isea_geo * ll, struct isea_pt * out) -{ - int i; - - /* - * spherical distance from center of polygon face to any of its - * vertexes on the globe - */ - double g; - - /* - * spherical angle between radius vector to center and adjacent edge - * of spherical polygon on the globe - */ - double G; - - /* - * plane angle between radius vector to center and adjacent edge of - * plane polygon - */ - double theta; - - /* additional variables from snyder */ - double q, Rprime, H, Ag, Azprime, Az, dprime, f, rho, - x, y; - - /* variables used to store intermediate results */ - double cot_theta, tan_g, az_offset; - - /* how many multiples of 60 degrees we adjust the azimuth */ - int Az_adjust_multiples; - - struct snyder_constants c; - - /* - * TODO by locality of reference, start by trying the same triangle - * as last time - */ - - /* TODO put these constants in as radians to begin with */ - c = constants[SNYDER_POLY_ICOSAHEDRON]; - theta = PJ_TORAD(c.theta); - g = PJ_TORAD(c.g); - G = PJ_TORAD(c.G); - - for (i = 1; i <= 20; i++) { - double z; - struct isea_geo center; - - center = icostriangles[i]; - - /* step 1 */ - z = acos(sin(center.lat) * sin(ll->lat) - + cos(center.lat) * cos(ll->lat) * cos(ll->lon - center.lon)); - /* not on this triangle */ - if (z > g + 0.000005) { /* TODO DBL_EPSILON */ - continue; - } - - Az = sph_azimuth(center.lon, center.lat, ll->lon, ll->lat); - - /* step 2 */ - - /* This calculates "some" vertex coordinate */ - az_offset = az_adjustment(i); - - Az -= az_offset; - - /* TODO I don't know why we do this. It's not in snyder */ - /* maybe because we should have picked a better vertex */ - if (Az < 0.0) { - Az += 2.0 * M_PI; - } - /* - * adjust Az for the point to fall within the range of 0 to - * 2(90 - theta) or 60 degrees for the hexagon, by - * and therefore 120 degrees for the triangle - * of the icosahedron - * subtracting or adding multiples of 60 degrees to Az and - * recording the amount of adjustment - */ - - Az_adjust_multiples = 0; - while (Az < 0.0) { - Az += DEG120; - Az_adjust_multiples--; - } - while (Az > DEG120 + DBL_EPSILON) { - Az -= DEG120; - Az_adjust_multiples++; - } - - /* step 3 */ - cot_theta = 1.0 / tan(theta); - tan_g = tan(g); /* TODO this is a constant */ - - /* Calculate q from eq 9. */ - /* TODO cot_theta is cot(30) */ - q = atan2(tan_g, cos(Az) + sin(Az) * cot_theta); - - /* not in this triangle */ - if (z > q + 0.000005) { - continue; - } - /* step 4 */ - - /* Apply equations 5-8 and 10-12 in order */ - - /* eq 5 */ - /* Rprime = 0.9449322893 * R; */ - /* R' in the paper is for the truncated */ - Rprime = 0.91038328153090290025; - - /* eq 6 */ - H = acos(sin(Az) * sin(G) * cos(g) - cos(Az) * cos(G)); - - /* eq 7 */ - /* Ag = (Az + G + H - DEG180) * M_PI * R * R / DEG180; */ - Ag = Az + G + H - DEG180; - - /* eq 8 */ - Azprime = atan2(2.0 * Ag, Rprime * Rprime * tan_g * tan_g - 2.0 * Ag * cot_theta); - - /* eq 10 */ - /* cot(theta) = 1.73205080756887729355 */ - dprime = Rprime * tan_g / (cos(Azprime) + sin(Azprime) * cot_theta); - - /* eq 11 */ - f = dprime / (2.0 * Rprime * sin(q / 2.0)); - - /* eq 12 */ - rho = 2.0 * Rprime * f * sin(z / 2.0); - - /* - * add back the same 60 degree multiple adjustment from step - * 2 to Azprime - */ - - Azprime += DEG120 * Az_adjust_multiples; - - /* calculate rectangular coordinates */ - - x = rho * sin(Azprime); - y = rho * cos(Azprime); - - /* - * TODO - * translate coordinates to the origin for the particular - * hexagon on the flattened polyhedral map plot - */ - - out->x = x; - out->y = y; - - return i; - } - - /* - * should be impossible, this implies that the coordinate is not on - * any triangle - */ - - fprintf(stderr, "impossible transform: %f %f is not on any triangle\n", - PJ_TODEG(ll->lon), PJ_TODEG(ll->lat)); - - exit(EXIT_FAILURE); - - /* not reached */ - return 0; /* suppresses a warning */ -} - -#ifdef _MSC_VER -#pragma warning( pop ) -#endif - -/* - * return the new coordinates of any point in original coordinate system. - * Define a point (newNPold) in original coordinate system as the North Pole in - * new coordinate system, and the great circle connect the original and new - * North Pole as the lon0 longitude in new coordinate system, given any point - * in original coordinate system, this function return the new coordinates. - */ - -/* formula from Snyder, Map Projections: A working manual, p31 */ -/* - * old north pole at np in new coordinates - * could be simplified a bit with fewer intermediates - * - * TODO take a result pointer - */ -static struct isea_geo snyder_ctran(struct isea_geo * np, struct isea_geo * pt) -{ - struct isea_geo npt; - double alpha, phi, lambda, lambda0, beta, lambdap, phip; - double sin_phip; - double lp_b; /* lambda prime minus beta */ - double cos_p, sin_a; - - phi = pt->lat; - lambda = pt->lon; - alpha = np->lat; - beta = np->lon; - lambda0 = beta; - - cos_p = cos(phi); - sin_a = sin(alpha); - - /* mpawm 5-7 */ - sin_phip = sin_a * sin(phi) - cos(alpha) * cos_p * cos(lambda - lambda0); - - /* mpawm 5-8b */ - - /* use the two argument form so we end up in the right quadrant */ - lp_b = atan2(cos_p * sin(lambda - lambda0), - (sin_a * cos_p * cos(lambda - lambda0) + cos(alpha) * sin(phi))); - - lambdap = lp_b + beta; - - /* normalize longitude */ - /* TODO can we just do a modulus ? */ - lambdap = fmod(lambdap, 2 * M_PI); - while (lambdap > M_PI) - lambdap -= 2 * M_PI; - while (lambdap < -M_PI) - lambdap += 2 * M_PI; - - phip = asin(sin_phip); - - npt.lat = phip; - npt.lon = lambdap; - - return npt; -} - -static struct isea_geo isea_ctran(struct isea_geo * np, struct isea_geo * pt, - double lon0) -{ - struct isea_geo npt; - - np->lon += M_PI; - npt = snyder_ctran(np, pt); - np->lon -= M_PI; - - npt.lon -= (M_PI - lon0 + np->lon); - - /* - * snyder is down tri 3, isea is along side of tri1 from vertex 0 to - * vertex 1 these are 180 degrees apart - */ - npt.lon += M_PI; - /* normalize longitude */ - npt.lon = fmod(npt.lon, 2 * M_PI); - while (npt.lon > M_PI) - npt.lon -= 2 * M_PI; - while (npt.lon < -M_PI) - npt.lon += 2 * M_PI; - - return npt; -} - -/* fuller's at 5.2454 west, 2.3009 N, adjacent at 7.46658 deg */ - -static int isea_grid_init(struct isea_dgg * g) -{ - if (!g) - return 0; - - g->polyhedron = 20; - g->o_lat = ISEA_STD_LAT; - g->o_lon = ISEA_STD_LON; - g->o_az = 0.0; - g->aperture = 4; - g->resolution = 6; - g->radius = 1.0; - g->topology = 6; - - return 1; -} - -static void isea_orient_isea(struct isea_dgg * g) -{ - if (!g) - return; - g->o_lat = ISEA_STD_LAT; - g->o_lon = ISEA_STD_LON; - g->o_az = 0.0; -} - -static void isea_orient_pole(struct isea_dgg * g) -{ - if (!g) - return; - g->o_lat = M_PI / 2.0; - g->o_lon = 0.0; - g->o_az = 0; -} - -static int isea_transform(struct isea_dgg * g, struct isea_geo * in, - struct isea_pt * out) -{ - struct isea_geo i, pole; - int tri; - - pole.lat = g->o_lat; - pole.lon = g->o_lon; - - i = isea_ctran(&pole, in, g->o_az); - - tri = isea_snyder_forward(&i, out); - out->x *= g->radius; - out->y *= g->radius; - g->triangle = tri; - - return tri; -} - -#define DOWNTRI(tri) (((tri - 1) / 5) % 2 == 1) - -static void isea_rotate(struct isea_pt * pt, double degrees) -{ - double rad; - - double x, y; - - rad = -degrees * M_PI / 180.0; - while (rad >= 2.0 * M_PI) rad -= 2.0 * M_PI; - while (rad <= -2.0 * M_PI) rad += 2.0 * M_PI; - - x = pt->x * cos(rad) + pt->y * sin(rad); - y = -pt->x * sin(rad) + pt->y * cos(rad); - - pt->x = x; - pt->y = y; -} - -static int isea_tri_plane(int tri, struct isea_pt *pt, double radius) { - struct isea_pt tc; /* center of triangle */ - - if (DOWNTRI(tri)) { - isea_rotate(pt, 180.0); - } - tc = isea_triangle_xy(tri); - tc.x *= radius; - tc.y *= radius; - pt->x += tc.x; - pt->y += tc.y; - - return tri; -} - -/* convert projected triangle coords to quad xy coords, return quad number */ -static int isea_ptdd(int tri, struct isea_pt *pt) { - int downtri, quad; - - downtri = (((tri - 1) / 5) % 2 == 1); - quad = ((tri - 1) % 5) + ((tri - 1) / 10) * 5 + 1; - - isea_rotate(pt, downtri ? 240.0 : 60.0); - if (downtri) { - pt->x += 0.5; - /* pt->y += cos(30.0 * M_PI / 180.0); */ - pt->y += .86602540378443864672; - } - return quad; -} - -static int isea_dddi_ap3odd(struct isea_dgg *g, int quad, struct isea_pt *pt, - struct isea_pt *di) -{ - struct isea_pt v; - double hexwidth; - double sidelength; /* in hexes */ - long d, i; - long maxcoord; - struct hex h; - - /* This is the number of hexes from apex to base of a triangle */ - sidelength = (pow(2.0, g->resolution) + 1.0) / 2.0; - - /* apex to base is cos(30deg) */ - hexwidth = cos(M_PI / 6.0) / sidelength; - - /* TODO I think sidelength is always x.5, so - * (int)sidelength * 2 + 1 might be just as good - */ - maxcoord = lround((sidelength * 2.0)); - - v = *pt; - hexbin2(hexwidth, v.x, v.y, &h.x, &h.y); - h.iso = 0; - hex_iso(&h); - - d = h.x - h.z; - i = h.x + h.y + h.y; - - /* - * you want to test for max coords for the next quad in the same - * "row" first to get the case where both are max - */ - if (quad <= 5) { - if (d == 0 && i == maxcoord) { - /* north pole */ - quad = 0; - d = 0; - i = 0; - } else if (i == maxcoord) { - /* upper right in next quad */ - quad += 1; - if (quad == 6) - quad = 1; - i = maxcoord - d; - d = 0; - } else if (d == maxcoord) { - /* lower right in quad to lower right */ - quad += 5; - d = 0; - } - } else if (quad >= 6) { - if (i == 0 && d == maxcoord) { - /* south pole */ - quad = 11; - d = 0; - i = 0; - } else if (d == maxcoord) { - /* lower right in next quad */ - quad += 1; - if (quad == 11) - quad = 6; - d = maxcoord - i; - i = 0; - } else if (i == maxcoord) { - /* upper right in quad to upper right */ - quad = (quad - 4) % 5; - i = 0; - } - } - - di->x = d; - di->y = i; - - g->quad = quad; - return quad; -} - -static int isea_dddi(struct isea_dgg *g, int quad, struct isea_pt *pt, - struct isea_pt *di) { - struct isea_pt v; - double hexwidth; - long sidelength; /* in hexes */ - struct hex h; - - if (g->aperture == 3 && g->resolution % 2 != 0) { - return isea_dddi_ap3odd(g, quad, pt, di); - } - /* todo might want to do this as an iterated loop */ - if (g->aperture >0) { - sidelength = lround(pow(g->aperture, g->resolution / 2.0)); - } else { - sidelength = g->resolution; - } - - hexwidth = 1.0 / sidelength; - - v = *pt; - isea_rotate(&v, -30.0); - hexbin2(hexwidth, v.x, v.y, &h.x, &h.y); - h.iso = 0; - hex_iso(&h); - - /* we may actually be on another quad */ - if (quad <= 5) { - if (h.x == 0 && h.z == -sidelength) { - /* north pole */ - quad = 0; - h.z = 0; - h.y = 0; - h.x = 0; - } else if (h.z == -sidelength) { - quad = quad + 1; - if (quad == 6) - quad = 1; - h.y = sidelength - h.x; - h.z = h.x - sidelength; - h.x = 0; - } else if (h.x == sidelength) { - quad += 5; - h.y = -h.z; - h.x = 0; - } - } else if (quad >= 6) { - if (h.z == 0 && h.x == sidelength) { - /* south pole */ - quad = 11; - h.x = 0; - h.y = 0; - h.z = 0; - } else if (h.x == sidelength) { - quad = quad + 1; - if (quad == 11) - quad = 6; - h.x = h.y + sidelength; - h.y = 0; - h.z = -h.x; - } else if (h.y == -sidelength) { - quad -= 4; - h.y = 0; - h.z = -h.x; - } - } - di->x = h.x; - di->y = -h.z; - - g->quad = quad; - return quad; -} - -static int isea_ptdi(struct isea_dgg *g, int tri, struct isea_pt *pt, - struct isea_pt *di) { - struct isea_pt v; - int quad; - - v = *pt; - quad = isea_ptdd(tri, &v); - quad = isea_dddi(g, quad, &v, di); - return quad; -} - -/* q2di to seqnum */ - -static long isea_disn(struct isea_dgg *g, int quad, struct isea_pt *di) { - long sidelength; - long sn, height; - long hexes; - - if (quad == 0) { - g->serial = 1; - return g->serial; - } - /* hexes in a quad */ - hexes = lround(pow(g->aperture, g->resolution)); - if (quad == 11) { - g->serial = 1 + 10 * hexes + 1; - return g->serial; - } - if (g->aperture == 3 && g->resolution % 2 == 1) { - height = lround(floor((pow(g->aperture, (g->resolution - 1) / 2.0)))); - sn = ((long)di->x) * height; - sn += ((long)di->y) / height; - sn += (quad - 1) * hexes; - sn += 2; - } else { - sidelength = lround((pow(g->aperture, g->resolution / 2.0))); - sn = lround(floor(((quad - 1) * hexes + sidelength * di->x + di->y + 2))); - } - - g->serial = sn; - return sn; -} - -/* TODO just encode the quad in the d or i coordinate - * quad is 0-11, which can be four bits. - * d' = d << 4 + q, d = d' >> 4, q = d' & 0xf - */ -/* convert a q2di to global hex coord */ -static int isea_hex(struct isea_dgg *g, int tri, - struct isea_pt *pt, struct isea_pt *hex) { - struct isea_pt v; -#ifdef FIXME - long sidelength; - long d, i, x, y; -#endif - int quad; - - quad = isea_ptdi(g, tri, pt, &v); - - hex->x = ((int)v.x << 4) + quad; - hex->y = v.y; - - return 1; -#ifdef FIXME - d = lround(floor(v.x)); - i = lround(floor(v.y)); - - /* Aperture 3 odd resolutions */ - if (g->aperture == 3 && g->resolution % 2 != 0) { - long offset = lround((pow(3.0, g->resolution - 1) + 0.5)); - - d += offset * ((g->quad-1) % 5); - i += offset * ((g->quad-1) % 5); - - if (quad == 0) { - d = 0; - i = offset; - } else if (quad == 11) { - d = 2 * offset; - i = 0; - } else if (quad > 5) { - d += offset; - } - - x = (2*d - i) /3; - y = (2*i - d) /3; - - hex->x = x + offset / 3; - hex->y = y + 2 * offset / 3; - return 1; - } - - /* aperture 3 even resolutions and aperture 4 */ - sidelength = lround((pow(g->aperture, g->resolution / 2.0))); - if (g->quad == 0) { - hex->x = 0; - hex->y = sidelength; - } else if (g->quad == 11) { - hex->x = sidelength * 2; - hex->y = 0; - } else { - hex->x = d + sidelength * ((g->quad-1) % 5); - if (g->quad > 5) hex->x += sidelength; - hex->y = i + sidelength * ((g->quad-1) % 5); - } - - return 1; -#endif -} - -static struct isea_pt isea_forward(struct isea_dgg *g, struct isea_geo *in) -{ - int tri; - struct isea_pt out, coord; - - tri = isea_transform(g, in, &out); - - if (g->output == ISEA_PLANE) { - isea_tri_plane(tri, &out, g->radius); - return out; - } - - /* convert to isea standard triangle size */ - out.x = out.x / g->radius * ISEA_SCALE; - out.y = out.y / g->radius * ISEA_SCALE; - out.x += 0.5; - out.y += 2.0 * .14433756729740644112; - - switch (g->output) { - case ISEA_PROJTRI: - /* nothing to do, already in projected triangle */ - break; - case ISEA_VERTEX2DD: - g->quad = isea_ptdd(tri, &out); - break; - case ISEA_Q2DD: - /* Same as above, we just don't print as much */ - g->quad = isea_ptdd(tri, &out); - break; - case ISEA_Q2DI: - g->quad = isea_ptdi(g, tri, &out, &coord); - return coord; - break; - case ISEA_SEQNUM: - isea_ptdi(g, tri, &out, &coord); - /* disn will set g->serial */ - isea_disn(g, g->quad, &coord); - return coord; - break; - case ISEA_HEX: - isea_hex(g, tri, &out, &coord); - return coord; - break; - } - - return out; -} - -/* - * Proj 4 integration code follows - */ - -PROJ_HEAD(isea, "Icosahedral Snyder Equal Area") "\n\tSph"; - -namespace { // anonymous namespace -struct pj_opaque { - struct isea_dgg dgg; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - struct isea_pt out; - struct isea_geo in; - - in.lon = lp.lam; - in.lat = lp.phi; - - out = isea_forward(&Q->dgg, &in); - - xy.x = out.x; - xy.y = out.y; - - return xy; -} - - -PJ *PROJECTION(isea) { - char *opt; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - - P->fwd = s_forward; - isea_grid_init(&Q->dgg); - - Q->dgg.output = ISEA_PLANE; -/* P->dgg.radius = P->a; / * otherwise defaults to 1 */ - /* calling library will scale, I think */ - - opt = pj_param(P->ctx,P->params, "sorient").s; - if (opt) { - if (!strcmp(opt, "isea")) { - isea_orient_isea(&Q->dgg); - } else if (!strcmp(opt, "pole")) { - isea_orient_pole(&Q->dgg); - } else { - return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - } - } - - if (pj_param(P->ctx,P->params, "tazi").i) { - Q->dgg.o_az = pj_param(P->ctx,P->params, "razi").f; - } - - if (pj_param(P->ctx,P->params, "tlon_0").i) { - Q->dgg.o_lon = pj_param(P->ctx,P->params, "rlon_0").f; - } - - if (pj_param(P->ctx,P->params, "tlat_0").i) { - Q->dgg.o_lat = pj_param(P->ctx,P->params, "rlat_0").f; - } - - if (pj_param(P->ctx,P->params, "taperture").i) { - Q->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i; - } - - if (pj_param(P->ctx,P->params, "tresolution").i) { - Q->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i; - } - - opt = pj_param(P->ctx,P->params, "smode").s; - if (opt) { - if (!strcmp(opt, "plane")) { - Q->dgg.output = ISEA_PLANE; - } else if (!strcmp(opt, "di")) { - Q->dgg.output = ISEA_Q2DI; - } - else if (!strcmp(opt, "dd")) { - Q->dgg.output = ISEA_Q2DD; - } - else if (!strcmp(opt, "hex")) { - Q->dgg.output = ISEA_HEX; - } - else { - /* TODO verify error code. Possibly eliminate magic */ - return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - } - } - - if (pj_param(P->ctx,P->params, "trescale").i) { - Q->dgg.radius = ISEA_SCALE; - } - - if (pj_param(P->ctx,P->params, "tresolution").i) { - Q->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i; - } else { - Q->dgg.resolution = 4; - } - - if (pj_param(P->ctx,P->params, "taperture").i) { - Q->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i; - } else { - Q->dgg.aperture = 3; - } - - return P; -} diff --git a/src/projections/PJ_krovak.cpp b/src/projections/PJ_krovak.cpp deleted file mode 100644 index 9ecffb89..00000000 --- a/src/projections/PJ_krovak.cpp +++ /dev/null @@ -1,222 +0,0 @@ - /* - * 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 -#include - -#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(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(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(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; -} diff --git a/src/projections/PJ_labrd.cpp b/src/projections/PJ_labrd.cpp deleted file mode 100644 index d3930243..00000000 --- a/src/projections/PJ_labrd.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(labrd, "Laborde") "\n\tCyl, Sph\n\tSpecial for Madagascar"; -#define EPS 1.e-10 - -namespace { // anonymous namespace -struct pj_opaque { - double kRg, p0s, A, C, Ca, Cb, Cc, Cd; -}; -} // anonymous namespace - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double V1, V2, ps, sinps, cosps, sinps2, cosps2; - double I1, I2, I3, I4, I5, I6, x2, y2, t; - - V1 = Q->A * log( tan(M_FORTPI + .5 * lp.phi) ); - t = P->e * sin(lp.phi); - V2 = .5 * P->e * Q->A * log ((1. + t)/(1. - t)); - ps = 2. * (atan(exp(V1 - V2 + Q->C)) - M_FORTPI); - I1 = ps - Q->p0s; - cosps = cos(ps); cosps2 = cosps * cosps; - sinps = sin(ps); sinps2 = sinps * sinps; - I4 = Q->A * cosps; - I2 = .5 * Q->A * I4 * sinps; - I3 = I2 * Q->A * Q->A * (5. * cosps2 - sinps2) / 12.; - I6 = I4 * Q->A * Q->A; - I5 = I6 * (cosps2 - sinps2) / 6.; - I6 *= Q->A * Q->A * - (5. * cosps2 * cosps2 + sinps2 * (sinps2 - 18. * cosps2)) / 120.; - t = lp.lam * lp.lam; - xy.x = Q->kRg * lp.lam * (I4 + t * (I5 + t * I6)); - xy.y = Q->kRg * (I1 + t * (I2 + t * I3)); - x2 = xy.x * xy.x; - y2 = xy.y * xy.y; - V1 = 3. * xy.x * y2 - xy.x * x2; - V2 = xy.y * y2 - 3. * x2 * xy.y; - xy.x += Q->Ca * V1 + Q->Cb * V2; - xy.y += Q->Ca * V2 - Q->Cb * V1; - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - /* t = 0.0 optimization is to avoid a false positive cppcheck warning */ - /* (cppcheck git beaf29c15867984aa3c2a15cf15bd7576ccde2b3). Might no */ - /* longer be necessary with later versions. */ - double x2, y2, V1, V2, V3, V4, t = 0.0, t2, ps, pe, tpe, s; - double I7, I8, I9, I10, I11, d, Re; - int i; - - x2 = xy.x * xy.x; - y2 = xy.y * xy.y; - V1 = 3. * xy.x * y2 - xy.x * x2; - V2 = xy.y * y2 - 3. * x2 * xy.y; - V3 = xy.x * (5. * y2 * y2 + x2 * (-10. * y2 + x2 )); - V4 = xy.y * (5. * x2 * x2 + y2 * (-10. * x2 + y2 )); - xy.x += - Q->Ca * V1 - Q->Cb * V2 + Q->Cc * V3 + Q->Cd * V4; - xy.y += Q->Cb * V1 - Q->Ca * V2 - Q->Cd * V3 + Q->Cc * V4; - ps = Q->p0s + xy.y / Q->kRg; - pe = ps + P->phi0 - Q->p0s; - - for ( i = 20; i; --i) { - V1 = Q->A * log(tan(M_FORTPI + .5 * pe)); - tpe = P->e * sin(pe); - V2 = .5 * P->e * Q->A * log((1. + tpe)/(1. - tpe)); - t = ps - 2. * (atan(exp(V1 - V2 + Q->C)) - M_FORTPI); - pe += t; - if (fabs(t) < EPS) - break; - } - - t = P->e * sin(pe); - t = 1. - t * t; - Re = P->one_es / ( t * sqrt(t) ); - t = tan(ps); - t2 = t * t; - s = Q->kRg * Q->kRg; - d = Re * P->k0 * Q->kRg; - I7 = t / (2. * d); - I8 = t * (5. + 3. * t2) / (24. * d * s); - d = cos(ps) * Q->kRg * Q->A; - I9 = 1. / d; - d *= s; - I10 = (1. + 2. * t2) / (6. * d); - I11 = (5. + t2 * (28. + 24. * t2)) / (120. * d * s); - x2 = xy.x * xy.x; - lp.phi = pe + x2 * (-I7 + I8 * x2); - lp.lam = xy.x * (I9 + x2 * (-I10 + x2 * I11)); - return lp; -} - - -PJ *PROJECTION(labrd) { - double Az, sinp, R, N, t; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Az = pj_param(P->ctx, P->params, "razi").f; - sinp = sin(P->phi0); - t = 1. - P->es * sinp * sinp; - N = 1. / sqrt(t); - R = P->one_es * N / t; - Q->kRg = P->k0 * sqrt( N * R ); - Q->p0s = atan( sqrt(R / N) * tan(P->phi0) ); - Q->A = sinp / sin(Q->p0s); - t = P->e * sinp; - Q->C = .5 * P->e * Q->A * log((1. + t)/(1. - t)) + - - Q->A * log( tan(M_FORTPI + .5 * P->phi0)) - + log( tan(M_FORTPI + .5 * Q->p0s)); - t = Az + Az; - Q->Ca = (1. - cos(t)) * ( Q->Cb = 1. / (12. * Q->kRg * Q->kRg) ); - Q->Cb *= sin(t); - Q->Cc = 3. * (Q->Ca * Q->Ca - Q->Cb * Q->Cb); - Q->Cd = 6. * Q->Ca * Q->Cb; - - P->inv = e_inverse; - P->fwd = e_forward; - - return P; -} diff --git a/src/projections/PJ_laea.cpp b/src/projections/PJ_laea.cpp deleted file mode 100644 index dd02c75a..00000000 --- a/src/projections/PJ_laea.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -PROJ_HEAD(laea, "Lambert Azimuthal Equal Area") "\n\tAzi, Sph&Ell"; - -namespace { // anonymous namespace -enum Mode { - N_POLE = 0, - S_POLE = 1, - EQUIT = 2, - OBLIQ = 3 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double sinb1; - double cosb1; - double xmf; - double ymf; - double mmf; - double qp; - double dd; - double rq; - double *apa; - enum Mode mode; -}; -} // anonymous namespace - -#define EPS10 1.e-10 - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, sinlam, sinphi, q, sinb=0.0, cosb=0.0, b=0.0; - - coslam = cos(lp.lam); - sinlam = sin(lp.lam); - sinphi = sin(lp.phi); - q = pj_qsfn(sinphi, P->e, P->one_es); - - if (Q->mode == OBLIQ || Q->mode == EQUIT) { - sinb = q / Q->qp; - cosb = sqrt(1. - sinb * sinb); - } - - switch (Q->mode) { - case OBLIQ: - b = 1. + Q->sinb1 * sinb + Q->cosb1 * cosb * coslam; - break; - case EQUIT: - b = 1. + cosb * coslam; - break; - case N_POLE: - b = M_HALFPI + lp.phi; - q = Q->qp - q; - break; - case S_POLE: - b = lp.phi - M_HALFPI; - q = Q->qp + q; - break; - } - if (fabs(b) < EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - - switch (Q->mode) { - case OBLIQ: - b = sqrt(2. / b); - xy.y = Q->ymf * b * (Q->cosb1 * sinb - Q->sinb1 * cosb * coslam); - goto eqcon; - break; - case EQUIT: - b = sqrt(2. / (1. + cosb * coslam)); - xy.y = b * sinb * Q->ymf; -eqcon: - xy.x = Q->xmf * b * cosb * sinlam; - break; - case N_POLE: - case S_POLE: - if (q >= 0.) { - b = sqrt(q); - xy.x = b * sinlam; - xy.y = coslam * (Q->mode == S_POLE ? b : -b); - } else - xy.x = xy.y = 0.; - break; - } - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, cosphi, sinphi; - - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - coslam = cos(lp.lam); - switch (Q->mode) { - case EQUIT: - xy.y = 1. + cosphi * coslam; - goto oblcon; - case OBLIQ: - xy.y = 1. + Q->sinb1 * sinphi + Q->cosb1 * cosphi * coslam; -oblcon: - if (xy.y <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.y = sqrt(2. / xy.y); - xy.x = xy.y * cosphi * sin(lp.lam); - xy.y *= Q->mode == EQUIT ? sinphi : - Q->cosb1 * sinphi - Q->sinb1 * cosphi * coslam; - break; - case N_POLE: - coslam = -coslam; - /*-fallthrough*/ - case S_POLE: - if (fabs(lp.phi + P->phi0) < EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.y = M_FORTPI - lp.phi * .5; - xy.y = 2. * (Q->mode == S_POLE ? cos(xy.y) : sin(xy.y)); - xy.x = xy.y * sin(lp.lam); - xy.y *= coslam; - break; - } - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cCe, sCe, q, rho, ab=0.0; - - switch (Q->mode) { - case EQUIT: - case OBLIQ: - xy.x /= Q->dd; - xy.y *= Q->dd; - rho = hypot(xy.x, xy.y); - if (rho < EPS10) { - lp.lam = 0.; - lp.phi = P->phi0; - return lp; - } - sCe = 2. * asin(.5 * rho / Q->rq); - cCe = cos(sCe); - sCe = sin(sCe); - xy.x *= sCe; - if (Q->mode == OBLIQ) { - ab = cCe * Q->sinb1 + xy.y * sCe * Q->cosb1 / rho; - xy.y = rho * Q->cosb1 * cCe - xy.y * Q->sinb1 * sCe; - } else { - ab = xy.y * sCe / rho; - xy.y = rho * cCe; - } - break; - case N_POLE: - xy.y = -xy.y; - /*-fallthrough*/ - case S_POLE: - q = (xy.x * xy.x + xy.y * xy.y); - if (q == 0.0) { - lp.lam = 0.; - lp.phi = P->phi0; - return (lp); - } - ab = 1. - q / Q->qp; - if (Q->mode == S_POLE) - ab = - ab; - break; - } - lp.lam = atan2(xy.x, xy.y); - lp.phi = pj_authlat(asin(ab), Q->apa); - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cosz=0.0, rh, sinz=0.0; - - rh = hypot(xy.x, xy.y); - if ((lp.phi = rh * .5 ) > 1.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - lp.phi = 2. * asin(lp.phi); - if (Q->mode == OBLIQ || Q->mode == EQUIT) { - sinz = sin(lp.phi); - cosz = cos(lp.phi); - } - switch (Q->mode) { - case EQUIT: - lp.phi = fabs(rh) <= EPS10 ? 0. : asin(xy.y * sinz / rh); - xy.x *= sinz; - xy.y = cosz * rh; - break; - case OBLIQ: - lp.phi = fabs(rh) <= EPS10 ? P->phi0 : - asin(cosz * Q->sinb1 + xy.y * sinz * Q->cosb1 / rh); - xy.x *= sinz * Q->cosb1; - xy.y = (cosz - sin(lp.phi) * Q->sinb1) * rh; - break; - case N_POLE: - xy.y = -xy.y; - lp.phi = M_HALFPI - lp.phi; - break; - case S_POLE: - lp.phi -= M_HALFPI; - break; - } - lp.lam = (xy.y == 0. && (Q->mode == EQUIT || Q->mode == OBLIQ)) ? - 0. : atan2(xy.x, xy.y); - return (lp); -} - - -static PJ *destructor (PJ *P, int errlev) { - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->apa); - - return pj_default_destructor(P, errlev); -} - - -PJ *PROJECTION(laea) { - double t; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - P->destructor = destructor; - - t = fabs(P->phi0); - if (fabs(t - M_HALFPI) < EPS10) - Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - else if (fabs(t) < EPS10) - Q->mode = EQUIT; - else - Q->mode = OBLIQ; - if (P->es != 0.0) { - double sinphi; - - P->e = sqrt(P->es); - Q->qp = pj_qsfn(1., P->e, P->one_es); - Q->mmf = .5 / (1. - P->es); - Q->apa = pj_authset(P->es); - if (nullptr==Q->apa) - return destructor(P, ENOMEM); - switch (Q->mode) { - case N_POLE: - case S_POLE: - Q->dd = 1.; - break; - case EQUIT: - Q->dd = 1. / (Q->rq = sqrt(.5 * Q->qp)); - Q->xmf = 1.; - Q->ymf = .5 * Q->qp; - break; - case OBLIQ: - Q->rq = sqrt(.5 * Q->qp); - sinphi = sin(P->phi0); - Q->sinb1 = pj_qsfn(sinphi, P->e, P->one_es) / Q->qp; - Q->cosb1 = sqrt(1. - Q->sinb1 * Q->sinb1); - Q->dd = cos(P->phi0) / (sqrt(1. - P->es * sinphi * sinphi) * - Q->rq * Q->cosb1); - Q->ymf = (Q->xmf = Q->rq) / Q->dd; - Q->xmf *= Q->dd; - break; - } - P->inv = e_inverse; - P->fwd = e_forward; - } else { - if (Q->mode == OBLIQ) { - Q->sinb1 = sin(P->phi0); - Q->cosb1 = cos(P->phi0); - } - P->inv = s_inverse; - P->fwd = s_forward; - } - - return P; -} - diff --git a/src/projections/PJ_lagrng.cpp b/src/projections/PJ_lagrng.cpp deleted file mode 100644 index 8c0150aa..00000000 --- a/src/projections/PJ_lagrng.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#define PJ_LIB__ -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(lagrng, "Lagrange") "\n\tMisc Sph\n\tW="; - -#define TOL 1e-10 - -namespace { // anonymous namespace -struct pj_opaque { - double a1; - double a2; - double hrw; - double hw; - double rw; - double w; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double v, c; - - if (fabs(fabs(lp.phi) - M_HALFPI) < TOL) { - xy.x = 0; - xy.y = lp.phi < 0 ? -2. : 2.; - } else { - lp.phi = sin(lp.phi); - v = Q->a1 * pow((1. + lp.phi)/(1. - lp.phi), Q->hrw); - lp.lam *= Q->rw; - c = 0.5 * (v + 1./v) + cos(lp.lam); - if (c < TOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.x = 2. * sin(lp.lam) / c; - xy.y = (v - 1./v) / c; - } - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double c, x2, y2p, y2m; - - if (fabs(fabs(xy.y) - 2.) < TOL) { - lp.phi = xy.y < 0 ? -M_HALFPI : M_HALFPI; - lp.lam = 0; - } else { - x2 = xy.x * xy.x; - y2p = 2. + xy.y; - y2m = 2. - xy.y; - c = y2p * y2m - x2; - if (fabs(c) < TOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - lp.phi = 2. * atan(pow((y2p * y2p + x2) / (Q->a2 * (y2m * y2m + x2)), Q->hw)) - M_HALFPI; - lp.lam = Q->w * atan2(4. * xy.x, c); - } - return lp; -} - - -PJ *PROJECTION(lagrng) { - double phi1; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->w = pj_param(P->ctx, P->params, "dW").f; - if (Q->w <= 0) - return pj_default_destructor(P, PJD_ERR_W_OR_M_ZERO_OR_LESS); - Q->hw = 0.5 * Q->w; - Q->rw = 1. / Q->w; - Q->hrw = 0.5 * Q->rw; - phi1 = sin(pj_param(P->ctx, P->params, "rlat_1").f); - if (fabs(fabs(phi1) - 1.) < TOL) - return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); - - Q->a1 = pow((1. - phi1)/(1. + phi1), Q->hrw); - Q->a2 = Q->a1 * Q->a1; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} - diff --git a/src/projections/PJ_larr.cpp b/src/projections/PJ_larr.cpp deleted file mode 100644 index e4d5d240..00000000 --- a/src/projections/PJ_larr.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(larr, "Larrivee") "\n\tMisc Sph, no inv"; - -#define SIXTH .16666666666666666 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - xy.x = 0.5 * lp.lam * (1. + sqrt(cos(lp.phi))); - xy.y = lp.phi / (cos(0.5 * lp.phi) * cos(SIXTH * lp.lam)); - return xy; -} - - -PJ *PROJECTION(larr) { - - P->es = 0; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_lask.cpp b/src/projections/PJ_lask.cpp deleted file mode 100644 index 46f23edb..00000000 --- a/src/projections/PJ_lask.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#define PJ_LIB__ -#include "projects.h" - -PROJ_HEAD(lask, "Laskowski") "\n\tMisc Sph, no inv"; - -#define a10 0.975534 -#define a12 -0.119161 -#define a32 -0.0143059 -#define a14 -0.0547009 -#define b01 1.00384 -#define b21 0.0802894 -#define b03 0.0998909 -#define b41 0.000199025 -#define b23 -0.0285500 -#define b05 -0.0491032 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double l2, p2; - (void) P; - - l2 = lp.lam * lp.lam; - p2 = lp.phi * lp.phi; - xy.x = lp.lam * (a10 + p2 * (a12 + l2 * a32 + p2 * a14)); - xy.y = lp.phi * (b01 + l2 * (b21 + p2 * b23 + l2 * b41) + - p2 * (b03 + p2 * b05)); - return xy; -} - - -PJ *PROJECTION(lask) { - - P->fwd = s_forward; - P->es = 0.; - - return P; -} - diff --git a/src/projections/PJ_latlong.cpp b/src/projections/PJ_latlong.cpp deleted file mode 100644 index 1331d59a..00000000 --- a/src/projections/PJ_latlong.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Stub projection implementation for lat/long coordinates. We - * don't actually change the coordinates, but we want proj=latlong - * to act sort of like a projection. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2000, Frank Warmerdam - * - * 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. - *****************************************************************************/ - -/* very loosely based upon DMA code by Bradford W. Drew */ -#define PJ_LIB__ -#include "proj_internal.h" -#include "projects.h" - -PROJ_HEAD(lonlat, "Lat/long (Geodetic)") "\n\t"; -PROJ_HEAD(latlon, "Lat/long (Geodetic alias)") "\n\t"; -PROJ_HEAD(latlong, "Lat/long (Geodetic alias)") "\n\t"; -PROJ_HEAD(longlat, "Lat/long (Geodetic alias)") "\n\t"; - - - static XY latlong_forward(LP lp, PJ *P) { - XY xy = {0.0,0.0}; - (void) P; - xy.x = lp.lam; - xy.y = lp.phi; - return xy; -} - - -static LP latlong_inverse(XY xy, PJ *P) { - LP lp = {0.0,0.0}; - (void) P; - lp.phi = xy.y; - lp.lam = xy.x; - return lp; -} - - - static XYZ latlong_forward_3d (LPZ lpz, PJ *P) { - XYZ xyz = {0,0,0}; - (void) P; - xyz.x = lpz.lam; - xyz.y = lpz.phi; - xyz.z = lpz.z; - return xyz; -} - - -static LPZ latlong_inverse_3d (XYZ xyz, PJ *P) { - LPZ lpz = {0,0,0}; - (void) P; - lpz.lam = xyz.x; - lpz.phi = xyz.y; - lpz.z = xyz.z; - return lpz; -} - -static PJ_COORD latlong_forward_4d (PJ_COORD obs, PJ *P) { - (void) P; - return obs; -} - - -static PJ_COORD latlong_inverse_4d (PJ_COORD obs, PJ *P) { - (void) P; - return obs; -} - - - -static PJ *latlong_setup (PJ *P) { - P->is_latlong = 1; - P->x0 = 0; - P->y0 = 0; - P->inv = latlong_inverse; - P->fwd = latlong_forward; - P->inv3d = latlong_inverse_3d; - P->fwd3d = latlong_forward_3d; - P->inv4d = latlong_inverse_4d; - P->fwd4d = latlong_forward_4d; - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_ANGULAR; - return P; -} - -PJ *PROJECTION(latlong) { - return latlong_setup (P); -} - - -PJ *PROJECTION(longlat) { - return latlong_setup (P); -} - - -PJ *PROJECTION(latlon) { - return latlong_setup (P); -} - - -PJ *PROJECTION(lonlat) { - return latlong_setup (P); -} - diff --git a/src/projections/PJ_lcc.cpp b/src/projections/PJ_lcc.cpp deleted file mode 100644 index 7d6e3f57..00000000 --- a/src/projections/PJ_lcc.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -PROJ_HEAD(lcc, "Lambert Conformal Conic") - "\n\tConic, Sph&Ell\n\tlat_1= and lat_2= or lat_0, k_0="; - -#define EPS10 1.e-10 - -namespace { // anonymous namespace -struct pj_opaque { - double phi1; - double phi2; - double n; - double rho0; - double c; -}; -} // anonymous namespace - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0., 0.}; - struct pj_opaque *Q = static_cast(P->opaque); - double rho; - - if (fabs(fabs(lp.phi) - M_HALFPI) < EPS10) { - if ((lp.phi * Q->n) <= 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - rho = 0.; - } else { - rho = Q->c * (P->es != 0. ? - pow(pj_tsfn(lp.phi, sin(lp.phi), P->e), Q->n) : - pow(tan(M_FORTPI + .5 * lp.phi), -Q->n)); - } - lp.lam *= Q->n; - xy.x = P->k0 * (rho * sin(lp.lam)); - xy.y = P->k0 * (Q->rho0 - rho * cos(lp.lam)); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0., 0.}; - struct pj_opaque *Q = static_cast(P->opaque); - double rho; - - xy.x /= P->k0; - xy.y /= P->k0; - - xy.y = Q->rho0 - xy.y; - rho = hypot(xy.x, xy.y); - if (rho != 0.) { - if (Q->n < 0.) { - rho = -rho; - xy.x = -xy.x; - xy.y = -xy.y; - } - if (P->es != 0.) { - lp.phi = pj_phi2(P->ctx, pow(rho / Q->c, 1./Q->n), P->e); - if (lp.phi == HUGE_VAL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - - } else - lp.phi = 2. * atan(pow(Q->c / rho, 1./Q->n)) - M_HALFPI; - lp.lam = atan2(xy.x, xy.y) / Q->n; - } else { - lp.lam = 0.; - lp.phi = Q->n > 0. ? M_HALFPI : -M_HALFPI; - } - return lp; -} - - -PJ *PROJECTION(lcc) { - double cosphi, sinphi; - int secant; - struct pj_opaque *Q = static_cast(pj_calloc(1, sizeof (struct pj_opaque))); - - if (nullptr == Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; - if (pj_param(P->ctx, P->params, "tlat_2").i) - Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; - else { - Q->phi2 = Q->phi1; - if (!pj_param(P->ctx, P->params, "tlat_0").i) - P->phi0 = Q->phi1; - } - if (fabs(Q->phi1 + Q->phi2) < EPS10) - return pj_default_destructor(P, PJD_ERR_CONIC_LAT_EQUAL); - - Q->n = sinphi = sin(Q->phi1); - cosphi = cos(Q->phi1); - secant = fabs(Q->phi1 - Q->phi2) >= EPS10; - if (P->es != 0.) { - double ml1, m1; - - m1 = pj_msfn(sinphi, cosphi, P->es); - ml1 = pj_tsfn(Q->phi1, sinphi, P->e); - if (secant) { /* secant cone */ - sinphi = sin(Q->phi2); - Q->n = log(m1 / pj_msfn(sinphi, cos(Q->phi2), P->es)); - Q->n /= log(ml1 / pj_tsfn(Q->phi2, sinphi, P->e)); - } - Q->c = (Q->rho0 = m1 * pow(ml1, -Q->n) / Q->n); - Q->rho0 *= (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) ? 0. : - pow(pj_tsfn(P->phi0, sin(P->phi0), P->e), Q->n); - } else { - if (secant) - Q->n = log(cosphi / cos(Q->phi2)) / - log(tan(M_FORTPI + .5 * Q->phi2) / - tan(M_FORTPI + .5 * Q->phi1)); - Q->c = cosphi * pow(tan(M_FORTPI + .5 * Q->phi1), Q->n) / Q->n; - Q->rho0 = (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) ? 0. : - Q->c * pow(tan(M_FORTPI + .5 * P->phi0), -Q->n); - } - - P->inv = e_inverse; - P->fwd = e_forward; - - return P; -} diff --git a/src/projections/PJ_lcca.cpp b/src/projections/PJ_lcca.cpp deleted file mode 100644 index 70b5dff9..00000000 --- a/src/projections/PJ_lcca.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/***************************************************************************** - - Lambert Conformal Conic Alternative - ----------------------------------- - - This is Gerald Evenden's 2003 implementation of an alternative - "almost" LCC, which has been in use historically, but which - should NOT be used for new projects - i.e: use this implementation - if you need interoperability with old data represented in this - projection, but not in any other case. - - The code was originally discussed on the PROJ.4 mailing list in - a thread archived over at - - http://lists.maptools.org/pipermail/proj/2003-March/000644.html - - It was discussed again in the thread starting at - - http://lists.maptools.org/pipermail/proj/2017-October/007828.html - and continuing at - http://lists.maptools.org/pipermail/proj/2017-November/007831.html - - which prompted Clifford J. Mugnier to add these clarifying notes: - - The French Army Truncated Cubic Lambert (partially conformal) Conic - projection is the Legal system for the projection in France between - the late 1800s and 1948 when the French Legislature changed the law - to recognize the fully conformal version. - - It was (might still be in one or two North African prior French - Colonies) used in North Africa in Algeria, Tunisia, & Morocco, as - well as in Syria during the Levant. - - Last time I have seen it used was about 30+ years ago in - Algeria when it was used to define Lease Block boundaries for - Petroleum Exploration & Production. - - (signed) - - Clifford J. Mugnier, c.p., c.m.s. - Chief of Geodesy - LSU Center for GeoInformatics - Dept. of Civil Engineering - LOUISIANA STATE UNIVERSITY - -*****************************************************************************/ - -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(lcca, "Lambert Conformal Conic Alternative") - "\n\tConic, Sph&Ell\n\tlat_0="; - -#define MAX_ITER 10 -#define DEL_TOL 1e-12 - -namespace { // anonymous namespace -struct pj_opaque { - double *en; - double r0, l, M0; - double C; -}; -} // anonymous namespace - - -static double fS(double S, double C) { /* func to compute dr */ - - return S * ( 1. + S * S * C); -} - - -static double fSp(double S, double C) { /* deriv of fs */ - - return 1. + 3.* S * S * C; -} - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double S, r, dr; - - S = pj_mlfn(lp.phi, sin(lp.phi), cos(lp.phi), Q->en) - Q->M0; - dr = fS(S, Q->C); - r = Q->r0 - dr; - xy.x = P->k0 * (r * sin( lp.lam *= Q->l ) ); - xy.y = P->k0 * (Q->r0 - r * cos(lp.lam) ); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double theta, dr, S, dif; - int i; - - xy.x /= P->k0; - xy.y /= P->k0; - theta = atan2(xy.x , Q->r0 - xy.y); - dr = xy.y - xy.x * tan(0.5 * theta); - lp.lam = theta / Q->l; - S = dr; - for (i = MAX_ITER; i ; --i) { - S -= (dif = (fS(S, Q->C) - dr) / fSp(S, Q->C)); - if (fabs(dif) < DEL_TOL) break; - } - if (!i) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - lp.phi = pj_inv_mlfn(P->ctx, S + Q->M0, P->es, Q->en); - - return lp; -} - - -static PJ *destructor (PJ *P, int errlev) { - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - -PJ *PROJECTION(lcca) { - double s2p0, N0, R0, tan0; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - (Q->en = pj_enfn(P->es)); - if (!Q->en) - return pj_default_destructor (P, ENOMEM); - - if (P->phi0 == 0.) { - return destructor(P, PJD_ERR_LAT_0_IS_ZERO); - } - Q->l = sin(P->phi0); - Q->M0 = pj_mlfn(P->phi0, Q->l, cos(P->phi0), Q->en); - s2p0 = Q->l * Q->l; - R0 = 1. / (1. - P->es * s2p0); - N0 = sqrt(R0); - R0 *= P->one_es * N0; - tan0 = tan(P->phi0); - Q->r0 = N0 / tan0; - Q->C = 1. / (6. * R0 * N0); - - P->inv = e_inverse; - P->fwd = e_forward; - P->destructor = destructor; - - return P; -} diff --git a/src/projections/PJ_loxim.cpp b/src/projections/PJ_loxim.cpp deleted file mode 100644 index f68e844a..00000000 --- a/src/projections/PJ_loxim.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(loxim, "Loximuthal") "\n\tPCyl Sph"; - -#define EPS 1e-8 - -namespace { // anonymous namespace -struct pj_opaque { - double phi1; - double cosphi1; - double tanphi1; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - xy.y = lp.phi - Q->phi1; - if (fabs(xy.y) < EPS) - xy.x = lp.lam * Q->cosphi1; - else { - xy.x = M_FORTPI + 0.5 * lp.phi; - if (fabs(xy.x) < EPS || fabs(fabs(xy.x) - M_HALFPI) < EPS) - xy.x = 0.; - else - xy.x = lp.lam * xy.y / log( tan(xy.x) / Q->tanphi1 ); - } - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - lp.phi = xy.y + Q->phi1; - if (fabs(xy.y) < EPS) { - lp.lam = xy.x / Q->cosphi1; - } else { - lp.lam = M_FORTPI + 0.5 * lp.phi; - if (fabs(lp.lam) < EPS || fabs(fabs(lp.lam) - M_HALFPI) < EPS) - lp.lam = 0.; - else - lp.lam = xy.x * log( tan(lp.lam) / Q->tanphi1 ) / xy.y ; - } - return lp; -} - - -PJ *PROJECTION(loxim) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; - Q->cosphi1 = cos(Q->phi1); - if (Q->cosphi1 < EPS) - return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); - - - Q->tanphi1 = tan(M_FORTPI + 0.5 * Q->phi1); - - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - - return P; -} diff --git a/src/projections/PJ_lsat.cpp b/src/projections/PJ_lsat.cpp deleted file mode 100644 index a0eca1bd..00000000 --- a/src/projections/PJ_lsat.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* based upon Snyder and Linck, USGS-NMD */ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(lsat, "Space oblique for LANDSAT") - "\n\tCyl, Sph&Ell\n\tlsat= path="; - -#define TOL 1e-7 - -namespace { // anonymous namespace -struct pj_opaque { - double a2, a4, b, c1, c3; - double q, t, u, w, p22, sa, ca, xj, rlm, rlm2; -}; -} // anonymous namespace - -static void seraz0(double lam, double mult, PJ *P) { - struct pj_opaque *Q = static_cast(P->opaque); - double sdsq, h, s, fc, sd, sq, d__1 = 0; - - lam *= DEG_TO_RAD; - sd = sin(lam); - sdsq = sd * sd; - s = Q->p22 * Q->sa * cos(lam) * sqrt((1. + Q->t * sdsq) - / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); - - d__1 = 1. + Q->q * sdsq; - h = sqrt((1. + Q->q * sdsq) / (1. + Q->w * sdsq)) * ((1. + Q->w * sdsq) - / (d__1 * d__1) - Q->p22 * Q->ca); - - sq = sqrt(Q->xj * Q->xj + s * s); - fc = mult * (h * Q->xj - s * s) / sq; - Q->b += fc; - Q->a2 += fc * cos(lam + lam); - Q->a4 += fc * cos(lam * 4.); - fc = mult * s * (h + Q->xj) / sq; - Q->c1 += fc * cos(lam); - Q->c3 += fc * cos(lam * 3.); -} - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - int l, nn; - double lamt = 0.0, xlam, sdsq, c, d, s, lamdp = 0.0, phidp, lampp, tanph; - double lamtp, cl, sd, sp, sav, tanphi; - - if (lp.phi > M_HALFPI) - lp.phi = M_HALFPI; - else if (lp.phi < -M_HALFPI) - lp.phi = -M_HALFPI; - - if (lp.phi >= 0. ) - lampp = M_HALFPI; - else - lampp = M_PI_HALFPI; - tanphi = tan(lp.phi); - for (nn = 0;;) { - double fac; - sav = lampp; - lamtp = lp.lam + Q->p22 * lampp; - cl = cos(lamtp); - if( cl < 0 ) - fac = lampp + sin(lampp) * M_HALFPI; - else - fac = lampp - sin(lampp) * M_HALFPI; - for (l = 50; l >= 0; --l) { - lamt = lp.lam + Q->p22 * sav; - c = cos(lamt); - if (fabs(c) < TOL) - lamt -= TOL; - xlam = (P->one_es * tanphi * Q->sa + sin(lamt) * Q->ca) / c; - lamdp = atan(xlam) + fac; - if (fabs(fabs(sav) - fabs(lamdp)) < TOL) - break; - sav = lamdp; - } - if (!l || ++nn >= 3 || (lamdp > Q->rlm && lamdp < Q->rlm2)) - break; - if (lamdp <= Q->rlm) - lampp = M_TWOPI_HALFPI; - else if (lamdp >= Q->rlm2) - lampp = M_HALFPI; - } - if (l) { - sp = sin(lp.phi); - phidp = aasin(P->ctx,(P->one_es * Q->ca * sp - Q->sa * cos(lp.phi) * - sin(lamt)) / sqrt(1. - P->es * sp * sp)); - tanph = log(tan(M_FORTPI + .5 * phidp)); - sd = sin(lamdp); - sdsq = sd * sd; - s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq) - / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); - d = sqrt(Q->xj * Q->xj + s * s); - xy.x = Q->b * lamdp + Q->a2 * sin(2. * lamdp) + Q->a4 * - sin(lamdp * 4.) - tanph * s / d; - xy.y = Q->c1 * sd + Q->c3 * sin(lamdp * 3.) + tanph * Q->xj / d; - } else - xy.x = xy.y = HUGE_VAL; - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - int nn; - double lamt, sdsq, s, lamdp, phidp, sppsq, dd, sd, sl, fac, scl, sav, spp; - - lamdp = xy.x / Q->b; - nn = 50; - do { - sav = lamdp; - sd = sin(lamdp); - sdsq = sd * sd; - s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq) - / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); - lamdp = xy.x + xy.y * s / Q->xj - Q->a2 * sin( - 2. * lamdp) - Q->a4 * sin(lamdp * 4.) - s / Q->xj * ( - Q->c1 * sin(lamdp) + Q->c3 * sin(lamdp * 3.)); - lamdp /= Q->b; - } while (fabs(lamdp - sav) >= TOL && --nn); - sl = sin(lamdp); - fac = exp(sqrt(1. + s * s / Q->xj / Q->xj) * (xy.y - - Q->c1 * sl - Q->c3 * sin(lamdp * 3.))); - phidp = 2. * (atan(fac) - M_FORTPI); - dd = sl * sl; - if (fabs(cos(lamdp)) < TOL) - lamdp -= TOL; - spp = sin(phidp); - sppsq = spp * spp; - lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) * - Q->ca - spp * Q->sa * sqrt((1. + Q->q * dd) * ( - 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / (1. - sppsq - * (1. + Q->u))); - sl = lamt >= 0. ? 1. : -1.; - scl = cos(lamdp) >= 0. ? 1. : -1; - lamt -= M_HALFPI * (1. - scl) * sl; - lp.lam = lamt - Q->p22 * lamdp; - if (fabs(Q->sa) < TOL) - lp.phi = aasin(P->ctx,spp / sqrt(P->one_es * P->one_es + P->es * sppsq)); - else - lp.phi = atan((tan(lamdp) * cos(lamt) - Q->ca * sin(lamt)) / - (P->one_es * Q->sa)); - return lp; -} - - -PJ *PROJECTION(lsat) { - int land, path; - double lam, alf, esc, ess; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - land = pj_param(P->ctx, P->params, "ilsat").i; - if (land <= 0 || land > 5) - return pj_default_destructor(P, PJD_ERR_LSAT_NOT_IN_RANGE); - - path = pj_param(P->ctx, P->params, "ipath").i; - if (path <= 0 || path > (land <= 3 ? 251 : 233)) - return pj_default_destructor(P, PJD_ERR_PATH_NOT_IN_RANGE); - - if (land <= 3) { - P->lam0 = DEG_TO_RAD * 128.87 - M_TWOPI / 251. * path; - Q->p22 = 103.2669323; - alf = DEG_TO_RAD * 99.092; - } else { - P->lam0 = DEG_TO_RAD * 129.3 - M_TWOPI / 233. * path; - Q->p22 = 98.8841202; - alf = DEG_TO_RAD * 98.2; - } - Q->p22 /= 1440.; - Q->sa = sin(alf); - Q->ca = cos(alf); - if (fabs(Q->ca) < 1e-9) - Q->ca = 1e-9; - esc = P->es * Q->ca * Q->ca; - ess = P->es * Q->sa * Q->sa; - Q->w = (1. - esc) * P->rone_es; - Q->w = Q->w * Q->w - 1.; - Q->q = ess * P->rone_es; - Q->t = ess * (2. - P->es) * P->rone_es * P->rone_es; - Q->u = esc * P->rone_es; - Q->xj = P->one_es * P->one_es * P->one_es; - Q->rlm = M_PI * (1. / 248. + .5161290322580645); - Q->rlm2 = Q->rlm + M_TWOPI; - Q->a2 = Q->a4 = Q->b = Q->c1 = Q->c3 = 0.; - seraz0(0., 1., P); - for (lam = 9.; lam <= 81.0001; lam += 18.) - seraz0(lam, 4., P); - for (lam = 18; lam <= 72.0001; lam += 18.) - seraz0(lam, 2., P); - seraz0(90., 1., P); - Q->a2 /= 30.; - Q->a4 /= 60.; - Q->b /= 30.; - Q->c1 /= 15.; - Q->c3 /= 45.; - - P->inv = e_inverse; - P->fwd = e_forward; - - return P; -} diff --git a/src/projections/PJ_mbt_fps.cpp b/src/projections/PJ_mbt_fps.cpp deleted file mode 100644 index 66ed9458..00000000 --- a/src/projections/PJ_mbt_fps.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(mbt_fps, "McBryde-Thomas Flat-Pole Sine (No. 2)") "\n\tCyl, Sph"; - -#define MAX_ITER 10 -#define LOOP_TOL 1e-7 -#define C1 0.45503 -#define C2 1.36509 -#define C3 1.41546 -#define C_x 0.22248 -#define C_y 1.44492 -#define C1_2 0.33333333333333333333333333 - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double k, V, t; - int i; - (void) P; - - k = C3 * sin(lp.phi); - for (i = MAX_ITER; i ; --i) { - t = lp.phi / C2; - lp.phi -= V = (C1 * sin(t) + sin(lp.phi) - k) / - (C1_2 * cos(t) + cos(lp.phi)); - if (fabs(V) < LOOP_TOL) - break; - } - t = lp.phi / C2; - xy.x = C_x * lp.lam * (1. + 3. * cos(lp.phi)/cos(t) ); - xy.y = C_y * sin(t); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double t; - - lp.phi = C2 * (t = aasin(P->ctx,xy.y / C_y)); - lp.lam = xy.x / (C_x * (1. + 3. * cos(lp.phi)/cos(t))); - lp.phi = aasin(P->ctx,(C1 * sin(t) + sin(lp.phi)) / C3); - return (lp); -} - - -PJ *PROJECTION(mbt_fps) { - - P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_mbtfpp.cpp b/src/projections/PJ_mbtfpp.cpp deleted file mode 100644 index 276a43eb..00000000 --- a/src/projections/PJ_mbtfpp.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(mbtfpp, "McBride-Thomas Flat-Polar Parabolic") "\n\tCyl, Sph"; - -#define CS .95257934441568037152 -#define FXC .92582009977255146156 -#define FYC 3.40168025708304504493 -#define C23 .66666666666666666666 -#define C13 .33333333333333333333 -#define ONEEPS 1.0000001 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - lp.phi = asin(CS * sin(lp.phi)); - xy.x = FXC * lp.lam * (2. * cos(C23 * lp.phi) - 1.); - xy.y = FYC * sin(C13 * lp.phi); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - - lp.phi = xy.y / FYC; - if (fabs(lp.phi) >= 1.) { - if (fabs(lp.phi) > ONEEPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } else { - lp.phi = (lp.phi < 0.) ? -M_HALFPI : M_HALFPI; - } - } else - lp.phi = asin(lp.phi); - - lp.lam = xy.x / ( FXC * (2. * cos(C23 * (lp.phi *= 3.)) - 1.) ); - if (fabs(lp.phi = sin(lp.phi) / CS) >= 1.) { - if (fabs(lp.phi) > ONEEPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } else { - lp.phi = (lp.phi < 0.) ? -M_HALFPI : M_HALFPI; - } - } else - lp.phi = asin(lp.phi); - - return lp; -} - - -PJ *PROJECTION(mbtfpp) { - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_mbtfpq.cpp b/src/projections/PJ_mbtfpq.cpp deleted file mode 100644 index b7c0eb16..00000000 --- a/src/projections/PJ_mbtfpq.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(mbtfpq, "McBryde-Thomas Flat-Polar Quartic") "\n\tCyl, Sph"; - -#define NITER 20 -#define EPS 1e-7 -#define ONETOL 1.000001 -#define C 1.70710678118654752440 -#define RC 0.58578643762690495119 -#define FYC 1.87475828462269495505 -#define RYC 0.53340209679417701685 -#define FXC 0.31245971410378249250 -#define RXC 3.20041258076506210122 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double th1, c; - int i; - (void) P; - - c = C * sin(lp.phi); - for (i = NITER; i; --i) { - lp.phi -= th1 = (sin(.5*lp.phi) + sin(lp.phi) - c) / - (.5*cos(.5*lp.phi) + cos(lp.phi)); - if (fabs(th1) < EPS) break; - } - xy.x = FXC * lp.lam * (1.0 + 2. * cos(lp.phi)/cos(0.5 * lp.phi)); - xy.y = FYC * sin(0.5 * lp.phi); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double t; - - lp.phi = RYC * xy.y; - if (fabs(lp.phi) > 1.) { - if (fabs(lp.phi) > ONETOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - else if (lp.phi < 0.) { t = -1.; lp.phi = -M_PI; } - else { t = 1.; lp.phi = M_PI; } - } else - lp.phi = 2. * asin(t = lp.phi); - lp.lam = RXC * xy.x / (1. + 2. * cos(lp.phi)/cos(0.5 * lp.phi)); - lp.phi = RC * (t + sin(lp.phi)); - if (fabs(lp.phi) > 1.) - if (fabs(lp.phi) > ONETOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - else lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; - else - lp.phi = asin(lp.phi); - return lp; -} - - -PJ *PROJECTION(mbtfpq) { - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_merc.cpp b/src/projections/PJ_merc.cpp deleted file mode 100644 index 1998234e..00000000 --- a/src/projections/PJ_merc.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj_internal.h" -#include "proj.h" -#include "proj_math.h" -#include "projects.h" - -PROJ_HEAD(merc, "Mercator") "\n\tCyl, Sph&Ell\n\tlat_ts="; -PROJ_HEAD(webmerc, "Web Mercator / Pseudo Mercator") "\n\tCyl, Ell\n\t"; - -#define EPS10 1.e-10 -static double logtanpfpim1(double x) { /* log(tan(x/2 + M_FORTPI)) */ - if (fabs(x) <= DBL_EPSILON) { - /* tan(M_FORTPI + .5 * x) can be approximated by 1.0 + x */ - return log1p(x); - } - return log(tan(M_FORTPI + .5 * x)); -} - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.x = P->k0 * lp.lam; - xy.y = - P->k0 * log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; -} - xy.x = P->k0 * lp.lam; - xy.y = P->k0 * logtanpfpim1(lp.phi); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - if ((lp.phi = pj_phi2(P->ctx, exp(- xy.y / P->k0), P->e)) == HUGE_VAL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; -} - lp.lam = xy.x / P->k0; - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - lp.phi = atan(sinh(xy.y / P->k0)); - lp.lam = xy.x / P->k0; - return lp; -} - - -PJ *PROJECTION(merc) { - double phits=0.0; - int is_phits; - - if( (is_phits = pj_param(P->ctx, P->params, "tlat_ts").i) ) { - phits = fabs(pj_param(P->ctx, P->params, "rlat_ts").f); - if (phits >= M_HALFPI) - return pj_default_destructor(P, PJD_ERR_LAT_TS_LARGER_THAN_90); - } - - if (P->es != 0.0) { /* ellipsoid */ - if (is_phits) - P->k0 = pj_msfn(sin(phits), cos(phits), P->es); - P->inv = e_inverse; - P->fwd = e_forward; - } - - else { /* sphere */ - if (is_phits) - P->k0 = cos(phits); - P->inv = s_inverse; - P->fwd = s_forward; - } - - return P; -} - -PJ *PROJECTION(webmerc) { - - /* Overriding k_0 with fixed parameter */ - P->k0 = 1.0; - - P->inv = s_inverse; - P->fwd = s_forward; - return P; -} diff --git a/src/projections/PJ_mill.cpp b/src/projections/PJ_mill.cpp deleted file mode 100644 index 3ea9636f..00000000 --- a/src/projections/PJ_mill.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(mill, "Miller Cylindrical") "\n\tCyl, Sph"; - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - xy.x = lp.lam; - xy.y = log(tan(M_FORTPI + lp.phi * .4)) * 1.25; - - return (xy); -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - (void) P; - - lp.lam = xy.x; - lp.phi = 2.5 * (atan(exp(.8 * xy.y)) - M_FORTPI); - - return (lp); -} - - -PJ *PROJECTION(mill) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_misrsom.cpp b/src/projections/PJ_misrsom.cpp deleted file mode 100644 index c84b96e3..00000000 --- a/src/projections/PJ_misrsom.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/****************************************************************************** - * This implements Space Oblique Mercator (SOM) projection, used by the - * Multi-angle Imaging SpectroRadiometer (MISR) products, from the NASA EOS Terra - * platform. - * - * The code is identical to that of Landsat SOM (PJ_lsat.c) with the following - * parameter changes: - * - * inclination angle = 98.30382 degrees - * period of revolution = 98.88 minutes - * ascending longitude = 129.3056 degrees - (360 / 233) * path_number - * - * and the following code change: - * - * Q->rlm = PI * (1. / 248. + .5161290322580645); - * - * changed to: - * - * Q->rlm = 0 - * - *****************************************************************************/ -/* based upon Snyder and Linck, USGS-NMD */ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(misrsom, "Space oblique for MISR") - "\n\tCyl, Sph&Ell\n\tpath="; - -#define TOL 1e-7 - -namespace { // anonymous namespace -struct pj_opaque { - double a2, a4, b, c1, c3; - double q, t, u, w, p22, sa, ca, xj, rlm, rlm2; -}; -} // anonymous namespace - -static void seraz0(double lam, double mult, PJ *P) { - struct pj_opaque *Q = static_cast(P->opaque); - double sdsq, h, s, fc, sd, sq, d__1; - - lam *= DEG_TO_RAD; - sd = sin(lam); - sdsq = sd * sd; - s = Q->p22 * Q->sa * cos(lam) * sqrt((1. + Q->t * sdsq) / (( - 1. + Q->w * sdsq) * (1. + Q->q * sdsq))); - d__1 = 1. + Q->q * sdsq; - h = sqrt((1. + Q->q * sdsq) / (1. + Q->w * sdsq)) * ((1. + - Q->w * sdsq) / (d__1 * d__1) - Q->p22 * Q->ca); - sq = sqrt(Q->xj * Q->xj + s * s); - Q->b += fc = mult * (h * Q->xj - s * s) / sq; - Q->a2 += fc * cos(lam + lam); - Q->a4 += fc * cos(lam * 4.); - fc = mult * s * (h + Q->xj) / sq; - Q->c1 += fc * cos(lam); - Q->c3 += fc * cos(lam * 3.); -} - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - int l, nn; - double lamt = 0.0, xlam, sdsq, c, d, s, lamdp = 0.0, phidp, lampp, tanph; - double lamtp, cl, sd, sp, sav, tanphi; - - if (lp.phi > M_HALFPI) - lp.phi = M_HALFPI; - else if (lp.phi < -M_HALFPI) - lp.phi = -M_HALFPI; - if (lp.phi >= 0. ) - lampp = M_HALFPI; - else - lampp = M_PI_HALFPI; - tanphi = tan(lp.phi); - for (nn = 0;;) { - double fac; - sav = lampp; - lamtp = lp.lam + Q->p22 * lampp; - cl = cos(lamtp); - if( cl < 0 ) - fac = lampp + sin(lampp) * M_HALFPI; - else - fac = lampp - sin(lampp) * M_HALFPI; - for (l = 50; l; --l) { - lamt = lp.lam + Q->p22 * sav; - if (fabs(c = cos(lamt)) < TOL) - lamt -= TOL; - xlam = (P->one_es * tanphi * Q->sa + sin(lamt) * Q->ca) / c; - lamdp = atan(xlam) + fac; - if (fabs(fabs(sav) - fabs(lamdp)) < TOL) - break; - sav = lamdp; - } - if (!l || ++nn >= 3 || (lamdp > Q->rlm && lamdp < Q->rlm2)) - break; - if (lamdp <= Q->rlm) - lampp = M_TWOPI_HALFPI; - else if (lamdp >= Q->rlm2) - lampp = M_HALFPI; - } - if (l) { - sp = sin(lp.phi); - phidp = aasin(P->ctx,(P->one_es * Q->ca * sp - Q->sa * cos(lp.phi) * - sin(lamt)) / sqrt(1. - P->es * sp * sp)); - tanph = log(tan(M_FORTPI + .5 * phidp)); - sd = sin(lamdp); - sdsq = sd * sd; - s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq) - / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); - d = sqrt(Q->xj * Q->xj + s * s); - xy.x = Q->b * lamdp + Q->a2 * sin(2. * lamdp) + Q->a4 * - sin(lamdp * 4.) - tanph * s / d; - xy.y = Q->c1 * sd + Q->c3 * sin(lamdp * 3.) + tanph * Q->xj / d; - } else - xy.x = xy.y = HUGE_VAL; - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - int nn; - double lamt, sdsq, s, lamdp, phidp, sppsq, dd, sd, sl, fac, scl, sav, spp; - - lamdp = xy.x / Q->b; - nn = 50; - do { - sav = lamdp; - sd = sin(lamdp); - sdsq = sd * sd; - s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq) - / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); - lamdp = xy.x + xy.y * s / Q->xj - Q->a2 * sin( - 2. * lamdp) - Q->a4 * sin(lamdp * 4.) - s / Q->xj * ( - Q->c1 * sin(lamdp) + Q->c3 * sin(lamdp * 3.)); - lamdp /= Q->b; - } while (fabs(lamdp - sav) >= TOL && --nn); - sl = sin(lamdp); - fac = exp(sqrt(1. + s * s / Q->xj / Q->xj) * (xy.y - - Q->c1 * sl - Q->c3 * sin(lamdp * 3.))); - phidp = 2. * (atan(fac) - M_FORTPI); - dd = sl * sl; - if (fabs(cos(lamdp)) < TOL) - lamdp -= TOL; - spp = sin(phidp); - sppsq = spp * spp; - lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) * - Q->ca - spp * Q->sa * sqrt((1. + Q->q * dd) * ( - 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / (1. - sppsq - * (1. + Q->u))); - sl = lamt >= 0. ? 1. : -1.; - scl = cos(lamdp) >= 0. ? 1. : -1; - lamt -= M_HALFPI * (1. - scl) * sl; - lp.lam = lamt - Q->p22 * lamdp; - if (fabs(Q->sa) < TOL) - lp.phi = aasin(P->ctx,spp / sqrt(P->one_es * P->one_es + P->es * sppsq)); - else - lp.phi = atan((tan(lamdp) * cos(lamt) - Q->ca * sin(lamt)) / - (P->one_es * Q->sa)); - return lp; -} - - -PJ *PROJECTION(misrsom) { - int path; - double lam, alf, esc, ess; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - path = pj_param(P->ctx, P->params, "ipath").i; - if (path <= 0 || path > 233) - return pj_default_destructor(P, PJD_ERR_PATH_NOT_IN_RANGE); - - P->lam0 = DEG_TO_RAD * 129.3056 - M_TWOPI / 233. * path; - alf = 98.30382 * DEG_TO_RAD; - Q->p22 = 98.88 / 1440.0; - - Q->sa = sin(alf); - Q->ca = cos(alf); - if (fabs(Q->ca) < 1e-9) - Q->ca = 1e-9; - esc = P->es * Q->ca * Q->ca; - ess = P->es * Q->sa * Q->sa; - Q->w = (1. - esc) * P->rone_es; - Q->w = Q->w * Q->w - 1.; - Q->q = ess * P->rone_es; - Q->t = ess * (2. - P->es) * P->rone_es * P->rone_es; - Q->u = esc * P->rone_es; - Q->xj = P->one_es * P->one_es * P->one_es; - Q->rlm = 0; - Q->rlm2 = Q->rlm + M_TWOPI; - Q->a2 = Q->a4 = Q->b = Q->c1 = Q->c3 = 0.; - seraz0(0., 1., P); - for (lam = 9.; lam <= 81.0001; lam += 18.) - seraz0(lam, 4., P); - for (lam = 18; lam <= 72.0001; lam += 18.) - seraz0(lam, 2., P); - seraz0(90., 1., P); - Q->a2 /= 30.; - Q->a4 /= 60.; - Q->b /= 30.; - Q->c1 /= 15.; - Q->c3 /= 45.; - - P->inv = e_inverse; - P->fwd = e_forward; - - return P; -} diff --git a/src/projections/PJ_mod_ster.cpp b/src/projections/PJ_mod_ster.cpp deleted file mode 100644 index 7c4f363b..00000000 --- a/src/projections/PJ_mod_ster.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* based upon Snyder and Linck, USGS-NMD */ -#define PJ_LIB__ -#include -#include "projects.h" -#include "proj_math.h" - -PROJ_HEAD(mil_os, "Miller Oblated Stereographic") "\n\tAzi(mod)"; -PROJ_HEAD(lee_os, "Lee Oblated Stereographic") "\n\tAzi(mod)"; -PROJ_HEAD(gs48, "Mod. Stereographic of 48 U.S.") "\n\tAzi(mod)"; -PROJ_HEAD(alsk, "Mod. Stereographic of Alaska") "\n\tAzi(mod)"; -PROJ_HEAD(gs50, "Mod. Stereographic of 50 U.S.") "\n\tAzi(mod)"; - -#define EPSLN 1e-12 - -namespace { // anonymous namespace -struct pj_opaque { - const COMPLEX *zcoeff; \ - double cchio, schio; \ - int n; -}; -} // anonymous namespace - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double sinlon, coslon, esphi, chi, schi, cchi, s; - COMPLEX p; - - sinlon = sin(lp.lam); - coslon = cos(lp.lam); - esphi = P->e * sin(lp.phi); - chi = 2. * atan(tan((M_HALFPI + lp.phi) * .5) * - pow((1. - esphi) / (1. + esphi), P->e * .5)) - M_HALFPI; - schi = sin(chi); - cchi = cos(chi); - s = 2. / (1. + Q->schio * schi + Q->cchio * cchi * coslon); - p.r = s * cchi * sinlon; - p.i = s * (Q->cchio * schi - Q->schio * cchi * coslon); - p = pj_zpoly1(p, Q->zcoeff, Q->n); - xy.x = p.r; - xy.y = p.i; - - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - int nn; - COMPLEX p, fxy, fpxy, dp; - double den, rh = 0.0, z, sinz = 0.0, cosz = 0.0, chi, phi = 0.0, esphi; - - p.r = xy.x; - p.i = xy.y; - for (nn = 20; nn ;--nn) { - fxy = pj_zpolyd1(p, Q->zcoeff, Q->n, &fpxy); - fxy.r -= xy.x; - fxy.i -= xy.y; - den = fpxy.r * fpxy.r + fpxy.i * fpxy.i; - dp.r = -(fxy.r * fpxy.r + fxy.i * fpxy.i) / den; - dp.i = -(fxy.i * fpxy.r - fxy.r * fpxy.i) / den; - p.r += dp.r; - p.i += dp.i; - if ((fabs(dp.r) + fabs(dp.i)) <= EPSLN) - break; - } - if (nn) { - rh = hypot(p.r, p.i); - z = 2. * atan(.5 * rh); - sinz = sin(z); - cosz = cos(z); - lp.lam = P->lam0; - if (fabs(rh) <= EPSLN) { - /* if we end up here input coordinates were (0,0). - * pj_inv() adds P->lam0 to lp.lam, this way we are - * sure to get the correct offset */ - lp.lam = 0.0; - lp.phi = P->phi0; - return lp; - } - chi = aasin(P->ctx, cosz * Q->schio + p.i * sinz * Q->cchio / rh); - phi = chi; - for (nn = 20; nn ;--nn) { - double dphi; - esphi = P->e * sin(phi); - dphi = 2. * atan(tan((M_HALFPI + chi) * .5) * - pow((1. + esphi) / (1. - esphi), P->e * .5)) - M_HALFPI - phi; - phi += dphi; - if (fabs(dphi) <= EPSLN) - break; - } - } - if (nn) { - lp.phi = phi; - lp.lam = atan2(p.r * sinz, rh * Q->cchio * cosz - p.i * - Q->schio * sinz); - } else - lp.lam = lp.phi = HUGE_VAL; - return lp; -} - - -static PJ *setup(PJ *P) { /* general initialization */ - struct pj_opaque *Q = static_cast(P->opaque); - double esphi, chio; - - if (P->es != 0.0) { - esphi = P->e * sin(P->phi0); - chio = 2. * atan(tan((M_HALFPI + P->phi0) * .5) * - pow((1. - esphi) / (1. + esphi), P->e * .5)) - M_HALFPI; - } else - chio = P->phi0; - Q->schio = sin(chio); - Q->cchio = cos(chio); - P->inv = e_inverse; - P->fwd = e_forward; - - return P; -} - - -/* Miller Oblated Stereographic */ -PJ *PROJECTION(mil_os) { - static const COMPLEX AB[] = { - {0.924500, 0.}, - {0., 0.}, - {0.019430, 0.} - }; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->n = 2; - P->lam0 = DEG_TO_RAD * 20.; - P->phi0 = DEG_TO_RAD * 18.; - Q->zcoeff = AB; - P->es = 0.; - - return setup(P); -} - - -/* Lee Oblated Stereographic */ -PJ *PROJECTION(lee_os) { - static const COMPLEX AB[] = { - {0.721316, 0.}, - {0., 0.}, - {-0.0088162, -0.00617325} - }; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->n = 2; - P->lam0 = DEG_TO_RAD * -165.; - P->phi0 = DEG_TO_RAD * -10.; - Q->zcoeff = AB; - P->es = 0.; - - return setup(P); -} - - -PJ *PROJECTION(gs48) { - static const COMPLEX /* 48 United States */ - AB[] = { - {0.98879, 0.}, - {0., 0.}, - {-0.050909, 0.}, - {0., 0.}, - {0.075528, 0.} - }; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->n = 4; - P->lam0 = DEG_TO_RAD * -96.; - P->phi0 = DEG_TO_RAD * 39.; - Q->zcoeff = AB; - P->es = 0.; - P->a = 6370997.; - - return setup(P); -} - - -PJ *PROJECTION(alsk) { - static const COMPLEX ABe[] = { /* Alaska ellipsoid */ - { .9945303, 0.}, - { .0052083, -.0027404}, - { .0072721, .0048181}, - {-.0151089, -.1932526}, - { .0642675, -.1381226}, - { .3582802, -.2884586}, - }; - - static const COMPLEX ABs[] = { /* Alaska sphere */ - { .9972523, 0.}, - { .0052513, -.0041175}, - { .0074606, .0048125}, - {-.0153783, -.1968253}, - { .0636871, -.1408027}, - { .3660976, -.2937382} - }; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->n = 5; - P->lam0 = DEG_TO_RAD * -152.; - P->phi0 = DEG_TO_RAD * 64.; - if (P->es != 0.0) { /* fixed ellipsoid/sphere */ - Q->zcoeff = ABe; - P->a = 6378206.4; - P->e = sqrt(P->es = 0.00676866); - } else { - Q->zcoeff = ABs; - P->a = 6370997.; - } - - return setup(P); -} - - -PJ *PROJECTION(gs50) { - static const COMPLEX ABe[] = { /* GS50 ellipsoid */ - { .9827497, 0.}, - { .0210669, .0053804}, - {-.1031415, -.0571664}, - {-.0323337, -.0322847}, - { .0502303, .1211983}, - { .0251805, .0895678}, - {-.0012315, -.1416121}, - { .0072202, -.1317091}, - {-.0194029, .0759677}, - {-.0210072, .0834037} - }; - - static const COMPLEX ABs[] = { /* GS50 sphere */ - { .9842990, 0.}, - { .0211642, .0037608}, - {-.1036018, -.0575102}, - {-.0329095, -.0320119}, - { .0499471, .1223335}, - { .0260460, .0899805}, - { .0007388, -.1435792}, - { .0075848, -.1334108}, - {-.0216473, .0776645}, - {-.0225161, .0853673} - }; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->n = 9; - P->lam0 = DEG_TO_RAD * -120.; - P->phi0 = DEG_TO_RAD * 45.; - if (P->es != 0.0) { /* fixed ellipsoid/sphere */ - Q->zcoeff = ABe; - P->a = 6378206.4; - P->e = sqrt(P->es = 0.00676866); - } else { - Q->zcoeff = ABs; - P->a = 6370997.; - } - - return setup(P); -} - diff --git a/src/projections/PJ_moll.cpp b/src/projections/PJ_moll.cpp deleted file mode 100644 index c877a1bb..00000000 --- a/src/projections/PJ_moll.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(moll, "Mollweide") "\n\tPCyl, Sph"; -PROJ_HEAD(wag4, "Wagner IV") "\n\tPCyl, Sph"; -PROJ_HEAD(wag5, "Wagner V") "\n\tPCyl, Sph"; - -#define MAX_ITER 10 -#define LOOP_TOL 1e-7 - -namespace { // anonymous namespace -struct pj_opaque { - double C_x, C_y, C_p; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double k, V; - int i; - - k = Q->C_p * sin(lp.phi); - for (i = MAX_ITER; i ; --i) { - lp.phi -= V = (lp.phi + sin(lp.phi) - k) / - (1. + cos(lp.phi)); - if (fabs(V) < LOOP_TOL) - break; - } - if (!i) - lp.phi = (lp.phi < 0.) ? -M_HALFPI : M_HALFPI; - else - lp.phi *= 0.5; - xy.x = Q->C_x * lp.lam * cos(lp.phi); - xy.y = Q->C_y * sin(lp.phi); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - lp.phi = aasin(P->ctx, xy.y / Q->C_y); - lp.lam = xy.x / (Q->C_x * cos(lp.phi)); - if (fabs(lp.lam) < M_PI) { - lp.phi += lp.phi; - lp.phi = aasin(P->ctx, (lp.phi + sin(lp.phi)) / Q->C_p); - } else { - lp.lam = lp.phi = HUGE_VAL; - } - return lp; -} - - -static PJ * setup(PJ *P, double p) { - struct pj_opaque *Q = static_cast(P->opaque); - double r, sp, p2 = p + p; - - P->es = 0; - sp = sin(p); - r = sqrt(M_TWOPI * sp / (p2 + sin(p2))); - - Q->C_x = 2. * r / M_PI; - Q->C_y = r / sp; - Q->C_p = p2 + sin(p2); - - P->inv = s_inverse; - P->fwd = s_forward; - return P; -} - - -PJ *PROJECTION(moll) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - return setup(P, M_HALFPI); -} - - -PJ *PROJECTION(wag4) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - return setup(P, M_PI/3.); -} - -PJ *PROJECTION(wag5) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - P->es = 0; - Q->C_x = 0.90977; - Q->C_y = 1.65014; - Q->C_p = 3.00896; - - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_natearth.cpp b/src/projections/PJ_natearth.cpp deleted file mode 100644 index 27a6b137..00000000 --- a/src/projections/PJ_natearth.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -The Natural Earth projection was designed by Tom Patterson, US National Park -Service, in 2007, using Flex Projector. The shape of the original projection -was defined at every 5 degrees and piece-wise cubic spline interpolation was -used to compute the complete graticule. -The code here uses polynomial functions instead of cubic splines and -is therefore much simpler to program. The polynomial approximation was -developed by Bojan Savric, in collaboration with Tom Patterson and Bernhard -Jenny, Institute of Cartography, ETH Zurich. It slightly deviates from -Patterson's original projection by adding additional curvature to meridians -where they meet the horizontal pole line. This improvement is by intention -and designed in collaboration with Tom Patterson. -Port to PROJ.4 by Bernhard Jenny, 6 June 2011 -*/ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(natearth, "Natural Earth") "\n\tPCyl, Sph"; - -#define A0 0.8707 -#define A1 -0.131979 -#define A2 -0.013791 -#define A3 0.003971 -#define A4 -0.001529 -#define B0 1.007226 -#define B1 0.015085 -#define B2 -0.044475 -#define B3 0.028874 -#define B4 -0.005916 -#define C0 B0 -#define C1 (3 * B1) -#define C2 (7 * B2) -#define C3 (9 * B3) -#define C4 (11 * B4) -#define EPS 1e-11 -#define MAX_Y (0.8707 * 0.52 * M_PI) -/* Not sure at all of the appropriate number for MAX_ITER... */ -#define MAX_ITER 100 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double phi2, phi4; - (void) P; - - phi2 = lp.phi * lp.phi; - phi4 = phi2 * phi2; - xy.x = lp.lam * (A0 + phi2 * (A1 + phi2 * (A2 + phi4 * phi2 * (A3 + phi2 * A4)))); - xy.y = lp.phi * (B0 + phi2 * (B1 + phi4 * (B2 + B3 * phi2 + B4 * phi4))); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double yc, tol, y2, y4, f, fder; - int i; - (void) P; - - /* make sure y is inside valid range */ - if (xy.y > MAX_Y) { - xy.y = MAX_Y; - } else if (xy.y < -MAX_Y) { - xy.y = -MAX_Y; - } - - /* latitude */ - yc = xy.y; - for (i = MAX_ITER; i ; --i) { /* Newton-Raphson */ - y2 = yc * yc; - y4 = y2 * y2; - f = (yc * (B0 + y2 * (B1 + y4 * (B2 + B3 * y2 + B4 * y4)))) - xy.y; - fder = C0 + y2 * (C1 + y4 * (C2 + C3 * y2 + C4 * y4)); - yc -= tol = f / fder; - if (fabs(tol) < EPS) { - break; - } - } - if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); - lp.phi = yc; - - /* longitude */ - y2 = yc * yc; - lp.lam = xy.x / (A0 + y2 * (A1 + y2 * (A2 + y2 * y2 * y2 * (A3 + y2 * A4)))); - - return lp; -} - - -PJ *PROJECTION(natearth) { - P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_natearth2.cpp b/src/projections/PJ_natearth2.cpp deleted file mode 100644 index f6aba671..00000000 --- a/src/projections/PJ_natearth2.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* -The Natural Earth II projection was designed by Tom Patterson, US National -Park Service, in 2012, using Flex Projector. The polynomial equation was -developed by Bojan Savric and Bernhard Jenny, College of Earth, Ocean, -and Atmospheric Sciences, Oregon State University. -Port to PROJ.4 by Bojan Savric, 4 April 2016 -*/ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(natearth2, "Natural Earth 2") "\n\tPCyl, Sph"; - -#define A0 0.84719 -#define A1 -0.13063 -#define A2 -0.04515 -#define A3 0.05494 -#define A4 -0.02326 -#define A5 0.00331 -#define B0 1.01183 -#define B1 -0.02625 -#define B2 0.01926 -#define B3 -0.00396 -#define C0 B0 -#define C1 (9 * B1) -#define C2 (11 * B2) -#define C3 (13 * B3) -#define EPS 1e-11 -#define MAX_Y (0.84719 * 0.535117535153096 * M_PI) -/* Not sure at all of the appropriate number for MAX_ITER... */ -#define MAX_ITER 100 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double phi2, phi4, phi6; - (void) P; - - phi2 = lp.phi * lp.phi; - phi4 = phi2 * phi2; - phi6 = phi2 * phi4; - - xy.x = lp.lam * (A0 + A1 * phi2 + phi6 * phi6 * (A2 + A3 * phi2 + A4 * phi4 + A5 * phi6)); - xy.y = lp.phi * (B0 + phi4 * phi4 * (B1 + B2 * phi2 + B3 * phi4)); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double yc, tol, y2, y4, y6, f, fder; - int i; - (void) P; - - /* make sure y is inside valid range */ - if (xy.y > MAX_Y) { - xy.y = MAX_Y; - } else if (xy.y < -MAX_Y) { - xy.y = -MAX_Y; - } - - /* latitude */ - yc = xy.y; - for (i = MAX_ITER; i ; --i) { /* Newton-Raphson */ - y2 = yc * yc; - y4 = y2 * y2; - f = (yc * (B0 + y4 * y4 * (B1 + B2 * y2 + B3 * y4))) - xy.y; - fder = C0 + y4 * y4 * (C1 + C2 * y2 + C3 * y4); - yc -= tol = f / fder; - if (fabs(tol) < EPS) { - break; - } - } - if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); - lp.phi = yc; - - /* longitude */ - y2 = yc * yc; - y4 = y2 * y2; - y6 = y2 * y4; - - lp.lam = xy.x / (A0 + A1 * y2 + y6 * y6 * (A2 + A3 * y2 + A4 * y4 + A5 * y6)); - - return lp; -} - - -PJ *PROJECTION(natearth2) { - P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_nell.cpp b/src/projections/PJ_nell.cpp deleted file mode 100644 index 2a7ea32c..00000000 --- a/src/projections/PJ_nell.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(nell, "Nell") "\n\tPCyl, Sph"; - -#define MAX_ITER 10 -#define LOOP_TOL 1e-7 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double k, V; - int i; - (void) P; - - k = 2. * sin(lp.phi); - V = lp.phi * lp.phi; - lp.phi *= 1.00371 + V * (-0.0935382 + V * -0.011412); - for (i = MAX_ITER; i ; --i) { - lp.phi -= V = (lp.phi + sin(lp.phi) - k) / - (1. + cos(lp.phi)); - if (fabs(V) < LOOP_TOL) - break; - } - xy.x = 0.5 * lp.lam * (1. + cos(lp.phi)); - xy.y = lp.phi; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - lp.lam = 2. * xy.x / (1. + cos(xy.y)); - lp.phi = aasin(P->ctx,0.5 * (xy.y + sin(xy.y))); - - return lp; -} - - -PJ *PROJECTION(nell) { - - P->es = 0; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_nell_h.cpp b/src/projections/PJ_nell_h.cpp deleted file mode 100644 index 28c3ace7..00000000 --- a/src/projections/PJ_nell_h.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(nell_h, "Nell-Hammer") "\n\tPCyl, Sph"; - -#define NITER 9 -#define EPS 1e-7 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - xy.x = 0.5 * lp.lam * (1. + cos(lp.phi)); - xy.y = 2.0 * (lp.phi - tan(0.5 *lp.phi)); - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double V, c, p; - int i; - (void) P; - - p = 0.5 * xy.y; - for (i = NITER; i ; --i) { - c = cos(0.5 * lp.phi); - lp.phi -= V = (lp.phi - tan(lp.phi/2) - p)/(1. - 0.5/(c*c)); - if (fabs(V) < EPS) - break; - } - if (!i) { - lp.phi = p < 0. ? -M_HALFPI : M_HALFPI; - lp.lam = 2. * xy.x; - } else - lp.lam = 2. * xy.x / (1. + cos(lp.phi)); - - return lp; -} - - -PJ *PROJECTION(nell_h) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_nocol.cpp b/src/projections/PJ_nocol.cpp deleted file mode 100644 index 541d08b2..00000000 --- a/src/projections/PJ_nocol.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(nicol, "Nicolosi Globular") "\n\tMisc Sph, no inv"; - -#define EPS 1e-10 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - (void) P; - - if (fabs(lp.lam) < EPS) { - xy.x = 0; - xy.y = lp.phi; - } else if (fabs(lp.phi) < EPS) { - xy.x = lp.lam; - xy.y = 0.; - } else if (fabs(fabs(lp.lam) - M_HALFPI) < EPS) { - xy.x = lp.lam * cos(lp.phi); - xy.y = M_HALFPI * sin(lp.phi); - } else if (fabs(fabs(lp.phi) - M_HALFPI) < EPS) { - xy.x = 0; - xy.y = lp.phi; - } else { - double tb, c, d, m, n, r2, sp; - - tb = M_HALFPI / lp.lam - lp.lam / M_HALFPI; - c = lp.phi / M_HALFPI; - d = (1 - c * c)/((sp = sin(lp.phi)) - c); - r2 = tb / d; - r2 *= r2; - m = (tb * sp / d - 0.5 * tb)/(1. + r2); - n = (sp / r2 + 0.5 * d)/(1. + 1./r2); - xy.x = cos(lp.phi); - xy.x = sqrt(m * m + xy.x * xy.x / (1. + r2)); - xy.x = M_HALFPI * ( m + (lp.lam < 0. ? -xy.x : xy.x)); - xy.y = sqrt(n * n - (sp * sp / r2 + d * sp - 1.) / - (1. + 1./r2)); - xy.y = M_HALFPI * ( n + (lp.phi < 0. ? xy.y : -xy.y )); - } - return (xy); -} - - -PJ *PROJECTION(nicol) { - P->es = 0.; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_nsper.cpp b/src/projections/PJ_nsper.cpp deleted file mode 100644 index f93010f8..00000000 --- a/src/projections/PJ_nsper.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -namespace { // anonymous namespace -enum Mode { - N_POLE = 0, - S_POLE = 1, - EQUIT = 2, - OBLIQ = 3 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double height; - double sinph0; - double cosph0; - double p; - double rp; - double pn1; - double pfact; - double h; - double cg; - double sg; - double sw; - double cw; - enum Mode mode; - int tilt; -}; -} // anonymous namespace - -PROJ_HEAD(nsper, "Near-sided perspective") "\n\tAzi, Sph\n\th="; -PROJ_HEAD(tpers, "Tilted perspective") "\n\tAzi, Sph\n\ttilt= azi= h="; - -# define EPS10 1.e-10 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, cosphi, sinphi; - - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - coslam = cos(lp.lam); - switch (Q->mode) { - case OBLIQ: - xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam; - break; - case EQUIT: - xy.y = cosphi * coslam; - break; - case S_POLE: - xy.y = - sinphi; - break; - case N_POLE: - xy.y = sinphi; - break; - } - if (xy.y < Q->rp) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.y = Q->pn1 / (Q->p - xy.y); - xy.x = xy.y * cosphi * sin(lp.lam); - switch (Q->mode) { - case OBLIQ: - xy.y *= (Q->cosph0 * sinphi - - Q->sinph0 * cosphi * coslam); - break; - case EQUIT: - xy.y *= sinphi; - break; - case N_POLE: - coslam = - coslam; - /*-fallthrough*/ - case S_POLE: - xy.y *= cosphi * coslam; - break; - } - if (Q->tilt) { - double yt, ba; - - yt = xy.y * Q->cg + xy.x * Q->sg; - ba = 1. / (yt * Q->sw * Q->h + Q->cw); - xy.x = (xy.x * Q->cg - xy.y * Q->sg) * Q->cw * ba; - xy.y = yt * ba; - } - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double rh, cosz, sinz; - - if (Q->tilt) { - double bm, bq, yt; - - yt = 1./(Q->pn1 - xy.y * Q->sw); - bm = Q->pn1 * xy.x * yt; - bq = Q->pn1 * xy.y * Q->cw * yt; - xy.x = bm * Q->cg + bq * Q->sg; - xy.y = bq * Q->cg - bm * Q->sg; - } - rh = hypot(xy.x, xy.y); - if ((sinz = 1. - rh * rh * Q->pfact) < 0.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - sinz = (Q->p - sqrt(sinz)) / (Q->pn1 / rh + rh / Q->pn1); - cosz = sqrt(1. - sinz * sinz); - if (fabs(rh) <= EPS10) { - lp.lam = 0.; - lp.phi = P->phi0; - } else { - switch (Q->mode) { - case OBLIQ: - lp.phi = asin(cosz * Q->sinph0 + xy.y * sinz * Q->cosph0 / rh); - xy.y = (cosz - Q->sinph0 * sin(lp.phi)) * rh; - xy.x *= sinz * Q->cosph0; - break; - case EQUIT: - lp.phi = asin(xy.y * sinz / rh); - xy.y = cosz * rh; - xy.x *= sinz; - break; - case N_POLE: - lp.phi = asin(cosz); - xy.y = -xy.y; - break; - case S_POLE: - lp.phi = - asin(cosz); - break; - } - lp.lam = atan2(xy.x, xy.y); - } - return lp; -} - - -static PJ *setup(PJ *P) { - struct pj_opaque *Q = static_cast(P->opaque); - - if ((Q->height = pj_param(P->ctx, P->params, "dh").f) <= 0.) - return pj_default_destructor(P, PJD_ERR_H_LESS_THAN_ZERO); - - if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) - Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - else if (fabs(P->phi0) < EPS10) - Q->mode = EQUIT; - else { - Q->mode = OBLIQ; - Q->sinph0 = sin(P->phi0); - Q->cosph0 = cos(P->phi0); - } - Q->pn1 = Q->height / P->a; /* normalize by radius */ - Q->p = 1. + Q->pn1; - Q->rp = 1. / Q->p; - Q->h = 1. / Q->pn1; - Q->pfact = (Q->p + 1.) * Q->h; - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - - return P; -} - - -PJ *PROJECTION(nsper) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->tilt = 0; - - return setup(P); -} - - -PJ *PROJECTION(tpers) { - double omega, gamma; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - omega = pj_param(P->ctx, P->params, "rtilt").f; - gamma = pj_param(P->ctx, P->params, "razi").f; - Q->tilt = 1; - Q->cg = cos(gamma); Q->sg = sin(gamma); - Q->cw = cos(omega); Q->sw = sin(omega); - - return setup(P); -} - diff --git a/src/projections/PJ_nzmg.cpp b/src/projections/PJ_nzmg.cpp deleted file mode 100644 index bf0862fb..00000000 --- a/src/projections/PJ_nzmg.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the nzmg (New Zealand Map Grid) projection. - * Very loosely based upon DMA code by Bradford W. Drew - * Author: Gerald Evenden - * - ****************************************************************************** - * Copyright (c) 1995, Gerald Evenden - * - * 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. - *****************************************************************************/ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(nzmg, "New Zealand Map Grid") "\n\tfixed Earth"; - -#define EPSLN 1e-10 -#define SEC5_TO_RAD 0.4848136811095359935899141023 -#define RAD_TO_SEC5 2.062648062470963551564733573 - -static const COMPLEX bf[] = { - { .7557853228, 0.0}, - { .249204646, 0.003371507}, - {-.001541739, 0.041058560}, - {-.10162907, 0.01727609}, - {-.26623489, -0.36249218}, - {-.6870983, -1.1651967} }; - -static const double tphi[] = { 1.5627014243, .5185406398, -.03333098, - -.1052906, -.0368594, .007317, - .01220, .00394, -.0013 }; - -static const double tpsi[] = { .6399175073, -.1358797613, .063294409, -.02526853, .0117879, - -.0055161, .0026906, -.001333, .00067, -.00034 }; - -#define Nbf 5 -#define Ntpsi 9 -#define Ntphi 8 - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - COMPLEX p; - const double *C; - int i; - - lp.phi = (lp.phi - P->phi0) * RAD_TO_SEC5; - for (p.r = *(C = tpsi + (i = Ntpsi)); i ; --i) - p.r = *--C + lp.phi * p.r; - p.r *= lp.phi; - p.i = lp.lam; - p = pj_zpoly1(p, bf, Nbf); - xy.x = p.i; - xy.y = p.r; - - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - int nn, i; - COMPLEX p, f, fp, dp; - double den; - const double *C; - - p.r = xy.y; - p.i = xy.x; - for (nn = 20; nn ;--nn) { - f = pj_zpolyd1(p, bf, Nbf, &fp); - f.r -= xy.y; - f.i -= xy.x; - den = fp.r * fp.r + fp.i * fp.i; - p.r += dp.r = -(f.r * fp.r + f.i * fp.i) / den; - p.i += dp.i = -(f.i * fp.r - f.r * fp.i) / den; - if ((fabs(dp.r) + fabs(dp.i)) <= EPSLN) - break; - } - if (nn) { - lp.lam = p.i; - for (lp.phi = *(C = tphi + (i = Ntphi)); i ; --i) - lp.phi = *--C + p.r * lp.phi; - lp.phi = P->phi0 + p.r * lp.phi * SEC5_TO_RAD; - } else - lp.lam = lp.phi = HUGE_VAL; - - return lp; -} - - -PJ *PROJECTION(nzmg) { - /* force to International major axis */ - P->ra = 1. / (P->a = 6378388.0); - P->lam0 = DEG_TO_RAD * 173.; - P->phi0 = DEG_TO_RAD * -41.; - P->x0 = 2510000.; - P->y0 = 6023150.; - - P->inv = e_inverse; - P->fwd = e_forward; - - - return P; -} diff --git a/src/projections/PJ_ob_tran.cpp b/src/projections/PJ_ob_tran.cpp deleted file mode 100644 index d34059a9..00000000 --- a/src/projections/PJ_ob_tran.cpp +++ /dev/null @@ -1,245 +0,0 @@ -#define PJ_LIB__ -#include -#include -#include -#include - -#include "proj.h" -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - struct PJconsts *link; - double lamp; - double cphip, sphip; -}; -} // anonymous namespace - -PROJ_HEAD(ob_tran, "General Oblique Transformation") "\n\tMisc Sph" -"\n\to_proj= plus parameters for projection" -"\n\to_lat_p= o_lon_p= (new pole) or" -"\n\to_alpha= o_lon_c= o_lat_c= or" -"\n\to_lon_1= o_lat_1= o_lon_2= o_lat_2="; - -#define TOL 1e-10 - - -static XY o_forward(LP lp, PJ *P) { /* spheroid */ - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, sinphi, cosphi; - - coslam = cos(lp.lam); - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam + - Q->cphip * sinphi) + Q->lamp); - lp.phi = aasin(P->ctx,Q->sphip * sinphi - Q->cphip * cosphi * coslam); - - return Q->link->fwd(lp, Q->link); -} - - -static XY t_forward(LP lp, PJ *P) { /* spheroid */ - struct pj_opaque *Q = static_cast(P->opaque); - double cosphi, coslam; - - cosphi = cos(lp.phi); - coslam = cos(lp.lam); - lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), sin(lp.phi)) + Q->lamp); - lp.phi = aasin(P->ctx, - cosphi * coslam); - - return Q->link->fwd(lp, Q->link); -} - - -static LP o_inverse(XY xy, PJ *P) { /* spheroid */ - - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, sinphi, cosphi; - - LP lp = Q->link->inv(xy, Q->link); - if (lp.lam != HUGE_VAL) { - coslam = cos(lp.lam -= Q->lamp); - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - lp.phi = aasin(P->ctx,Q->sphip * sinphi + Q->cphip * cosphi * coslam); - lp.lam = aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam - - Q->cphip * sinphi); - } - return lp; -} - - -static LP t_inverse(XY xy, PJ *P) { /* spheroid */ - - struct pj_opaque *Q = static_cast(P->opaque); - double cosphi, t; - - LP lp = Q->link->inv(xy, Q->link); - if (lp.lam != HUGE_VAL) { - cosphi = cos(lp.phi); - t = lp.lam - Q->lamp; - lp.lam = aatan2(cosphi * sin(t), - sin(lp.phi)); - lp.phi = aasin(P->ctx,cosphi * cos(t)); - } - return lp; -} - - -static PJ *destructor(PJ *P, int errlev) { - if (nullptr==P) - return nullptr; - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - if (static_cast(P->opaque)->link) - static_cast(P->opaque)->link->destructor (static_cast(P->opaque)->link, errlev); - - return pj_default_destructor(P, errlev); -} - - - - -/*********************************************************************** - -These functions are modified versions of the functions "argc_params" -and "argv_params" from PJ_pipeline.c - -Basically, they do the somewhat backwards stunt of turning the paralist -representation of the +args back into the original +argv, +argc -representation accepted by pj_init_ctx(). - -This, however, also begs the question of whether we really need the -paralist linked list representation, or if we could do with a simpler -null-terminated argv style array? This would simplfy some code, and -keep memory allocations more localized. - -***********************************************************************/ - -typedef struct {int argc; char **argv;} ARGS; - -/* count the number of args in the linked list */ -static size_t paralist_params_argc (paralist *params) { - size_t argc = 0; - for (; params != nullptr; params = params->next) - argc++; - return argc; -} - - -/* turn paralist into argc/argv style argument list */ -static ARGS ob_tran_target_params (paralist *params) { - int i = 0; - ARGS args = {0, nullptr}; - size_t argc = paralist_params_argc (params); - if (argc < 2) - return args; - - /* all args except the proj_ob_tran */ - args.argv = static_cast(pj_calloc (argc - 1, sizeof (char *))); - if (nullptr==args.argv) - return args; - - /* Copy all args *except* the proj=ob_tran arg to the argv array */ - for (i = 0; params != nullptr; params = params->next) { - if (0==strcmp (params->param, "proj=ob_tran")) - continue; - args.argv[i++] = params->param; - } - args.argc = i; - - /* Then convert the o_proj=xxx element to proj=xxx */ - for (i = 0; i < args.argc; i++) { - if (0!=strncmp (args.argv[i], "o_proj=", 7)) - continue; - args.argv[i] += 2; - break; - } - - return args; -} - - - -PJ *PROJECTION(ob_tran) { - double phip; - char *name; - ARGS args; - PJ *R; /* projection to rotate */ - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return destructor(P, ENOMEM); - - P->opaque = Q; - P->destructor = destructor; - - /* get name of projection to be translated */ - if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) - return destructor(P, PJD_ERR_NO_ROTATION_PROJ); - - /* avoid endless recursion */ - if( strcmp(name, "ob_tran") == 0 ) - return destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); - - /* Create the target projection object to rotate */ - args = ob_tran_target_params (P->params); - R = pj_init_ctx (pj_get_ctx(P), args.argc, args.argv); - pj_dealloc (args.argv); - - if (nullptr==R) - return destructor (P, PJD_ERR_UNKNOWN_PROJECTION_ID); - Q->link = R; - - if (pj_param(P->ctx, P->params, "to_alpha").i) { - double lamc, phic, alpha; - - lamc = pj_param(P->ctx, P->params, "ro_lon_c").f; - phic = pj_param(P->ctx, P->params, "ro_lat_c").f; - alpha = pj_param(P->ctx, P->params, "ro_alpha").f; - - if (fabs(fabs(phic) - M_HALFPI) <= TOL) - return destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); - - Q->lamp = lamc + aatan2(-cos(alpha), -sin(alpha) * sin(phic)); - phip = aasin(P->ctx,cos(phic) * sin(alpha)); - } else if (pj_param(P->ctx, P->params, "to_lat_p").i) { /* specified new pole */ - Q->lamp = pj_param(P->ctx, P->params, "ro_lon_p").f; - phip = pj_param(P->ctx, P->params, "ro_lat_p").f; - } else { /* specified new "equator" points */ - double lam1, lam2, phi1, phi2, con; - - lam1 = pj_param(P->ctx, P->params, "ro_lon_1").f; - phi1 = pj_param(P->ctx, P->params, "ro_lat_1").f; - lam2 = pj_param(P->ctx, P->params, "ro_lon_2").f; - phi2 = pj_param(P->ctx, P->params, "ro_lat_2").f; - if (fabs(phi1 - phi2) <= TOL || (con = fabs(phi1)) <= TOL || - fabs(con - M_HALFPI) <= TOL || fabs(fabs(phi2) - M_HALFPI) <= TOL) - return destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); - - Q->lamp = atan2(cos(phi1) * sin(phi2) * cos(lam1) - - sin(phi1) * cos(phi2) * cos(lam2), - sin(phi1) * cos(phi2) * sin(lam2) - - cos(phi1) * sin(phi2) * sin(lam1)); - phip = atan(-cos(Q->lamp - lam1) / tan(phi1)); - } - - if (fabs(phip) > TOL) { /* oblique */ - Q->cphip = cos(phip); - Q->sphip = sin(phip); - P->fwd = Q->link->fwd ? o_forward : nullptr; - P->inv = Q->link->inv ? o_inverse : nullptr; - } else { /* transverse */ - P->fwd = Q->link->fwd ? t_forward : nullptr; - P->inv = Q->link->inv ? t_inverse : nullptr; - } - - /* Support some rather speculative test cases, where the rotated projection */ - /* is actually latlong. We do not want scaling in that case... */ - if (Q->link->right==PJ_IO_UNITS_ANGULAR) - P->right = PJ_IO_UNITS_PROJECTED; - - - return P; -} diff --git a/src/projections/PJ_ocea.cpp b/src/projections/PJ_ocea.cpp deleted file mode 100644 index 0576ace7..00000000 --- a/src/projections/PJ_ocea.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(ocea, "Oblique Cylindrical Equal Area") "\n\tCyl, Sph" - "lonc= alpha= or\n\tlat_1= lat_2= lon_1= lon_2="; - -namespace { // anonymous namespace -struct pj_opaque { - double rok; - double rtk; - double sinphi; - double cosphi; - double singam; - double cosgam; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double t; - xy.y = sin(lp.lam); - t = cos(lp.lam); - xy.x = atan((tan(lp.phi) * Q->cosphi + Q->sinphi * xy.y) / t); - if (t < 0.) - xy.x += M_PI; - xy.x *= Q->rtk; - xy.y = Q->rok * (Q->sinphi * sin(lp.phi) - Q->cosphi * cos(lp.phi) * xy.y); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double t, s; - - xy.y /= Q->rok; - xy.x /= Q->rtk; - t = sqrt(1. - xy.y * xy.y); - lp.phi = asin(xy.y * Q->sinphi + t * Q->cosphi * (s = sin(xy.x))); - lp.lam = atan2(t * Q->sinphi * s - xy.y * Q->cosphi, - t * cos(xy.x)); - return lp; -} - - -PJ *PROJECTION(ocea) { - double phi_0=0.0, phi_1, phi_2, lam_1, lam_2, lonz, alpha; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->rok = 1. / P->k0; - Q->rtk = P->k0; - /*If the keyword "alpha" is found in the sentence then use 1point+1azimuth*/ - if ( pj_param(P->ctx, P->params, "talpha").i) { - /*Define Pole of oblique transformation from 1 point & 1 azimuth*/ - alpha = pj_param(P->ctx, P->params, "ralpha").f; - lonz = pj_param(P->ctx, P->params, "rlonc").f; - /*Equation 9-8 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ - Q->singam = atan(-cos(alpha)/(-sin(phi_0) * sin(alpha))) + lonz; - /*Equation 9-7 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ - Q->sinphi = asin(cos(phi_0) * sin(alpha)); - /*If the keyword "alpha" is NOT found in the sentence then use 2points*/ - } else { - /*Define Pole of oblique transformation from 2 points*/ - phi_1 = pj_param(P->ctx, P->params, "rlat_1").f; - phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; - lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; - lam_2 = pj_param(P->ctx, P->params, "rlon_2").f; - /*Equation 9-1 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ - Q->singam = atan2(cos(phi_1) * sin(phi_2) * cos(lam_1) - - sin(phi_1) * cos(phi_2) * cos(lam_2), - sin(phi_1) * cos(phi_2) * sin(lam_2) - - cos(phi_1) * sin(phi_2) * sin(lam_1) ); - - /* take care of P->lam0 wrap-around when +lam_1=-90*/ - if (lam_1 == -M_HALFPI) - Q->singam = -Q->singam; - - /*Equation 9-2 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ - Q->sinphi = atan(-cos(Q->singam - lam_1) / tan(phi_1)); - } - P->lam0 = Q->singam + M_HALFPI; - Q->cosphi = cos(Q->sinphi); - Q->sinphi = sin(Q->sinphi); - Q->cosgam = cos(Q->singam); - Q->singam = sin(Q->singam); - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - - return P; -} diff --git a/src/projections/PJ_oea.cpp b/src/projections/PJ_oea.cpp deleted file mode 100644 index 0c401b2f..00000000 --- a/src/projections/PJ_oea.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -PROJ_HEAD(oea, "Oblated Equal Area") "\n\tMisc Sph\n\tn= m= theta="; - -namespace { // anonymous namespace -struct pj_opaque { - double theta; - double m, n; - double two_r_m, two_r_n, rm, rn, hm, hn; - double cp0, sp0; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double Az, M, N, cp, sp, cl, shz; - - cp = cos(lp.phi); - sp = sin(lp.phi); - cl = cos(lp.lam); - Az = aatan2(cp * sin(lp.lam), Q->cp0 * sp - Q->sp0 * cp * cl) + Q->theta; - shz = sin(0.5 * aacos(P->ctx, Q->sp0 * sp + Q->cp0 * cp * cl)); - M = aasin(P->ctx, shz * sin(Az)); - N = aasin(P->ctx, shz * cos(Az) * cos(M) / cos(M * Q->two_r_m)); - xy.y = Q->n * sin(N * Q->two_r_n); - xy.x = Q->m * sin(M * Q->two_r_m) * cos(N) / cos(N * Q->two_r_n); - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double N, M, xp, yp, z, Az, cz, sz, cAz; - - N = Q->hn * aasin(P->ctx,xy.y * Q->rn); - M = Q->hm * aasin(P->ctx,xy.x * Q->rm * cos(N * Q->two_r_n) / cos(N)); - xp = 2. * sin(M); - yp = 2. * sin(N) * cos(M * Q->two_r_m) / cos(M); - cAz = cos(Az = aatan2(xp, yp) - Q->theta); - z = 2. * aasin(P->ctx, 0.5 * hypot(xp, yp)); - sz = sin(z); - cz = cos(z); - lp.phi = aasin(P->ctx, Q->sp0 * cz + Q->cp0 * sz * cAz); - lp.lam = aatan2(sz * sin(Az), - Q->cp0 * cz - Q->sp0 * sz * cAz); - - return lp; -} - - - - -PJ *PROJECTION(oea) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - if (((Q->n = pj_param(P->ctx, P->params, "dn").f) <= 0.) || - ((Q->m = pj_param(P->ctx, P->params, "dm").f) <= 0.)) { - return pj_default_destructor(P, PJD_ERR_INVALID_M_OR_N); - } else { - Q->theta = pj_param(P->ctx, P->params, "rtheta").f; - Q->sp0 = sin(P->phi0); - Q->cp0 = cos(P->phi0); - Q->rn = 1./ Q->n; - Q->rm = 1./ Q->m; - Q->two_r_n = 2. * Q->rn; - Q->two_r_m = 2. * Q->rm; - Q->hm = 0.5 * Q->m; - Q->hn = 0.5 * Q->n; - P->fwd = s_forward; - P->inv = s_inverse; - P->es = 0.; - } - - return P; -} - diff --git a/src/projections/PJ_omerc.cpp b/src/projections/PJ_omerc.cpp deleted file mode 100644 index ead07128..00000000 --- a/src/projections/PJ_omerc.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* -** Copyright (c) 2003, 2006 Gerald I. Evenden -*/ -/* -** 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. -*/ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(omerc, "Oblique Mercator") - "\n\tCyl, Sph&Ell no_rot\n\t" - "alpha= [gamma=] [no_off] lonc= or\n\t lon_1= lat_1= lon_2= lat_2="; - -namespace { // anonymous namespace -struct pj_opaque { - double A, B, E, AB, ArB, BrA, rB, singam, cosgam, sinrot, cosrot; - double v_pole_n, v_pole_s, u_0; - int no_rot; -}; -} // anonymous namespace - -#define TOL 1.e-7 -#define EPS 1.e-10 - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double S, T, U, V, W, temp, u, v; - - if (fabs(fabs(lp.phi) - M_HALFPI) > EPS) { - W = Q->E / pow(pj_tsfn(lp.phi, sin(lp.phi), P->e), Q->B); - temp = 1. / W; - S = .5 * (W - temp); - T = .5 * (W + temp); - V = sin(Q->B * lp.lam); - U = (S * Q->singam - V * Q->cosgam) / T; - if (fabs(fabs(U) - 1.0) < EPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - v = 0.5 * Q->ArB * log((1. - U)/(1. + U)); - temp = cos(Q->B * lp.lam); - if(fabs(temp) < TOL) { - u = Q->A * lp.lam; - } else { - u = Q->ArB * atan2((S * Q->cosgam + V * Q->singam), temp); - } - } else { - v = lp.phi > 0 ? Q->v_pole_n : Q->v_pole_s; - u = Q->ArB * lp.phi; - } - if (Q->no_rot) { - xy.x = u; - xy.y = v; - } else { - u -= Q->u_0; - xy.x = v * Q->cosrot + u * Q->sinrot; - xy.y = u * Q->cosrot - v * Q->sinrot; - } - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double u, v, Qp, Sp, Tp, Vp, Up; - - if (Q->no_rot) { - v = xy.y; - u = xy.x; - } else { - v = xy.x * Q->cosrot - xy.y * Q->sinrot; - u = xy.y * Q->cosrot + xy.x * Q->sinrot + Q->u_0; - } - Qp = exp(- Q->BrA * v); - Sp = .5 * (Qp - 1. / Qp); - Tp = .5 * (Qp + 1. / Qp); - Vp = sin(Q->BrA * u); - Up = (Vp * Q->cosgam + Sp * Q->singam) / Tp; - if (fabs(fabs(Up) - 1.) < EPS) { - lp.lam = 0.; - lp.phi = Up < 0. ? -M_HALFPI : M_HALFPI; - } else { - lp.phi = Q->E / sqrt((1. + Up) / (1. - Up)); - if ((lp.phi = pj_phi2(P->ctx, pow(lp.phi, 1. / Q->B), P->e)) == HUGE_VAL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - lp.lam = - Q->rB * atan2((Sp * Q->cosgam - - Vp * Q->singam), cos(Q->BrA * u)); - } - return lp; -} - - -PJ *PROJECTION(omerc) { - double con, com, cosph0, D, F, H, L, sinph0, p, J, gamma=0, - gamma0, lamc=0, lam1=0, lam2=0, phi1=0, phi2=0, alpha_c=0; - int alp, gam, no_off = 0; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->no_rot = pj_param(P->ctx, P->params, "bno_rot").i; - if ((alp = pj_param(P->ctx, P->params, "talpha").i) != 0) - alpha_c = pj_param(P->ctx, P->params, "ralpha").f; - if ((gam = pj_param(P->ctx, P->params, "tgamma").i) != 0) - gamma = pj_param(P->ctx, P->params, "rgamma").f; - if (alp || gam) { - lamc = pj_param(P->ctx, P->params, "rlonc").f; - no_off = - /* For libproj4 compatibility */ - pj_param(P->ctx, P->params, "tno_off").i - /* for backward compatibility */ - || pj_param(P->ctx, P->params, "tno_uoff").i; - if( no_off ) - { - /* Mark the parameter as used, so that the pj_get_def() return them */ - pj_param(P->ctx, P->params, "sno_uoff"); - pj_param(P->ctx, P->params, "sno_off"); - } - } else { - lam1 = pj_param(P->ctx, P->params, "rlon_1").f; - phi1 = pj_param(P->ctx, P->params, "rlat_1").f; - lam2 = pj_param(P->ctx, P->params, "rlon_2").f; - phi2 = pj_param(P->ctx, P->params, "rlat_2").f; - if (fabs(phi1 - phi2) <= TOL || - (con = fabs(phi1)) <= TOL || - fabs(con - M_HALFPI) <= TOL || - fabs(fabs(P->phi0) - M_HALFPI) <= TOL || - fabs(fabs(phi2) - M_HALFPI) <= TOL) - return pj_default_destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); - } - com = sqrt(P->one_es); - if (fabs(P->phi0) > EPS) { - sinph0 = sin(P->phi0); - cosph0 = cos(P->phi0); - con = 1. - P->es * sinph0 * sinph0; - Q->B = cosph0 * cosph0; - Q->B = sqrt(1. + P->es * Q->B * Q->B / P->one_es); - Q->A = Q->B * P->k0 * com / con; - D = Q->B * com / (cosph0 * sqrt(con)); - if ((F = D * D - 1.) <= 0.) - F = 0.; - else { - F = sqrt(F); - if (P->phi0 < 0.) - F = -F; - } - Q->E = F += D; - Q->E *= pow(pj_tsfn(P->phi0, sinph0, P->e), Q->B); - } else { - Q->B = 1. / com; - Q->A = P->k0; - Q->E = D = F = 1.; - } - if (alp || gam) { - if (alp) { - gamma0 = aasin(P->ctx, sin(alpha_c) / D); - if (!gam) - gamma = alpha_c; - } else - alpha_c = aasin(P->ctx, D*sin(gamma0 = gamma)); - P->lam0 = lamc - aasin(P->ctx, .5 * (F - 1. / F) * - tan(gamma0)) / Q->B; - } else { - H = pow(pj_tsfn(phi1, sin(phi1), P->e), Q->B); - L = pow(pj_tsfn(phi2, sin(phi2), P->e), Q->B); - F = Q->E / H; - p = (L - H) / (L + H); - J = Q->E * Q->E; - J = (J - L * H) / (J + L * H); - if ((con = lam1 - lam2) < -M_PI) - lam2 -= M_TWOPI; - else if (con > M_PI) - lam2 += M_TWOPI; - P->lam0 = adjlon(.5 * (lam1 + lam2) - atan( - J * tan(.5 * Q->B * (lam1 - lam2)) / p) / Q->B); - gamma0 = atan(2. * sin(Q->B * adjlon(lam1 - P->lam0)) / - (F - 1. / F)); - gamma = alpha_c = aasin(P->ctx, D * sin(gamma0)); - } - Q->singam = sin(gamma0); - Q->cosgam = cos(gamma0); - Q->sinrot = sin(gamma); - Q->cosrot = cos(gamma); - Q->BrA = 1. / (Q->ArB = Q->A * (Q->rB = 1. / Q->B)); - Q->AB = Q->A * Q->B; - if (no_off) - Q->u_0 = 0; - else { - Q->u_0 = fabs(Q->ArB * atan(sqrt(D * D - 1.) / cos(alpha_c))); - if (P->phi0 < 0.) - Q->u_0 = - Q->u_0; - } - F = 0.5 * gamma0; - Q->v_pole_n = Q->ArB * log(tan(M_FORTPI - F)); - Q->v_pole_s = Q->ArB * log(tan(M_FORTPI + F)); - P->inv = e_inverse; - P->fwd = e_forward; - - return P; -} diff --git a/src/projections/PJ_ortho.cpp b/src/projections/PJ_ortho.cpp deleted file mode 100644 index 6ea55248..00000000 --- a/src/projections/PJ_ortho.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "proj_internal.h" -#include "proj_math.h" -#include "projects.h" - -PROJ_HEAD(ortho, "Orthographic") "\n\tAzi, Sph"; - -namespace { // anonymous namespace -enum Mode { - N_POLE = 0, - S_POLE = 1, - EQUIT = 2, - OBLIQ = 3 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double sinph0; - double cosph0; - enum Mode mode; -}; -} // anonymous namespace - -#define EPS10 1.e-10 - -static XY forward_error(PJ *P, LP lp, XY xy) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - proj_log_trace(P, "Coordinate (%.3f, %.3f) is on the unprojected hemisphere", - proj_todeg(lp.lam), proj_todeg(lp.phi)); - return xy; -} - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy; - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, cosphi, sinphi; - - xy.x = HUGE_VAL; xy.y = HUGE_VAL; - - cosphi = cos(lp.phi); - coslam = cos(lp.lam); - switch (Q->mode) { - case EQUIT: - if (cosphi * coslam < - EPS10) - return forward_error(P, lp, xy); - xy.y = sin(lp.phi); - break; - case OBLIQ: - if (Q->sinph0 * (sinphi = sin(lp.phi)) + Q->cosph0 * cosphi * coslam < - EPS10) - return forward_error(P, lp, xy); - xy.y = Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam; - break; - case N_POLE: - coslam = - coslam; - /*-fallthrough*/ - case S_POLE: - if (fabs(lp.phi - P->phi0) - EPS10 > M_HALFPI) - return forward_error(P, lp, xy); - xy.y = cosphi * coslam; - break; - } - xy.x = cosphi * sin(lp.lam); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp; - struct pj_opaque *Q = static_cast(P->opaque); - double rh, cosc, sinc; - - lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; - - if ((sinc = (rh = hypot(xy.x, xy.y))) > 1.) { - if ((sinc - 1.) > EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - proj_log_trace(P, "Point (%.3f, %.3f) is outside the projection boundary"); - return lp; - } - sinc = 1.; - } - cosc = sqrt(1. - sinc * sinc); /* in this range OK */ - if (fabs(rh) <= EPS10) { - lp.phi = P->phi0; - lp.lam = 0.0; - } else { - switch (Q->mode) { - case N_POLE: - xy.y = -xy.y; - lp.phi = acos(sinc); - break; - case S_POLE: - lp.phi = - acos(sinc); - break; - case EQUIT: - lp.phi = xy.y * sinc / rh; - xy.x *= sinc; - xy.y = cosc * rh; - goto sinchk; - case OBLIQ: - lp.phi = cosc * Q->sinph0 + xy.y * sinc * Q->cosph0 /rh; - xy.y = (cosc - Q->sinph0 * lp.phi) * rh; - xy.x *= sinc * Q->cosph0; - sinchk: - if (fabs(lp.phi) >= 1.) - lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; - else - lp.phi = asin(lp.phi); - break; - } - lp.lam = (xy.y == 0. && (Q->mode == OBLIQ || Q->mode == EQUIT)) - ? (xy.x == 0. ? 0. : xy.x < 0. ? -M_HALFPI : M_HALFPI) - : atan2(xy.x, xy.y); - } - return lp; -} - - - -PJ *PROJECTION(ortho) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - if (fabs(fabs(P->phi0) - M_HALFPI) <= EPS10) - Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - else if (fabs(P->phi0) > EPS10) { - Q->mode = OBLIQ; - Q->sinph0 = sin(P->phi0); - Q->cosph0 = cos(P->phi0); - } else - Q->mode = EQUIT; - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - - return P; -} - diff --git a/src/projections/PJ_patterson.cpp b/src/projections/PJ_patterson.cpp deleted file mode 100644 index 0d19414e..00000000 --- a/src/projections/PJ_patterson.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2014 Bojan Savric - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * The Patterson Cylindrical projection was designed by Tom Patterson, US National - * Park Service, in 2014, using Flex Projector. The polynomial equations for the - * projection were developed by Bojan Savric, Oregon State University, in - * collaboration with Tom Patterson and Bernhard Jenny, Oregon State University. - * - * Java reference algorithm implemented by Bojan Savric in Java Map Projection - * Library (a Java port of PROJ.4) in the file PattersonProjection.java. - * - * References: - * Java Map Projection Library - * https://github.com/OSUCartography/JMapProjLib - * - * Patterson Cylindrical Projection - * http://shadedrelief.com/patterson/ - * - * Patterson, T., Savric, B., and Jenny, B. (2015). Cartographic Perspectives - * (No.78). Describes the projection design and characteristics, and - * developing the equations. doi:10.14714/CP78.1270 - * https://doi.org/10.14714/CP78.1270 - * - * Port to PROJ.4 by Micah Cochran, 26 March 2016 - */ - -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(patterson, "Patterson Cylindrical") "\n\tCyl"; - -#define K1 1.0148 -#define K2 0.23185 -#define K3 -0.14499 -#define K4 0.02406 -#define C1 K1 -#define C2 (5.0 * K2) -#define C3 (7.0 * K3) -#define C4 (9.0 * K4) -#define EPS11 1.0e-11 -#define MAX_Y 1.790857183 -/* Not sure at all of the appropriate number for MAX_ITER... */ -#define MAX_ITER 100 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double phi2; - (void) P; - - phi2 = lp.phi * lp.phi; - xy.x = lp.lam; - xy.y = lp.phi * (K1 + phi2 * phi2 * (K2 + phi2 * (K3 + K4 * phi2))); - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double yc, tol, y2, f, fder; - int i; - (void) P; - - yc = xy.y; - - /* make sure y is inside valid range */ - if (xy.y > MAX_Y) { - xy.y = MAX_Y; - } else if (xy.y < -MAX_Y) { - xy.y = -MAX_Y; - } - - for (i = MAX_ITER; i ; --i) { /* Newton-Raphson */ - y2 = yc * yc; - f = (yc * (K1 + y2 * y2 * (K2 + y2 * (K3 + K4 * y2)))) - xy.y; - fder = C1 + y2 * y2 * (C2 + y2 * (C3 + C4 * y2)); - yc -= tol = f / fder; - if (fabs(tol) < EPS11) { - break; - } - } - if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); - lp.phi = yc; - - /* longitude */ - lp.lam = xy.x; - - return lp; -} - - -PJ *PROJECTION(patterson) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_poly.cpp b/src/projections/PJ_poly.cpp deleted file mode 100644 index a970fdb1..00000000 --- a/src/projections/PJ_poly.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(poly, "Polyconic (American)") - "\n\tConic, Sph&Ell"; - -namespace { // anonymous namespace -struct pj_opaque { - double ml0; \ - double *en; -}; -} // anonymous namespace - -#define TOL 1e-10 -#define CONV 1e-10 -#define N_ITER 10 -#define I_ITER 20 -#define ITOL 1.e-12 - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double ms, sp, cp; - - if (fabs(lp.phi) <= TOL) { - xy.x = lp.lam; - xy.y = -Q->ml0; - } else { - sp = sin(lp.phi); - ms = fabs(cp = cos(lp.phi)) > TOL ? pj_msfn(sp, cp, P->es) / sp : 0.; - xy.x = ms * sin(lp.lam *= sp); - xy.y = (pj_mlfn(lp.phi, sp, cp, Q->en) - Q->ml0) + ms * (1. - cos(lp.lam)); - } - - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cot, E; - - if (fabs(lp.phi) <= TOL) { - xy.x = lp.lam; - xy.y = Q->ml0; - } else { - cot = 1. / tan(lp.phi); - xy.x = sin(E = lp.lam * sin(lp.phi)) * cot; - xy.y = lp.phi - P->phi0 + cot * (1. - cos(E)); - } - - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - xy.y += Q->ml0; - if (fabs(xy.y) <= TOL) { - lp.lam = xy.x; - lp.phi = 0.; - } else { - double r, c, sp, cp, s2ph, ml, mlb, mlp, dPhi; - int i; - - r = xy.y * xy.y + xy.x * xy.x; - lp.phi = xy.y; - for (i = I_ITER; i ; --i) { - sp = sin(lp.phi); - s2ph = sp * ( cp = cos(lp.phi)); - if (fabs(cp) < ITOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - c = sp * (mlp = sqrt(1. - P->es * sp * sp)) / cp; - ml = pj_mlfn(lp.phi, sp, cp, Q->en); - mlb = ml * ml + r; - mlp = P->one_es / (mlp * mlp * mlp); - lp.phi += ( dPhi = - ( ml + ml + c * mlb - 2. * xy.y * (c * ml + 1.) ) / ( - P->es * s2ph * (mlb - 2. * xy.y * ml) / c + - 2.* (xy.y - ml) * (c * mlp - 1. / s2ph) - mlp - mlp )); - if (fabs(dPhi) <= ITOL) - break; - } - if (!i) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - c = sin(lp.phi); - lp.lam = asin(xy.x * tan(lp.phi) * sqrt(1. - P->es * c * c)) / sin(lp.phi); - } - - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double B, dphi, tp; - int i; - - if (fabs(xy.y = P->phi0 + xy.y) <= TOL) { - lp.lam = xy.x; - lp.phi = 0.; - } else { - lp.phi = xy.y; - B = xy.x * xy.x + xy.y * xy.y; - i = N_ITER; - do { - tp = tan(lp.phi); - lp.phi -= (dphi = (xy.y * (lp.phi * tp + 1.) - lp.phi - - .5 * ( lp.phi * lp.phi + B) * tp) / - ((lp.phi - xy.y) / tp - 1.)); - } while (fabs(dphi) > CONV && --i); - if (! i) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - lp.lam = asin(xy.x * tan(lp.phi)) / sin(lp.phi); - } - - return lp; -} - - -static PJ *destructor(PJ *P, int errlev) { - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - if (static_cast(P->opaque)->en) - pj_dealloc (static_cast(P->opaque)->en); - - return pj_default_destructor(P, errlev); -} - - -PJ *PROJECTION(poly) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - - P->opaque = Q; - P->destructor = destructor; - - if (P->es != 0.0) { - if (!(Q->en = pj_enfn(P->es))) - return pj_default_destructor (P, ENOMEM); - Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); - P->inv = e_inverse; - P->fwd = e_forward; - } else { - Q->ml0 = -P->phi0; - P->inv = s_inverse; - P->fwd = s_forward; - } - - return P; -} diff --git a/src/projections/PJ_putp2.cpp b/src/projections/PJ_putp2.cpp deleted file mode 100644 index d7a847c8..00000000 --- a/src/projections/PJ_putp2.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(putp2, "Putnins P2") "\n\tPCyl, Sph"; - -#define C_x 1.89490 -#define C_y 1.71848 -#define C_p 0.6141848493043784 -#define EPS 1e-10 -#define NITER 10 -#define PI_DIV_3 1.0471975511965977 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double p, c, s, V; - int i; - (void) P; - - p = C_p * sin(lp.phi); - s = lp.phi * lp.phi; - lp.phi *= 0.615709 + s * ( 0.00909953 + s * 0.0046292 ); - for (i = NITER; i ; --i) { - c = cos(lp.phi); - s = sin(lp.phi); - lp.phi -= V = (lp.phi + s * (c - 1.) - p) / - (1. + c * (c - 1.) - s * s); - if (fabs(V) < EPS) - break; - } - if (!i) - lp.phi = lp.phi < 0 ? - PI_DIV_3 : PI_DIV_3; - xy.x = C_x * lp.lam * (cos(lp.phi) - 0.5); - xy.y = C_y * sin(lp.phi); - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double c; - - lp.phi = aasin(P->ctx,xy.y / C_y); - lp.lam = xy.x / (C_x * ((c = cos(lp.phi)) - 0.5)); - lp.phi = aasin(P->ctx,(lp.phi + sin(lp.phi) * (c - 1.)) / C_p); - - return lp; -} - - -PJ *PROJECTION(putp2) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_putp3.cpp b/src/projections/PJ_putp3.cpp deleted file mode 100644 index 98bb2ff0..00000000 --- a/src/projections/PJ_putp3.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#define PJ_LIB__ -#include -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - double A; -}; -} // anonymous namespace - -PROJ_HEAD(putp3, "Putnins P3") "\n\tPCyl, Sph"; -PROJ_HEAD(putp3p, "Putnins P3'") "\n\tPCyl, Sph"; - -#define C 0.79788456 -#define RPISQ 0.1013211836 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - - xy.x = C * lp.lam * (1. - static_cast(P->opaque)->A * lp.phi * lp.phi); - xy.y = C * lp.phi; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - - lp.phi = xy.y / C; - lp.lam = xy.x / (C * (1. - static_cast(P->opaque)->A * lp.phi * lp.phi)); - - return lp; -} - - -PJ *PROJECTION(putp3) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->A = 4. * RPISQ; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} - -PJ *PROJECTION(putp3p) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->A = 2. * RPISQ; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} - diff --git a/src/projections/PJ_putp4p.cpp b/src/projections/PJ_putp4p.cpp deleted file mode 100644 index 608fc76e..00000000 --- a/src/projections/PJ_putp4p.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - double C_x, C_y; -}; -} // anonymous namespace - -PROJ_HEAD(putp4p, "Putnins P4'") "\n\tPCyl, Sph"; -PROJ_HEAD(weren, "Werenskiold I") "\n\tPCyl, Sph"; - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - lp.phi = aasin(P->ctx,0.883883476 * sin(lp.phi)); - xy.x = Q->C_x * lp.lam * cos(lp.phi); - xy.x /= cos(lp.phi *= 0.333333333333333); - xy.y = Q->C_y * sin(lp.phi); - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - lp.phi = aasin(P->ctx,xy.y / Q->C_y); - lp.lam = xy.x * cos(lp.phi) / Q->C_x; - lp.phi *= 3.; - lp.lam /= cos(lp.phi); - lp.phi = aasin(P->ctx,1.13137085 * sin(lp.phi)); - - return lp; -} - - -PJ *PROJECTION(putp4p) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->C_x = 0.874038744; - Q->C_y = 3.883251825; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} - - -PJ *PROJECTION(weren) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->C_x = 1.; - Q->C_y = 4.442882938; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_putp5.cpp b/src/projections/PJ_putp5.cpp deleted file mode 100644 index 79e2ad15..00000000 --- a/src/projections/PJ_putp5.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - double A, B; -}; -} // anonymous namespace - -PROJ_HEAD(putp5, "Putnins P5") "\n\tPCyl, Sph"; -PROJ_HEAD(putp5p, "Putnins P5'") "\n\tPCyl, Sph"; - -#define C 1.01346 -#define D 1.2158542 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - xy.x = C * lp.lam * (Q->A - Q->B * sqrt(1. + D * lp.phi * lp.phi)); - xy.y = C * lp.phi; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - - lp.phi = xy.y / C; - lp.lam = xy.x / (C * (Q->A - Q->B * sqrt(1. + D * lp.phi * lp.phi))); - - return lp; -} - - - -PJ *PROJECTION(putp5) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->A = 2.; - Q->B = 1.; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} - - -PJ *PROJECTION(putp5p) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->A = 1.5; - Q->B = 0.5; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_putp6.cpp b/src/projections/PJ_putp6.cpp deleted file mode 100644 index 1186b18b..00000000 --- a/src/projections/PJ_putp6.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - double C_x, C_y, A, B, D; -}; -} // anonymous namespace - -PROJ_HEAD(putp6, "Putnins P6") "\n\tPCyl, Sph"; -PROJ_HEAD(putp6p, "Putnins P6'") "\n\tPCyl, Sph"; - -#define EPS 1e-10 -#define NITER 10 -#define CON_POLE 1.732050807568877 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double p, r, V; - int i; - - p = Q->B * sin(lp.phi); - lp.phi *= 1.10265779; - for (i = NITER; i ; --i) { - r = sqrt(1. + lp.phi * lp.phi); - lp.phi -= V = ( (Q->A - r) * lp.phi - log(lp.phi + r) - p ) / - (Q->A - 2. * r); - if (fabs(V) < EPS) - break; - } - if (!i) - lp.phi = p < 0. ? -CON_POLE : CON_POLE; - xy.x = Q->C_x * lp.lam * (Q->D - sqrt(1. + lp.phi * lp.phi)); - xy.y = Q->C_y * lp.phi; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double r; - - lp.phi = xy.y / Q->C_y; - r = sqrt(1. + lp.phi * lp.phi); - lp.lam = xy.x / (Q->C_x * (Q->D - r)); - lp.phi = aasin( P->ctx, ( (Q->A - r) * lp.phi - log(lp.phi + r) ) / Q->B); - - return lp; -} - - -PJ *PROJECTION(putp6) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - Q->C_x = 1.01346; - Q->C_y = 0.91910; - Q->A = 4.; - Q->B = 2.1471437182129378784; - Q->D = 2.; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} - - -PJ *PROJECTION(putp6p) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - Q->C_x = 0.44329; - Q->C_y = 0.80404; - Q->A = 6.; - Q->B = 5.61125; - Q->D = 3.; - - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_qsc.cpp b/src/projections/PJ_qsc.cpp deleted file mode 100644 index b50a7c95..00000000 --- a/src/projections/PJ_qsc.cpp +++ /dev/null @@ -1,408 +0,0 @@ -/* - * This implements the Quadrilateralized Spherical Cube (QSC) projection. - * - * Copyright (c) 2011, 2012 Martin Lambers - * - * The QSC projection was introduced in: - * [OL76] - * E.M. O'Neill and R.E. Laubscher, "Extended Studies of a Quadrilateralized - * Spherical Cube Earth Data Base", Naval Environmental Prediction Research - * Facility Tech. Report NEPRF 3-76 (CSC), May 1976. - * - * The preceding shift from an ellipsoid to a sphere, which allows to apply - * this projection to ellipsoids as used in the Ellipsoidal Cube Map model, - * is described in - * [LK12] - * M. Lambers and A. Kolb, "Ellipsoidal Cube Maps for Accurate Rendering of - * Planetary-Scale Terrain Data", Proc. Pacific Graphics (Short Papers), Sep. - * 2012 - * - * You have to choose one of the following projection centers, - * corresponding to the centers of the six cube faces: - * phi0 = 0.0, lam0 = 0.0 ("front" face) - * phi0 = 0.0, lam0 = 90.0 ("right" face) - * phi0 = 0.0, lam0 = 180.0 ("back" face) - * phi0 = 0.0, lam0 = -90.0 ("left" face) - * phi0 = 90.0 ("top" face) - * phi0 = -90.0 ("bottom" face) - * Other projection centers will not work! - * - * In the projection code below, each cube face is handled differently. - * See the computation of the face parameter in the PROJECTION(qsc) function - * and the handling of different face values (FACE_*) in the forward and - * inverse projections. - * - * Furthermore, the projection is originally only defined for theta angles - * between (-1/4 * PI) and (+1/4 * PI) on the current cube face. This area - * of definition is named AREA_0 in the projection code below. The other - * three areas of a cube face are handled by rotation of AREA_0. - */ - -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -/* The six cube faces. */ -namespace { // anonymous namespace -enum Face { - FACE_FRONT = 0, - FACE_RIGHT = 1, - FACE_BACK = 2, - FACE_LEFT = 3, - FACE_TOP = 4, - FACE_BOTTOM = 5 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - enum Face face; - double a_squared; - double b; - double one_minus_f; - double one_minus_f_squared; -}; -} // anonymous namespace -PROJ_HEAD(qsc, "Quadrilateralized Spherical Cube") "\n\tAzi, Sph"; - -#define EPS10 1.e-10 - -/* The four areas on a cube face. AREA_0 is the area of definition, - * the other three areas are counted counterclockwise. */ -namespace { // anonymous namespace -enum Area { - AREA_0 = 0, - AREA_1 = 1, - AREA_2 = 2, - AREA_3 = 3 -}; -} // anonymous namespace - -/* Helper function for forward projection: compute the theta angle - * and determine the area number. */ -static double qsc_fwd_equat_face_theta(double phi, double y, double x, enum Area *area) { - double theta; - if (phi < EPS10) { - *area = AREA_0; - theta = 0.0; - } else { - theta = atan2(y, x); - if (fabs(theta) <= M_FORTPI) { - *area = AREA_0; - } else if (theta > M_FORTPI && theta <= M_HALFPI + M_FORTPI) { - *area = AREA_1; - theta -= M_HALFPI; - } else if (theta > M_HALFPI + M_FORTPI || theta <= -(M_HALFPI + M_FORTPI)) { - *area = AREA_2; - theta = (theta >= 0.0 ? theta - M_PI : theta + M_PI); - } else { - *area = AREA_3; - theta += M_HALFPI; - } - } - return theta; -} - -/* Helper function: shift the longitude. */ -static double qsc_shift_lon_origin(double lon, double offset) { - double slon = lon + offset; - if (slon < -M_PI) { - slon += M_TWOPI; - } else if (slon > +M_PI) { - slon -= M_TWOPI; - } - return slon; -} - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double lat, lon; - double theta, phi; - double t, mu; /* nu; */ - enum Area area; - - /* Convert the geodetic latitude to a geocentric latitude. - * This corresponds to the shift from the ellipsoid to the sphere - * described in [LK12]. */ - if (P->es != 0.0) { - lat = atan(Q->one_minus_f_squared * tan(lp.phi)); - } else { - lat = lp.phi; - } - - /* Convert the input lat, lon into theta, phi as used by QSC. - * This depends on the cube face and the area on it. - * For the top and bottom face, we can compute theta and phi - * directly from phi, lam. For the other faces, we must use - * unit sphere cartesian coordinates as an intermediate step. */ - lon = lp.lam; - if (Q->face == FACE_TOP) { - phi = M_HALFPI - lat; - if (lon >= M_FORTPI && lon <= M_HALFPI + M_FORTPI) { - area = AREA_0; - theta = lon - M_HALFPI; - } else if (lon > M_HALFPI + M_FORTPI || lon <= -(M_HALFPI + M_FORTPI)) { - area = AREA_1; - theta = (lon > 0.0 ? lon - M_PI : lon + M_PI); - } else if (lon > -(M_HALFPI + M_FORTPI) && lon <= -M_FORTPI) { - area = AREA_2; - theta = lon + M_HALFPI; - } else { - area = AREA_3; - theta = lon; - } - } else if (Q->face == FACE_BOTTOM) { - phi = M_HALFPI + lat; - if (lon >= M_FORTPI && lon <= M_HALFPI + M_FORTPI) { - area = AREA_0; - theta = -lon + M_HALFPI; - } else if (lon < M_FORTPI && lon >= -M_FORTPI) { - area = AREA_1; - theta = -lon; - } else if (lon < -M_FORTPI && lon >= -(M_HALFPI + M_FORTPI)) { - area = AREA_2; - theta = -lon - M_HALFPI; - } else { - area = AREA_3; - theta = (lon > 0.0 ? -lon + M_PI : -lon - M_PI); - } - } else { - double q, r, s; - double sinlat, coslat; - double sinlon, coslon; - - if (Q->face == FACE_RIGHT) { - lon = qsc_shift_lon_origin(lon, +M_HALFPI); - } else if (Q->face == FACE_BACK) { - lon = qsc_shift_lon_origin(lon, +M_PI); - } else if (Q->face == FACE_LEFT) { - lon = qsc_shift_lon_origin(lon, -M_HALFPI); - } - sinlat = sin(lat); - coslat = cos(lat); - sinlon = sin(lon); - coslon = cos(lon); - q = coslat * coslon; - r = coslat * sinlon; - s = sinlat; - - if (Q->face == FACE_FRONT) { - phi = acos(q); - theta = qsc_fwd_equat_face_theta(phi, s, r, &area); - } else if (Q->face == FACE_RIGHT) { - phi = acos(r); - theta = qsc_fwd_equat_face_theta(phi, s, -q, &area); - } else if (Q->face == FACE_BACK) { - phi = acos(-q); - theta = qsc_fwd_equat_face_theta(phi, s, -r, &area); - } else if (Q->face == FACE_LEFT) { - phi = acos(-r); - theta = qsc_fwd_equat_face_theta(phi, s, q, &area); - } else { - /* Impossible */ - phi = theta = 0.0; - area = AREA_0; - } - } - - /* Compute mu and nu for the area of definition. - * For mu, see Eq. (3-21) in [OL76], but note the typos: - * compare with Eq. (3-14). For nu, see Eq. (3-38). */ - mu = atan((12.0 / M_PI) * (theta + acos(sin(theta) * cos(M_FORTPI)) - M_HALFPI)); - t = sqrt((1.0 - cos(phi)) / (cos(mu) * cos(mu)) / (1.0 - cos(atan(1.0 / cos(theta))))); - /* nu = atan(t); We don't really need nu, just t, see below. */ - - /* Apply the result to the real area. */ - if (area == AREA_1) { - mu += M_HALFPI; - } else if (area == AREA_2) { - mu += M_PI; - } else if (area == AREA_3) { - mu += M_PI_HALFPI; - } - - /* Now compute x, y from mu and nu */ - /* t = tan(nu); */ - xy.x = t * cos(mu); - xy.y = t * sin(mu); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double mu, nu, cosmu, tannu; - double tantheta, theta, cosphi, phi; - double t; - int area; - - /* Convert the input x, y to the mu and nu angles as used by QSC. - * This depends on the area of the cube face. */ - nu = atan(sqrt(xy.x * xy.x + xy.y * xy.y)); - mu = atan2(xy.y, xy.x); - if (xy.x >= 0.0 && xy.x >= fabs(xy.y)) { - area = AREA_0; - } else if (xy.y >= 0.0 && xy.y >= fabs(xy.x)) { - area = AREA_1; - mu -= M_HALFPI; - } else if (xy.x < 0.0 && -xy.x >= fabs(xy.y)) { - area = AREA_2; - mu = (mu < 0.0 ? mu + M_PI : mu - M_PI); - } else { - area = AREA_3; - mu += M_HALFPI; - } - - /* Compute phi and theta for the area of definition. - * The inverse projection is not described in the original paper, but some - * good hints can be found here (as of 2011-12-14): - * http://fits.gsfc.nasa.gov/fitsbits/saf.93/saf.9302 - * (search for "Message-Id: <9302181759.AA25477 at fits.cv.nrao.edu>") */ - t = (M_PI / 12.0) * tan(mu); - tantheta = sin(t) / (cos(t) - (1.0 / sqrt(2.0))); - theta = atan(tantheta); - cosmu = cos(mu); - tannu = tan(nu); - cosphi = 1.0 - cosmu * cosmu * tannu * tannu * (1.0 - cos(atan(1.0 / cos(theta)))); - if (cosphi < -1.0) { - cosphi = -1.0; - } else if (cosphi > +1.0) { - cosphi = +1.0; - } - - /* Apply the result to the real area on the cube face. - * For the top and bottom face, we can compute phi and lam directly. - * For the other faces, we must use unit sphere cartesian coordinates - * as an intermediate step. */ - if (Q->face == FACE_TOP) { - phi = acos(cosphi); - lp.phi = M_HALFPI - phi; - if (area == AREA_0) { - lp.lam = theta + M_HALFPI; - } else if (area == AREA_1) { - lp.lam = (theta < 0.0 ? theta + M_PI : theta - M_PI); - } else if (area == AREA_2) { - lp.lam = theta - M_HALFPI; - } else /* area == AREA_3 */ { - lp.lam = theta; - } - } else if (Q->face == FACE_BOTTOM) { - phi = acos(cosphi); - lp.phi = phi - M_HALFPI; - if (area == AREA_0) { - lp.lam = -theta + M_HALFPI; - } else if (area == AREA_1) { - lp.lam = -theta; - } else if (area == AREA_2) { - lp.lam = -theta - M_HALFPI; - } else /* area == AREA_3 */ { - lp.lam = (theta < 0.0 ? -theta - M_PI : -theta + M_PI); - } - } else { - /* Compute phi and lam via cartesian unit sphere coordinates. */ - double q, r, s; - q = cosphi; - t = q * q; - if (t >= 1.0) { - s = 0.0; - } else { - s = sqrt(1.0 - t) * sin(theta); - } - t += s * s; - if (t >= 1.0) { - r = 0.0; - } else { - r = sqrt(1.0 - t); - } - /* Rotate q,r,s into the correct area. */ - if (area == AREA_1) { - t = r; - r = -s; - s = t; - } else if (area == AREA_2) { - r = -r; - s = -s; - } else if (area == AREA_3) { - t = r; - r = s; - s = -t; - } - /* Rotate q,r,s into the correct cube face. */ - if (Q->face == FACE_RIGHT) { - t = q; - q = -r; - r = t; - } else if (Q->face == FACE_BACK) { - q = -q; - r = -r; - } else if (Q->face == FACE_LEFT) { - t = q; - q = r; - r = -t; - } - /* Now compute phi and lam from the unit sphere coordinates. */ - lp.phi = acos(-s) - M_HALFPI; - lp.lam = atan2(r, q); - if (Q->face == FACE_RIGHT) { - lp.lam = qsc_shift_lon_origin(lp.lam, -M_HALFPI); - } else if (Q->face == FACE_BACK) { - lp.lam = qsc_shift_lon_origin(lp.lam, -M_PI); - } else if (Q->face == FACE_LEFT) { - lp.lam = qsc_shift_lon_origin(lp.lam, +M_HALFPI); - } - } - - /* Apply the shift from the sphere to the ellipsoid as described - * in [LK12]. */ - if (P->es != 0.0) { - int invert_sign; - double tanphi, xa; - invert_sign = (lp.phi < 0.0 ? 1 : 0); - tanphi = tan(lp.phi); - xa = Q->b / sqrt(tanphi * tanphi + Q->one_minus_f_squared); - lp.phi = atan(sqrt(P->a * P->a - xa * xa) / (Q->one_minus_f * xa)); - if (invert_sign) { - lp.phi = -lp.phi; - } - } - return lp; -} - - -PJ *PROJECTION(qsc) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - P->inv = e_inverse; - P->fwd = e_forward; - /* Determine the cube face from the center of projection. */ - if (P->phi0 >= M_HALFPI - M_FORTPI / 2.0) { - Q->face = FACE_TOP; - } else if (P->phi0 <= -(M_HALFPI - M_FORTPI / 2.0)) { - Q->face = FACE_BOTTOM; - } else if (fabs(P->lam0) <= M_FORTPI) { - Q->face = FACE_FRONT; - } else if (fabs(P->lam0) <= M_HALFPI + M_FORTPI) { - Q->face = (P->lam0 > 0.0 ? FACE_RIGHT : FACE_LEFT); - } else { - Q->face = FACE_BACK; - } - /* Fill in useful values for the ellipsoid <-> sphere shift - * described in [LK12]. */ - if (P->es != 0.0) { - Q->a_squared = P->a * P->a; - Q->b = P->a * sqrt(1.0 - P->es); - Q->one_minus_f = 1.0 - (P->a - Q->b) / P->a; - Q->one_minus_f_squared = Q->one_minus_f * Q->one_minus_f; - } - - return P; -} diff --git a/src/projections/PJ_robin.cpp b/src/projections/PJ_robin.cpp deleted file mode 100644 index 987977ae..00000000 --- a/src/projections/PJ_robin.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#define PJ_LIB__ -#include "proj_math.h" -#include "proj_internal.h" -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(robin, "Robinson") "\n\tPCyl, Sph"; - -#define V(C,z) (C.c0 + z * (C.c1 + z * (C.c2 + z * C.c3))) -#define DV(C,z) (C.c1 + z * (C.c2 + C.c2 + z * 3. * C.c3)) - -/* -note: following terms based upon 5 deg. intervals in degrees. - -Some background on these coefficients is available at: - -http://article.gmane.org/gmane.comp.gis.proj-4.devel/6039 -http://trac.osgeo.org/proj/ticket/113 -*/ - -namespace { // anonymous namespace -struct COEFS { - float c0, c1, c2, c3; -}; -} // anonymous namespace - -static const struct COEFS X[] = { - {1.0f, 2.2199e-17f, -7.15515e-05f, 3.1103e-06f}, - {0.9986f, -0.000482243f, -2.4897e-05f, -1.3309e-06f}, - {0.9954f, -0.00083103f, -4.48605e-05f, -9.86701e-07f}, - {0.99f, -0.00135364f, -5.9661e-05f, 3.6777e-06f}, - {0.9822f, -0.00167442f, -4.49547e-06f, -5.72411e-06f}, - {0.973f, -0.00214868f, -9.03571e-05f, 1.8736e-08f}, - {0.96f, -0.00305085f, -9.00761e-05f, 1.64917e-06f}, - {0.9427f, -0.00382792f, -6.53386e-05f, -2.6154e-06f}, - {0.9216f, -0.00467746f, -0.00010457f, 4.81243e-06f}, - {0.8962f, -0.00536223f, -3.23831e-05f, -5.43432e-06f}, - {0.8679f, -0.00609363f, -0.000113898f, 3.32484e-06f}, - {0.835f, -0.00698325f, -6.40253e-05f, 9.34959e-07f}, - {0.7986f, -0.00755338f, -5.00009e-05f, 9.35324e-07f}, - {0.7597f, -0.00798324f, -3.5971e-05f, -2.27626e-06f}, - {0.7186f, -0.00851367f, -7.01149e-05f, -8.6303e-06f}, - {0.6732f, -0.00986209f, -0.000199569f, 1.91974e-05f}, - {0.6213f, -0.010418f, 8.83923e-05f, 6.24051e-06f}, - {0.5722f, -0.00906601f, 0.000182f, 6.24051e-06f}, - {0.5322f, -0.00677797f, 0.000275608f, 6.24051e-06f} -}; - -static const struct COEFS Y[] = { - {-5.20417e-18f, 0.0124f, 1.21431e-18f, -8.45284e-11f}, - {0.062f, 0.0124f, -1.26793e-09f, 4.22642e-10f}, - {0.124f, 0.0124f, 5.07171e-09f, -1.60604e-09f}, - {0.186f, 0.0123999f, -1.90189e-08f, 6.00152e-09f}, - {0.248f, 0.0124002f, 7.10039e-08f, -2.24e-08f}, - {0.31f, 0.0123992f, -2.64997e-07f, 8.35986e-08f}, - {0.372f, 0.0124029f, 9.88983e-07f, -3.11994e-07f}, - {0.434f, 0.0123893f, -3.69093e-06f, -4.35621e-07f}, - {0.4958f, 0.0123198f, -1.02252e-05f, -3.45523e-07f}, - {0.5571f, 0.0121916f, -1.54081e-05f, -5.82288e-07f}, - {0.6176f, 0.0119938f, -2.41424e-05f, -5.25327e-07f}, - {0.6769f, 0.011713f, -3.20223e-05f, -5.16405e-07f}, - {0.7346f, 0.0113541f, -3.97684e-05f, -6.09052e-07f}, - {0.7903f, 0.0109107f, -4.89042e-05f, -1.04739e-06f}, - {0.8435f, 0.0103431f, -6.4615e-05f, -1.40374e-09f}, - {0.8936f, 0.00969686f, -6.4636e-05f, -8.547e-06f}, - {0.9394f, 0.00840947f, -0.000192841f, -4.2106e-06f}, - {0.9761f, 0.00616527f, -0.000256f, -4.2106e-06f}, - {1.0f, 0.00328947f, -0.000319159f, -4.2106e-06f} -}; - -#define FXC 0.8487 -#define FYC 1.3523 -#define C1 11.45915590261646417544 -#define RC1 0.08726646259971647884 -#define NODES 18 -#define ONEEPS 1.000001 -#define EPS 1e-8 -/* Not sure at all of the appropriate number for MAX_ITER... */ -#define MAX_ITER 100 - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - long i; - double dphi; - (void) P; - - dphi = fabs(lp.phi); - i = isnan(lp.phi) ? -1 : lround(floor(dphi * C1)); - if( i < 0 ){ - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - if (i >= NODES) i = NODES - 1; - dphi = RAD_TO_DEG * (dphi - RC1 * i); - xy.x = V(X[i], dphi) * FXC * lp.lam; - xy.y = V(Y[i], dphi) * FYC; - if (lp.phi < 0.) xy.y = -xy.y; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - long i; - double t, t1; - struct COEFS T; - int iters; - - lp.lam = xy.x / FXC; - lp.phi = fabs(xy.y / FYC); - if (lp.phi >= 1.) { /* simple pathologic cases */ - if (lp.phi > ONEEPS) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - else { - lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; - lp.lam /= X[NODES].c0; - } - } else { /* general problem */ - /* in Y space, reduce to table interval */ - i = isnan(lp.phi) ? -1 : lround(floor(lp.phi * NODES)); - if( i < 0 || i >= NODES ) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - for (;;) { - if (Y[i].c0 > lp.phi) --i; - else if (Y[i+1].c0 <= lp.phi) ++i; - else break; - } - T = Y[i]; - /* first guess, linear interp */ - t = 5. * (lp.phi - T.c0)/(Y[i+1].c0 - T.c0); - /* make into root */ - T.c0 = (float)(T.c0 - lp.phi); - for (iters = MAX_ITER; iters ; --iters) { /* Newton-Raphson */ - t -= t1 = V(T,t) / DV(T,t); - if (fabs(t1) < EPS) - break; - } - if( iters == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); - lp.phi = (5 * i + t) * DEG_TO_RAD; - if (xy.y < 0.) lp.phi = -lp.phi; - lp.lam /= V(X[i], t); - } - return lp; -} - - -PJ *PROJECTION(robin) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} - - diff --git a/src/projections/PJ_rpoly.cpp b/src/projections/PJ_rpoly.cpp deleted file mode 100644 index a34f6171..00000000 --- a/src/projections/PJ_rpoly.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - double phi1; - double fxa; - double fxb; - int mode; -}; -} // anonymous namespace - -PROJ_HEAD(rpoly, "Rectangular Polyconic") - "\n\tConic, Sph, no inv\n\tlat_ts="; - -#define EPS 1e-9 - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double fa; - - if (Q->mode) - fa = tan(lp.lam * Q->fxb) * Q->fxa; - else - fa = 0.5 * lp.lam; - if (fabs(lp.phi) < EPS) { - xy.x = fa + fa; - xy.y = - P->phi0; - } else { - xy.y = 1. / tan(lp.phi); - xy.x = sin(fa = 2. * atan(fa * sin(lp.phi))) * xy.y; - xy.y = lp.phi - P->phi0 + (1. - cos(fa)) * xy.y; - } - return xy; -} - - - -PJ *PROJECTION(rpoly) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - if ((Q->mode = (Q->phi1 = fabs(pj_param(P->ctx, P->params, "rlat_ts").f)) > EPS)) { - Q->fxb = 0.5 * sin(Q->phi1); - Q->fxa = 0.5 / Q->fxb; - } - P->es = 0.; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_sch.cpp b/src/projections/PJ_sch.cpp deleted file mode 100644 index 5a2f944b..00000000 --- a/src/projections/PJ_sch.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/****************************************************************************** - * Project: SCH Coordinate system - * Purpose: Implementation of SCH Coordinate system - * References : - * 1. Hensley. Scott. SCH Coordinates and various transformations. June 15, 2000. - * 2. Buckley, Sean Monroe. Radar interferometry measurement of land subsidence. 2000.. - * PhD Thesis. UT Austin. (Appendix) - * 3. Hensley, Scott, Elaine Chapin, and T. Michel. "Improved processing of AIRSAR - * data based on the GeoSAR processor." Airsar earth science and applications - * workshop, March. 2002. (http://airsar.jpl.nasa.gov/documents/workshop2002/papers/T3.pdf) - * - * Author: Piyush Agram (piyush.agram@jpl.nasa.gov) - * Copyright (c) 2015 California Institute of Technology. - * Government sponsorship acknowledged. - * - * NOTE: The SCH coordinate system is a sensor aligned coordinate system - * developed at JPL for radar mapping missions. Details pertaining to the - * coordinate system have been release in the public domain (see references above). - * This code is an independent implementation of the SCH coordinate system - * that conforms to the PROJ.4 conventions and uses the details presented in these - * publicly released documents. All credit for the development of the coordinate - * system and its use should be directed towards the original developers at JPL. - ****************************************************************************** - * 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. - ****************************************************************************/ - -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" -#include "geocent.h" - -namespace { // anonymous namespace -struct pj_opaque { - double plat; /*Peg Latitude */ - double plon; /*Peg Longitude*/ - double phdg; /*Peg heading */ - double h0; /*Average altitude */ - double transMat[9]; - double xyzoff[3]; - double rcurv; - GeocentricInfo sph; - GeocentricInfo elp_0; -}; -} // anonymous namespace - -PROJ_HEAD(sch, "Spherical Cross-track Height") "\n\tMisc\n\tplat_0= plon_0= phdg_0= [h_0=]"; - -static LPZ inverse3d(XYZ xyz, PJ *P) { - LPZ lpz = {0.0, 0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double temp[3]; - double pxyz[3]; - - /* Local lat,lon using radius */ - pxyz[0] = xyz.y * P->a / Q->rcurv; - pxyz[1] = xyz.x * P->a / Q->rcurv; - pxyz[2] = xyz.z; - - if( pj_Convert_Geodetic_To_Geocentric( &(Q->sph), pxyz[0], pxyz[1], pxyz[2], temp, temp+1, temp+2) != 0) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lpz; - } - - /* Apply rotation */ - pxyz[0] = Q->transMat[0] * temp[0] + Q->transMat[1] * temp[1] + Q->transMat[2] * temp[2]; - pxyz[1] = Q->transMat[3] * temp[0] + Q->transMat[4] * temp[1] + Q->transMat[5] * temp[2]; - pxyz[2] = Q->transMat[6] * temp[0] + Q->transMat[7] * temp[1] + Q->transMat[8] * temp[2]; - - /* Apply offset */ - pxyz[0] += Q->xyzoff[0]; - pxyz[1] += Q->xyzoff[1]; - pxyz[2] += Q->xyzoff[2]; - - /* Convert geocentric coordinates to lat lon */ - pj_Convert_Geocentric_To_Geodetic( &(Q->elp_0), pxyz[0], pxyz[1], pxyz[2], - temp, temp+1, temp+2); - - - lpz.lam = temp[1] ; - lpz.phi = temp[0] ; - lpz.z = temp[2]; - - return lpz; -} - -static XYZ forward3d(LPZ lpz, PJ *P) { - XYZ xyz = {0.0, 0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double temp[3]; - double pxyz[3]; - - - /* Convert lat lon to geocentric coordinates */ - if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), lpz.phi, lpz.lam, lpz.z, temp, temp+1, temp+2 ) != 0 ) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xyz; - } - - - /* Adjust for offset */ - temp[0] -= Q->xyzoff[0]; - temp[1] -= Q->xyzoff[1]; - temp[2] -= Q->xyzoff[2]; - - - /* Apply rotation */ - pxyz[0] = Q->transMat[0] * temp[0] + Q->transMat[3] * temp[1] + Q->transMat[6] * temp[2]; - pxyz[1] = Q->transMat[1] * temp[0] + Q->transMat[4] * temp[1] + Q->transMat[7] * temp[2]; - pxyz[2] = Q->transMat[2] * temp[0] + Q->transMat[5] * temp[1] + Q->transMat[8] * temp[2]; - - /* Convert to local lat,lon */ - pj_Convert_Geocentric_To_Geodetic( &(Q->sph), pxyz[0], pxyz[1], pxyz[2], - temp, temp+1, temp+2); - - - /* Scale by radius */ - xyz.x = temp[1] * Q->rcurv / P->a; - xyz.y = temp[0] * Q->rcurv / P->a; - xyz.z = temp[2]; - - return xyz; -} - - -static PJ *setup(PJ *P) { /* general initialization */ - struct pj_opaque *Q = static_cast(P->opaque); - double reast, rnorth; - double chdg, shdg; - double clt, slt; - double clo, slo; - double temp; - double pxyz[3]; - - temp = P->a * sqrt(1.0 - P->es); - - /* Setup original geocentric system */ - if ( pj_Set_Geocentric_Parameters(&(Q->elp_0), P->a, temp) != 0) - return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); - - clt = cos(Q->plat); - slt = sin(Q->plat); - clo = cos(Q->plon); - slo = sin(Q->plon); - - /* Estimate the radius of curvature for given peg */ - temp = sqrt(1.0 - (P->es) * slt * slt); - reast = (P->a)/temp; - rnorth = (P->a) * (1.0 - (P->es))/pow(temp,3); - - chdg = cos(Q->phdg); - shdg = sin(Q->phdg); - - Q->rcurv = Q->h0 + (reast*rnorth)/(reast * chdg * chdg + rnorth * shdg * shdg); - - /* Set up local sphere at the given peg point */ - if ( pj_Set_Geocentric_Parameters(&(Q->sph), Q->rcurv, Q->rcurv) != 0) - return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); - - /* Set up the transformation matrices */ - Q->transMat[0] = clt * clo; - Q->transMat[1] = -shdg*slo - slt*clo * chdg; - Q->transMat[2] = slo*chdg - slt*clo*shdg; - Q->transMat[3] = clt*slo; - Q->transMat[4] = clo*shdg - slt*slo*chdg; - Q->transMat[5] = -clo*chdg - slt*slo*shdg; - Q->transMat[6] = slt; - Q->transMat[7] = clt*chdg; - Q->transMat[8] = clt*shdg; - - - if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), Q->plat, Q->plon, Q->h0, - pxyz, pxyz+1, pxyz+2 ) != 0 ) - return pj_default_destructor(P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); - - - Q->xyzoff[0] = pxyz[0] - (Q->rcurv) * clt * clo; - Q->xyzoff[1] = pxyz[1] - (Q->rcurv) * clt * slo; - Q->xyzoff[2] = pxyz[2] - (Q->rcurv) * slt; - - P->fwd3d = forward3d; - P->inv3d = inverse3d; - return P; -} - - -PJ *PROJECTION(sch) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - Q->h0 = 0.0; - - /* Check if peg latitude was defined */ - if (pj_param(P->ctx, P->params, "tplat_0").i) - Q->plat = pj_param(P->ctx, P->params, "rplat_0").f; - else { - return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); - } - - /* Check if peg longitude was defined */ - if (pj_param(P->ctx, P->params, "tplon_0").i) - Q->plon = pj_param(P->ctx, P->params, "rplon_0").f; - else { - return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); - } - - /* Check if peg latitude is defined */ - if (pj_param(P->ctx, P->params, "tphdg_0").i) - Q->phdg = pj_param(P->ctx, P->params, "rphdg_0").f; - else { - return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); - } - - - /* Check if average height was defined - If so read it in */ - if (pj_param(P->ctx, P->params, "th_0").i) - Q->h0 = pj_param(P->ctx, P->params, "dh_0").f; - - - return setup(P); -} diff --git a/src/projections/PJ_sconics.cpp b/src/projections/PJ_sconics.cpp deleted file mode 100644 index 1d19a13d..00000000 --- a/src/projections/PJ_sconics.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - - -namespace { // anonymous namespace -enum Type { - EULER = 0, - MURD1 = 1, - MURD2 = 2, - MURD3 = 3, - PCONIC = 4, - TISSOT = 5, - VITK1 = 6 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double n; - double rho_c; - double rho_0; - double sig; - double c1, c2; - enum Type type; -}; -} // anonymous namespace - - -#define EPS10 1.e-10 -#define EPS 1e-10 -#define LINE2 "\n\tConic, Sph\n\tlat_1= and lat_2=" - -PROJ_HEAD(euler, "Euler") LINE2; -PROJ_HEAD(murd1, "Murdoch I") LINE2; -PROJ_HEAD(murd2, "Murdoch II") LINE2; -PROJ_HEAD(murd3, "Murdoch III") LINE2; -PROJ_HEAD(pconic, "Perspective Conic") LINE2; -PROJ_HEAD(tissot, "Tissot") LINE2; -PROJ_HEAD(vitk1, "Vitkovsky I") LINE2; - - - -/* get common factors for simple conics */ -static int phi12(PJ *P, double *del) { - double p1, p2; - int err = 0; - - if (!pj_param(P->ctx, P->params, "tlat_1").i || - !pj_param(P->ctx, P->params, "tlat_2").i) { - err = -41; - } else { - p1 = pj_param(P->ctx, P->params, "rlat_1").f; - p2 = pj_param(P->ctx, P->params, "rlat_2").f; - *del = 0.5 * (p2 - p1); - static_cast(P->opaque)->sig = 0.5 * (p2 + p1); - err = (fabs(*del) < EPS || fabs(static_cast(P->opaque)->sig) < EPS) ? PJD_ERR_ABS_LAT1_EQ_ABS_LAT2 : 0; - } - return err; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double rho; - - switch (Q->type) { - case MURD2: - rho = Q->rho_c + tan (Q->sig - lp.phi); - break; - case PCONIC: - rho = Q->c2 * (Q->c1 - tan (lp.phi - Q->sig)); - break; - default: - rho = Q->rho_c - lp.phi; - break; - } - - xy.x = rho * sin ( lp.lam *= Q->n ); - xy.y = Q->rho_0 - rho * cos (lp.lam); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, (and ellipsoidal?) inverse */ - LP lp = {0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double rho; - - rho = hypot (xy.x, xy.y = Q->rho_0 - xy.y); - if (Q->n < 0.) { - rho = - rho; - xy.x = - xy.x; - xy.y = - xy.y; - } - - lp.lam = atan2 (xy.x, xy.y) / Q->n; - - switch (Q->type) { - case PCONIC: - lp.phi = atan (Q->c1 - rho / Q->c2) + Q->sig; - break; - case MURD2: - lp.phi = Q->sig - atan(rho - Q->rho_c); - break; - default: - lp.phi = Q->rho_c - rho; - } - return lp; -} - - -static PJ *setup(PJ *P, enum Type type) { - double del, cs; - int err; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - Q->type = type; - - err = phi12 (P, &del); - if(err) - return pj_default_destructor (P, err); - - switch (Q->type) { - - case TISSOT: - Q->n = sin (Q->sig); - cs = cos (del); - Q->rho_c = Q->n / cs + cs / Q->n; - Q->rho_0 = sqrt ((Q->rho_c - 2 * sin (P->phi0)) / Q->n); - break; - - case MURD1: - Q->rho_c = sin(del)/(del * tan(Q->sig)) + Q->sig; - Q->rho_0 = Q->rho_c - P->phi0; - Q->n = sin(Q->sig); - break; - - case MURD2: - Q->rho_c = (cs = sqrt (cos (del))) / tan (Q->sig); - Q->rho_0 = Q->rho_c + tan (Q->sig - P->phi0); - Q->n = sin (Q->sig) * cs; - break; - - case MURD3: - Q->rho_c = del / (tan(Q->sig) * tan(del)) + Q->sig; - Q->rho_0 = Q->rho_c - P->phi0; - Q->n = sin (Q->sig) * sin (del) * tan (del) / (del * del); - break; - - case EULER: - Q->n = sin (Q->sig) * sin (del) / del; - del *= 0.5; - Q->rho_c = del / (tan (del) * tan (Q->sig)) + Q->sig; - Q->rho_0 = Q->rho_c - P->phi0; - break; - - case PCONIC: - Q->n = sin (Q->sig); - Q->c2 = cos (del); - Q->c1 = 1./tan (Q->sig); - if (fabs (del = P->phi0 - Q->sig) - EPS10 >= M_HALFPI) - return pj_default_destructor(P, PJD_ERR_LAT_0_HALF_PI_FROM_MEAN); - - Q->rho_0 = Q->c2 * (Q->c1 - tan (del)); - break; - - case VITK1: - Q->n = (cs = tan (del)) * sin (Q->sig) / del; - Q->rho_c = del / (cs * tan (Q->sig)) + Q->sig; - Q->rho_0 = Q->rho_c - P->phi0; - break; - } - - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0; - return (P); -} - - -PJ *PROJECTION(euler) { - return setup(P, EULER); -} - - -PJ *PROJECTION(tissot) { - return setup(P, TISSOT); -} - - -PJ *PROJECTION(murd1) { - return setup(P, MURD1); -} - - -PJ *PROJECTION(murd2) { - return setup(P, MURD2); -} - - -PJ *PROJECTION(murd3) { - return setup(P, MURD3); -} - - -PJ *PROJECTION(pconic) { - return setup(P, PCONIC); -} - - -PJ *PROJECTION(vitk1) { - return setup(P, VITK1); -} - diff --git a/src/projections/PJ_somerc.cpp b/src/projections/PJ_somerc.cpp deleted file mode 100644 index 15d2e765..00000000 --- a/src/projections/PJ_somerc.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(somerc, "Swiss. Obl. Mercator") "\n\tCyl, Ell\n\tFor CH1903"; - -namespace { // anonymous namespace -struct pj_opaque { - double K, c, hlf_e, kR, cosp0, sinp0; -}; -} // anonymous namespace - -#define EPS 1.e-10 -#define NITER 6 - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0, 0.0}; - double phip, lamp, phipp, lampp, sp, cp; - struct pj_opaque *Q = static_cast(P->opaque); - - sp = P->e * sin (lp.phi); - phip = 2.* atan ( exp ( Q->c * ( - log (tan (M_FORTPI + 0.5 * lp.phi)) - Q->hlf_e * log ((1. + sp)/(1. - sp))) - + Q->K)) - M_HALFPI; - lamp = Q->c * lp.lam; - cp = cos(phip); - phipp = aasin (P->ctx, Q->cosp0 * sin (phip) - Q->sinp0 * cp * cos (lamp)); - lampp = aasin (P->ctx, cp * sin (lamp) / cos (phipp)); - xy.x = Q->kR * lampp; - xy.y = Q->kR * log (tan (M_FORTPI + 0.5 * phipp)); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double phip, lamp, phipp, lampp, cp, esp, con, delp; - int i; - - phipp = 2. * (atan (exp (xy.y / Q->kR)) - M_FORTPI); - lampp = xy.x / Q->kR; - cp = cos (phipp); - phip = aasin (P->ctx, Q->cosp0 * sin (phipp) + Q->sinp0 * cp * cos (lampp)); - lamp = aasin (P->ctx, cp * sin (lampp) / cos (phip)); - con = (Q->K - log (tan (M_FORTPI + 0.5 * phip)))/Q->c; - for (i = NITER; i ; --i) { - esp = P->e * sin(phip); - delp = (con + log(tan(M_FORTPI + 0.5 * phip)) - Q->hlf_e * - log((1. + esp)/(1. - esp)) ) * - (1. - esp * esp) * cos(phip) * P->rone_es; - phip -= delp; - if (fabs(delp) < EPS) - break; - } - if (i) { - lp.phi = phip; - lp.lam = lamp / Q->c; - } else { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - return (lp); -} - - -PJ *PROJECTION(somerc) { - double cp, phip0, sp; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - - Q->hlf_e = 0.5 * P->e; - cp = cos (P->phi0); - cp *= cp; - Q->c = sqrt (1 + P->es * cp * cp * P->rone_es); - sp = sin (P->phi0); - Q->cosp0 = cos( phip0 = aasin (P->ctx, Q->sinp0 = sp / Q->c) ); - sp *= P->e; - Q->K = log (tan (M_FORTPI + 0.5 * phip0)) - Q->c * ( - log (tan (M_FORTPI + 0.5 * P->phi0)) - Q->hlf_e * - log ((1. + sp) / (1. - sp))); - Q->kR = P->k0 * sqrt(P->one_es) / (1. - sp * sp); - P->inv = e_inverse; - P->fwd = e_forward; - return P; -} diff --git a/src/projections/PJ_stere.cpp b/src/projections/PJ_stere.cpp deleted file mode 100644 index 1502b2a6..00000000 --- a/src/projections/PJ_stere.cpp +++ /dev/null @@ -1,320 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - -PROJ_HEAD(stere, "Stereographic") "\n\tAzi, Sph&Ell\n\tlat_ts="; -PROJ_HEAD(ups, "Universal Polar Stereographic") "\n\tAzi, Sph&Ell\n\tsouth"; - - -namespace { // anonymous namespace -enum Mode { - S_POLE = 0, - N_POLE = 1, - OBLIQ = 2, - EQUIT = 3 -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque { - double phits; - double sinX1; - double cosX1; - double akm1; - enum Mode mode; -}; -} // anonymous namespace - -#define sinph0 static_cast(P->opaque)->sinX1 -#define cosph0 static_cast(P->opaque)->cosX1 -#define EPS10 1.e-10 -#define TOL 1.e-8 -#define NITER 8 -#define CONV 1.e-10 - -static double ssfn_ (double phit, double sinphi, double eccen) { - sinphi *= eccen; - return (tan (.5 * (M_HALFPI + phit)) * - pow ((1. - sinphi) / (1. + sinphi), .5 * eccen)); -} - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double coslam, sinlam, sinX = 0.0, cosX = 0.0, X, A = 0.0, sinphi; - - coslam = cos (lp.lam); - sinlam = sin (lp.lam); - sinphi = sin (lp.phi); - if (Q->mode == OBLIQ || Q->mode == EQUIT) { - sinX = sin (X = 2. * atan(ssfn_(lp.phi, sinphi, P->e)) - M_HALFPI); - cosX = cos (X); - } - - switch (Q->mode) { - case OBLIQ: - A = Q->akm1 / (Q->cosX1 * (1. + Q->sinX1 * sinX + - Q->cosX1 * cosX * coslam)); - xy.y = A * (Q->cosX1 * sinX - Q->sinX1 * cosX * coslam); - goto xmul; /* but why not just xy.x = A * cosX; break; ? */ - - case EQUIT: - /* avoid zero division */ - if (1. + cosX * coslam == 0.0) { - xy.y = HUGE_VAL; - } else { - A = Q->akm1 / (1. + cosX * coslam); - xy.y = A * sinX; - } -xmul: - xy.x = A * cosX; - break; - - case S_POLE: - lp.phi = -lp.phi; - coslam = - coslam; - sinphi = -sinphi; - /*-fallthrough*/ - case N_POLE: - xy.x = Q->akm1 * pj_tsfn (lp.phi, sinphi, P->e); - xy.y = - xy.x * coslam; - break; - } - - xy.x = xy.x * sinlam; - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double sinphi, cosphi, coslam, sinlam; - - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - coslam = cos(lp.lam); - sinlam = sin(lp.lam); - - switch (Q->mode) { - case EQUIT: - xy.y = 1. + cosphi * coslam; - goto oblcon; - case OBLIQ: - xy.y = 1. + sinph0 * sinphi + cosph0 * cosphi * coslam; -oblcon: - if (xy.y <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.x = (xy.y = Q->akm1 / xy.y) * cosphi * sinlam; - xy.y *= (Q->mode == EQUIT) ? sinphi : - cosph0 * sinphi - sinph0 * cosphi * coslam; - break; - case N_POLE: - coslam = - coslam; - lp.phi = - lp.phi; - /*-fallthrough*/ - case S_POLE: - if (fabs (lp.phi - M_HALFPI) < TOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.x = sinlam * ( xy.y = Q->akm1 * tan (M_FORTPI + .5 * lp.phi) ); - xy.y *= coslam; - break; - } - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cosphi, sinphi, tp=0.0, phi_l=0.0, rho, halfe=0.0, halfpi=0.0; - int i; - - rho = hypot (xy.x, xy.y); - - switch (Q->mode) { - case OBLIQ: - case EQUIT: - cosphi = cos ( tp = 2. * atan2 (rho * Q->cosX1 , Q->akm1) ); - sinphi = sin (tp); - if ( rho == 0.0 ) - phi_l = asin (cosphi * Q->sinX1); - else - phi_l = asin (cosphi * Q->sinX1 + (xy.y * sinphi * Q->cosX1 / rho)); - - tp = tan (.5 * (M_HALFPI + phi_l)); - xy.x *= sinphi; - xy.y = rho * Q->cosX1 * cosphi - xy.y * Q->sinX1* sinphi; - halfpi = M_HALFPI; - halfe = .5 * P->e; - break; - case N_POLE: - xy.y = -xy.y; - /*-fallthrough*/ - case S_POLE: - phi_l = M_HALFPI - 2. * atan (tp = - rho / Q->akm1); - halfpi = -M_HALFPI; - halfe = -.5 * P->e; - break; - } - - for (i = NITER; i--; phi_l = lp.phi) { - sinphi = P->e * sin(phi_l); - lp.phi = 2. * atan (tp * pow ((1.+sinphi)/(1.-sinphi), halfe)) - halfpi; - if (fabs (phi_l - lp.phi) < CONV) { - if (Q->mode == S_POLE) - lp.phi = -lp.phi; - lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2 (xy.x, xy.y); - return lp; - } - } - - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double c, rh, sinc, cosc; - - sinc = sin (c = 2. * atan ((rh = hypot (xy.x, xy.y)) / Q->akm1)); - cosc = cos (c); - lp.lam = 0.; - - switch (Q->mode) { - case EQUIT: - if (fabs (rh) <= EPS10) - lp.phi = 0.; - else - lp.phi = asin (xy.y * sinc / rh); - if (cosc != 0. || xy.x != 0.) - lp.lam = atan2 (xy.x * sinc, cosc * rh); - break; - case OBLIQ: - if (fabs (rh) <= EPS10) - lp.phi = P->phi0; - else - lp.phi = asin (cosc * sinph0 + xy.y * sinc * cosph0 / rh); - if ((c = cosc - sinph0 * sin (lp.phi)) != 0. || xy.x != 0.) - lp.lam = atan2 (xy.x * sinc * cosph0, c * rh); - break; - case N_POLE: - xy.y = -xy.y; - /*-fallthrough*/ - case S_POLE: - if (fabs (rh) <= EPS10) - lp.phi = P->phi0; - else - lp.phi = asin (Q->mode == S_POLE ? - cosc : cosc); - lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2 (xy.x, xy.y); - break; - } - return lp; -} - - -static PJ *setup(PJ *P) { /* general initialization */ - double t; - struct pj_opaque *Q = static_cast(P->opaque); - - if (fabs ((t = fabs (P->phi0)) - M_HALFPI) < EPS10) - Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - else - Q->mode = t > EPS10 ? OBLIQ : EQUIT; - Q->phits = fabs (Q->phits); - - if (P->es != 0.0) { - double X; - - switch (Q->mode) { - case N_POLE: - case S_POLE: - if (fabs (Q->phits - M_HALFPI) < EPS10) - Q->akm1 = 2. * P->k0 / - sqrt (pow (1+P->e,1+P->e) * pow (1-P->e,1-P->e)); - else { - Q->akm1 = cos (Q->phits) / - pj_tsfn (Q->phits, t = sin (Q->phits), P->e); - t *= P->e; - Q->akm1 /= sqrt(1. - t * t); - } - break; - case EQUIT: - case OBLIQ: - t = sin (P->phi0); - X = 2. * atan (ssfn_(P->phi0, t, P->e)) - M_HALFPI; - t *= P->e; - Q->akm1 = 2. * P->k0 * cos (P->phi0) / sqrt(1. - t * t); - Q->sinX1 = sin (X); - Q->cosX1 = cos (X); - break; - } - P->inv = e_inverse; - P->fwd = e_forward; - } else { - switch (Q->mode) { - case OBLIQ: - sinph0 = sin (P->phi0); - cosph0 = cos (P->phi0); - /*-fallthrough*/ - case EQUIT: - Q->akm1 = 2. * P->k0; - break; - case S_POLE: - case N_POLE: - Q->akm1 = fabs (Q->phits - M_HALFPI) >= EPS10 ? - cos (Q->phits) / tan (M_FORTPI - .5 * Q->phits) : - 2. * P->k0 ; - break; - } - - P->inv = s_inverse; - P->fwd = s_forward; - } - return P; -} - - -PJ *PROJECTION(stere) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->phits = pj_param (P->ctx, P->params, "tlat_ts").i ? - pj_param (P->ctx, P->params, "rlat_ts").f : M_HALFPI; - - return setup(P); -} - - -PJ *PROJECTION(ups) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - /* International Ellipsoid */ - P->phi0 = pj_param(P->ctx, P->params, "bsouth").i ? - M_HALFPI: M_HALFPI; - if (P->es == 0.0) { - proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - return pj_default_destructor (P, ENOMEM); - } - P->k0 = .994; - P->x0 = 2000000.; - P->y0 = 2000000.; - Q->phits = M_HALFPI; - P->lam0 = 0.; - - return setup(P); -} - diff --git a/src/projections/PJ_sterea.cpp b/src/projections/PJ_sterea.cpp deleted file mode 100644 index bb498068..00000000 --- a/src/projections/PJ_sterea.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* -** libproj -- library of cartographic projections -** -** Copyright (c) 2003 Gerald I. Evenden -*/ -/* -** 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. -*/ -#define PJ_LIB__ -#include -#include "projects.h" -#include "proj_math.h" - - -namespace { // anonymous namespace -struct pj_opaque { - double phic0; - double cosc0, sinc0; - double R2; - void *en; -}; -} // anonymous namespace - - -PROJ_HEAD(sterea, "Oblique Stereographic Alternative") "\n\tAzimuthal, Sph&Ell"; - - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cosc, sinc, cosl, k; - - lp = pj_gauss(P->ctx, lp, Q->en); - sinc = sin(lp.phi); - cosc = cos(lp.phi); - cosl = cos(lp.lam); - k = P->k0 * Q->R2 / (1. + Q->sinc0 * sinc + Q->cosc0 * cosc * cosl); - xy.x = k * cosc * sin(lp.lam); - xy.y = k * (Q->cosc0 * sinc - Q->sinc0 * cosc * cosl); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double rho, c, sinc, cosc; - - xy.x /= P->k0; - xy.y /= P->k0; - if ( (rho = hypot (xy.x, xy.y)) != 0.0 ) { - c = 2. * atan2 (rho, Q->R2); - sinc = sin (c); - cosc = cos (c); - lp.phi = asin (cosc * Q->sinc0 + xy.y * sinc * Q->cosc0 / rho); - lp.lam = atan2 (xy.x * sinc, rho * Q->cosc0 * cosc - xy.y * Q->sinc0 * sinc); - } else { - lp.phi = Q->phic0; - lp.lam = 0.; - } - return pj_inv_gauss(P->ctx, lp, Q->en); -} - - -static PJ *destructor (PJ *P, int errlev) { - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor (P, errlev); -} - - -PJ *PROJECTION(sterea) { - double R; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->en = pj_gauss_ini(P->e, P->phi0, &(Q->phic0), &R); - if (nullptr==Q->en) - return pj_default_destructor (P, ENOMEM); - - Q->sinc0 = sin (Q->phic0); - Q->cosc0 = cos (Q->phic0); - Q->R2 = 2. * R; - - P->inv = e_inverse; - P->fwd = e_forward; - P->destructor = destructor; - - return P; -} - diff --git a/src/projections/PJ_sts.cpp b/src/projections/PJ_sts.cpp deleted file mode 100644 index 9f889611..00000000 --- a/src/projections/PJ_sts.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(kav5, "Kavraisky V") "\n\tPCyl, Sph"; -PROJ_HEAD(qua_aut, "Quartic Authalic") "\n\tPCyl, Sph"; -PROJ_HEAD(fouc, "Foucaut") "\n\tPCyl, Sph"; -PROJ_HEAD(mbt_s, "McBryde-Thomas Flat-Polar Sine (No. 1)") "\n\tPCyl, Sph"; - - -namespace { // anonymous namespace -struct pj_opaque { - double C_x, C_y, C_p; - int tan_mode; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double c; - - xy.x = Q->C_x * lp.lam * cos(lp.phi); - xy.y = Q->C_y; - lp.phi *= Q->C_p; - c = cos(lp.phi); - if (Q->tan_mode) { - xy.x *= c * c; - xy.y *= tan (lp.phi); - } else { - xy.x /= c; - xy.y *= sin (lp.phi); - } - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double c; - - xy.y /= Q->C_y; - c = cos (lp.phi = Q->tan_mode ? atan (xy.y) : aasin (P->ctx, xy.y)); - lp.phi /= Q->C_p; - lp.lam = xy.x / (Q->C_x * cos(lp.phi)); - if (Q->tan_mode) - lp.lam /= c * c; - else - lp.lam *= c; - return lp; -} - - -static PJ *setup(PJ *P, double p, double q, int mode) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - static_cast(P->opaque)->C_x = q / p; - static_cast(P->opaque)->C_y = p; - static_cast(P->opaque)->C_p = 1/ q; - static_cast(P->opaque)->tan_mode = mode; - return P; -} - - - -PJ *PROJECTION(fouc) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - return setup(P, 2., 2., 1); -} - - - -PJ *PROJECTION(kav5) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - return setup(P, 1.50488, 1.35439, 0); -} - - - -PJ *PROJECTION(qua_aut) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - return setup(P, 2., 2., 0); -} - - - -PJ *PROJECTION(mbt_s) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - return setup(P, 1.48875, 1.36509, 0); -} diff --git a/src/projections/PJ_tcc.cpp b/src/projections/PJ_tcc.cpp deleted file mode 100644 index 64fdc182..00000000 --- a/src/projections/PJ_tcc.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(tcc, "Transverse Central Cylindrical") "\n\tCyl, Sph, no inv"; - -#define EPS10 1.e-10 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - double b, bt; - - b = cos (lp.phi) * sin (lp.lam); - if ((bt = 1. - b * b) < EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - xy.x = b / sqrt(bt); - xy.y = atan2 (tan (lp.phi) , cos (lp.lam)); - return xy; -} - - -PJ *PROJECTION(tcc) { - P->es = 0.; - P->fwd = s_forward; - P->inv = nullptr; - - return P; -} diff --git a/src/projections/PJ_tcea.cpp b/src/projections/PJ_tcea.cpp deleted file mode 100644 index d30f3df0..00000000 --- a/src/projections/PJ_tcea.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(tcea, "Transverse Cylindrical Equal Area") "\n\tCyl, Sph"; - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - xy.x = cos (lp.phi) * sin (lp.lam) / P->k0; - xy.y = P->k0 * (atan2 (tan (lp.phi), cos (lp.lam)) - P->phi0); - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0, 0.0}; - double t; - - xy.y = xy.y / P->k0 + P->phi0; - xy.x *= P->k0; - t = sqrt (1. - xy.x * xy.x); - lp.phi = asin (t * sin (xy.y)); - lp.lam = atan2 (xy.x, t * cos (xy.y)); - return lp; -} - - -PJ *PROJECTION(tcea) { - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - return P; -} diff --git a/src/projections/PJ_times.cpp b/src/projections/PJ_times.cpp deleted file mode 100644 index e8b4499f..00000000 --- a/src/projections/PJ_times.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the Times projection. - * Author: Kristian Evers - * - ****************************************************************************** - * Copyright (c) 2016, Kristian Evers - * - * 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. - ***************************************************************************** - * Based on describtion of the Times Projection in - * - * Flattening the Earth, Snyder, J.P., 1993, p.213-214. - *****************************************************************************/ - -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(times, "Times") "\n\tCyl, Sph"; - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - double T, S, S2; - XY xy = {0.0,0.0}; - (void) P; - - T = tan(lp.phi/2.0); - S = sin(M_FORTPI * T); - S2 = S*S; - - xy.x = lp.lam * (0.74482 - 0.34588*S2); - xy.y = 1.70711 * T; - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - double T, S, S2; - LP lp = {0.0,0.0}; - (void) P; - - T = xy.y / 1.70711; - S = sin(M_FORTPI * T); - S2 = S*S; - - lp.lam = xy.x / (0.74482 - 0.34588 * S2); - lp.phi = 2 * atan(T); - - return lp; -} - - -PJ *PROJECTION(times) { - P->es = 0.0; - - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_tmerc.cpp b/src/projections/PJ_tmerc.cpp deleted file mode 100644 index 5a2dacbd..00000000 --- a/src/projections/PJ_tmerc.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(tmerc, "Transverse Mercator") "\n\tCyl, Sph&Ell"; - - -namespace { // anonymous namespace -struct pj_opaque { - double esp; - double ml0; - double *en; -}; -} // anonymous namespace - -#define EPS10 1.e-10 -#define FC1 1. -#define FC2 .5 -#define FC3 .16666666666666666666 -#define FC4 .08333333333333333333 -#define FC5 .05 -#define FC6 .03333333333333333333 -#define FC7 .02380952380952380952 -#define FC8 .01785714285714285714 - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double al, als, n, cosphi, sinphi, t; - - /* - * Fail if our longitude is more than 90 degrees from the - * central meridian since the results are essentially garbage. - * Is error -20 really an appropriate return value? - * - * http://trac.osgeo.org/proj/ticket/5 - */ - if( lp.lam < -M_HALFPI || lp.lam > M_HALFPI ) { - xy.x = HUGE_VAL; - xy.y = HUGE_VAL; - pj_ctx_set_errno( P->ctx, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT ); - return xy; - } - - sinphi = sin (lp.phi); - cosphi = cos (lp.phi); - t = fabs (cosphi) > 1e-10 ? sinphi/cosphi : 0.; - t *= t; - al = cosphi * lp.lam; - als = al * al; - al /= sqrt (1. - P->es * sinphi * sinphi); - n = Q->esp * cosphi * cosphi; - xy.x = P->k0 * al * (FC1 + - FC3 * als * (1. - t + n + - FC5 * als * (5. + t * (t - 18.) + n * (14. - 58. * t) - + FC7 * als * (61. + t * ( t * (179. - t) - 479. ) ) - ))); - xy.y = P->k0 * (pj_mlfn(lp.phi, sinphi, cosphi, Q->en) - Q->ml0 + - sinphi * al * lp.lam * FC2 * ( 1. + - FC4 * als * (5. - t + n * (9. + 4. * n) + - FC6 * als * (61. + t * (t - 58.) + n * (270. - 330 * t) - + FC8 * als * (1385. + t * ( t * (543. - t) - 3111.) ) - )))); - return (xy); -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double b, cosphi; - - /* - * Fail if our longitude is more than 90 degrees from the - * central meridian since the results are essentially garbage. - * Is error -20 really an appropriate return value? - * - * http://trac.osgeo.org/proj/ticket/5 - */ - if( lp.lam < -M_HALFPI || lp.lam > M_HALFPI ) { - xy.x = HUGE_VAL; - xy.y = HUGE_VAL; - pj_ctx_set_errno( P->ctx, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT ); - return xy; - } - - cosphi = cos(lp.phi); - b = cosphi * sin (lp.lam); - if (fabs (fabs (b) - 1.) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - - xy.x = static_cast(P->opaque)->ml0 * log ((1. + b) / (1. - b)); - xy.y = cosphi * cos (lp.lam) / sqrt (1. - b * b); - - b = fabs ( xy.y ); - if (b >= 1.) { - if ((b - 1.) > EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - else xy.y = 0.; - } else - xy.y = acos (xy.y); - - if (lp.phi < 0.) - xy.y = -xy.y; - xy.y = static_cast(P->opaque)->esp * (xy.y - P->phi0); - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double n, con, cosphi, d, ds, sinphi, t; - - lp.phi = pj_inv_mlfn(P->ctx, Q->ml0 + xy.y / P->k0, P->es, Q->en); - if (fabs(lp.phi) >= M_HALFPI) { - lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; - lp.lam = 0.; - } else { - sinphi = sin(lp.phi); - cosphi = cos(lp.phi); - t = fabs (cosphi) > 1e-10 ? sinphi/cosphi : 0.; - n = Q->esp * cosphi * cosphi; - d = xy.x * sqrt (con = 1. - P->es * sinphi * sinphi) / P->k0; - con *= t; - t *= t; - ds = d * d; - lp.phi -= (con * ds / (1.-P->es)) * FC2 * (1. - - ds * FC4 * (5. + t * (3. - 9. * n) + n * (1. - 4 * n) - - ds * FC6 * (61. + t * (90. - 252. * n + - 45. * t) + 46. * n - - ds * FC8 * (1385. + t * (3633. + t * (4095. + 1575. * t)) ) - ))); - lp.lam = d*(FC1 - - ds*FC3*( 1. + 2.*t + n - - ds*FC5*(5. + t*(28. + 24.*t + 8.*n) + 6.*n - - ds * FC7 * (61. + t * (662. + t * (1320. + 720. * t)) ) - ))) / cosphi; - } - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0, 0.0}; - double h, g; - - h = exp(xy.x / static_cast(P->opaque)->esp); - g = .5 * (h - 1. / h); - h = cos (P->phi0 + xy.y / static_cast(P->opaque)->esp); - lp.phi = asin(sqrt((1. - h * h) / (1. + g * g))); - - /* Make sure that phi is on the correct hemisphere when false northing is used */ - if (xy.y < 0. && -lp.phi+P->phi0 < 0.0) lp.phi = -lp.phi; - - lp.lam = (g != 0.0 || h != 0.0) ? atan2 (g, h) : 0.; - return lp; -} - - -static PJ *destructor(PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor(P, errlev); - - pj_dealloc (static_cast(P->opaque)->en); - return pj_default_destructor(P, errlev); -} - - -static PJ *setup(PJ *P) { /* general initialization */ - struct pj_opaque *Q = static_cast(P->opaque); - if (P->es != 0.0) { - if (!(Q->en = pj_enfn(P->es))) - return pj_default_destructor(P, ENOMEM); - - Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); - Q->esp = P->es / (1. - P->es); - P->inv = e_inverse; - P->fwd = e_forward; - } else { - Q->esp = P->k0; - Q->ml0 = .5 * Q->esp; - P->inv = s_inverse; - P->fwd = s_forward; - } - return P; -} - - -PJ *PROJECTION(tmerc) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - - P->opaque = Q; - P->destructor = destructor; - - return setup(P); -} diff --git a/src/projections/PJ_tobmerc.cpp b/src/projections/PJ_tobmerc.cpp deleted file mode 100644 index 9c939f0b..00000000 --- a/src/projections/PJ_tobmerc.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj_internal.h" -#include "proj.h" -#include "proj_math.h" -#include "projects.h" - -PROJ_HEAD(tobmerc, "Tobler-Mercator") "\n\tCyl, Sph"; - -#define EPS10 1.e-10 -static double logtanpfpim1(double x) { /* log(tan(x/2 + M_FORTPI)) */ - if (fabs(x) <= DBL_EPSILON) { - /* tan(M_FORTPI + .5 * x) can be approximated by 1.0 + x */ - return log1p(x); - } - return log(tan(M_FORTPI + .5 * x)); -} - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - double cosphi; - - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - - cosphi = cos(lp.phi); - xy.x = P->k0 * lp.lam * cosphi * cosphi; - xy.y = P->k0 * logtanpfpim1(lp.phi); - return xy; -} - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0, 0.0}; - double cosphi; - - lp.phi = atan(sinh(xy.y / P->k0)); - cosphi = cos(lp.phi); - lp.lam = xy.x / P->k0 / (cosphi * cosphi); - return lp; -} - -PJ *PROJECTION(tobmerc) { - P->inv = s_inverse; - P->fwd = s_forward; - return P; -} diff --git a/src/projections/PJ_tpeqd.cpp b/src/projections/PJ_tpeqd.cpp deleted file mode 100644 index 2720327a..00000000 --- a/src/projections/PJ_tpeqd.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#define PJ_LIB__ -#include -#include "proj.h" -#include "proj_math.h" -#include "projects.h" - - -PROJ_HEAD(tpeqd, "Two Point Equidistant") - "\n\tMisc Sph\n\tlat_1= lon_1= lat_2= lon_2="; - -namespace { // anonymous namespace -struct pj_opaque { - double cp1, sp1, cp2, sp2, ccs, cs, sc, r2z0, z02, dlam2; - double hz0, thz0, rhshz0, ca, sa, lp, lamc; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double t, z1, z2, dl1, dl2, sp, cp; - - sp = sin(lp.phi); - cp = cos(lp.phi); - z1 = aacos(P->ctx, Q->sp1 * sp + Q->cp1 * cp * cos (dl1 = lp.lam + Q->dlam2)); - z2 = aacos(P->ctx, Q->sp2 * sp + Q->cp2 * cp * cos (dl2 = lp.lam - Q->dlam2)); - z1 *= z1; - z2 *= z2; - - xy.x = Q->r2z0 * (t = z1 - z2); - t = Q->z02 - t; - xy.y = Q->r2z0 * asqrt (4. * Q->z02 * z2 - t * t); - if ((Q->ccs * sp - cp * (Q->cs * sin(dl1) - Q->sc * sin(dl2))) < 0.) - xy.y = -xy.y; - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double cz1, cz2, s, d, cp, sp; - - cz1 = cos (hypot(xy.y, xy.x + Q->hz0)); - cz2 = cos (hypot(xy.y, xy.x - Q->hz0)); - s = cz1 + cz2; - d = cz1 - cz2; - lp.lam = - atan2(d, (s * Q->thz0)); - lp.phi = aacos(P->ctx, hypot (Q->thz0 * s, d) * Q->rhshz0); - if ( xy.y < 0. ) - lp.phi = - lp.phi; - /* lam--phi now in system relative to P1--P2 base equator */ - sp = sin (lp.phi); - cp = cos (lp.phi); - lp.phi = aasin (P->ctx, Q->sa * sp + Q->ca * cp * (s = cos(lp.lam -= Q->lp))); - lp.lam = atan2 (cp * sin(lp.lam), Q->sa * cp * s - Q->ca * sp) + Q->lamc; - return lp; -} - - -PJ *PROJECTION(tpeqd) { - double lam_1, lam_2, phi_1, phi_2, A12, pp; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - - /* get control point locations */ - phi_1 = pj_param(P->ctx, P->params, "rlat_1").f; - lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; - phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; - lam_2 = pj_param(P->ctx, P->params, "rlon_2").f; - - if (phi_1 == phi_2 && lam_1 == lam_2) - return pj_default_destructor(P, PJD_ERR_CONTROL_POINT_NO_DIST); - - P->lam0 = adjlon (0.5 * (lam_1 + lam_2)); - Q->dlam2 = adjlon (lam_2 - lam_1); - - Q->cp1 = cos (phi_1); - Q->cp2 = cos (phi_2); - Q->sp1 = sin (phi_1); - Q->sp2 = sin (phi_2); - Q->cs = Q->cp1 * Q->sp2; - Q->sc = Q->sp1 * Q->cp2; - Q->ccs = Q->cp1 * Q->cp2 * sin(Q->dlam2); - Q->z02 = aacos(P->ctx, Q->sp1 * Q->sp2 + Q->cp1 * Q->cp2 * cos (Q->dlam2)); - Q->hz0 = .5 * Q->z02; - A12 = atan2(Q->cp2 * sin (Q->dlam2), - Q->cp1 * Q->sp2 - Q->sp1 * Q->cp2 * cos (Q->dlam2)); - Q->ca = cos(pp = aasin(P->ctx, Q->cp1 * sin(A12))); - Q->sa = sin(pp); - Q->lp = adjlon ( atan2 (Q->cp1 * cos(A12), Q->sp1) - Q->hz0); - Q->dlam2 *= .5; - Q->lamc = M_HALFPI - atan2(sin(A12) * Q->sp1, cos(A12)) - Q->dlam2; - Q->thz0 = tan (Q->hz0); - Q->rhshz0 = .5 / sin (Q->hz0); - Q->r2z0 = 0.5 / Q->z02; - Q->z02 *= Q->z02; - - P->inv = s_inverse; - P->fwd = s_forward; - P->es = 0.; - - return P; -} - diff --git a/src/projections/PJ_urm5.cpp b/src/projections/PJ_urm5.cpp deleted file mode 100644 index 0e3c7e3c..00000000 --- a/src/projections/PJ_urm5.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(urm5, "Urmaev V") "\n\tPCyl, Sph, no inv\n\tn= q= alpha="; - -namespace { // anonymous namespace -struct pj_opaque { - double m, rmn, q3, n; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double t; - - t = lp.phi = aasin (P->ctx, Q->n * sin (lp.phi)); - xy.x = Q->m * lp.lam * cos (lp.phi); - t *= t; - xy.y = lp.phi * (1. + t * Q->q3) * Q->rmn; - return xy; -} - - -PJ *PROJECTION(urm5) { - double alpha, t; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - if (pj_param(P->ctx, P->params, "tn").i) { - Q->n = pj_param(P->ctx, P->params, "dn").f; - if (Q->n <= 0. || Q->n > 1.) - return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); - } else { - return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); - } - Q->q3 = pj_param(P->ctx, P->params, "dq").f / 3.; - alpha = pj_param(P->ctx, P->params, "ralpha").f; - t = Q->n * sin (alpha); - Q->m = cos (alpha) / sqrt (1. - t * t); - Q->rmn = 1. / (Q->m * Q->n); - - P->es = 0.; - P->inv = nullptr; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_urmfps.cpp b/src/projections/PJ_urmfps.cpp deleted file mode 100644 index 7103222a..00000000 --- a/src/projections/PJ_urmfps.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(urmfps, "Urmaev Flat-Polar Sinusoidal") "\n\tPCyl, Sph\n\tn="; -PROJ_HEAD(wag1, "Wagner I (Kavraisky VI)") "\n\tPCyl, Sph"; - -namespace { // anonymous namespace -struct pj_opaque { - double n, C_y; -}; -} // anonymous namespace - -#define C_x 0.8773826753 -#define Cy 1.139753528477 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - lp.phi = aasin (P->ctx,static_cast(P->opaque)->n * sin (lp.phi)); - xy.x = C_x * lp.lam * cos (lp.phi); - xy.y = static_cast(P->opaque)->C_y * lp.phi; - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0, 0.0}; - xy.y /= static_cast(P->opaque)->C_y; - lp.phi = aasin(P->ctx, sin (xy.y) / static_cast(P->opaque)->n); - lp.lam = xy.x / (C_x * cos (xy.y)); - return lp; -} - - -static PJ *setup(PJ *P) { - static_cast(P->opaque)->C_y = Cy / static_cast(P->opaque)->n; - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - return P; -} - - -PJ *PROJECTION(urmfps) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - - P->opaque = Q; - - if (pj_param(P->ctx, P->params, "tn").i) { - static_cast(P->opaque)->n = pj_param(P->ctx, P->params, "dn").f; - if (static_cast(P->opaque)->n <= 0. || static_cast(P->opaque)->n > 1.) - return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); - } else { - return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); - } - - return setup(P); -} - - -PJ *PROJECTION(wag1) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - static_cast(P->opaque)->n = 0.8660254037844386467637231707; - return setup(P); -} diff --git a/src/projections/PJ_vandg.cpp b/src/projections/PJ_vandg.cpp deleted file mode 100644 index d148e210..00000000 --- a/src/projections/PJ_vandg.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#define PJ_LIB__ -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(vandg, "van der Grinten (I)") "\n\tMisc Sph"; - -# define TOL 1.e-10 -# define THIRD .33333333333333333333 -# define C2_27 .07407407407407407407 -# define PI4_3 4.18879020478639098458 -# define PISQ 9.86960440108935861869 -# define TPISQ 19.73920880217871723738 -# define HPISQ 4.93480220054467930934 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double al, al2, g, g2, p2; - - p2 = fabs(lp.phi / M_HALFPI); - if ((p2 - TOL) > 1.) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - if (p2 > 1.) - p2 = 1.; - if (fabs(lp.phi) <= TOL) { - xy.x = lp.lam; - xy.y = 0.; - } else if (fabs(lp.lam) <= TOL || fabs(p2 - 1.) < TOL) { - xy.x = 0.; - xy.y = M_PI * tan(.5 * asin(p2)); - if (lp.phi < 0.) xy.y = -xy.y; - } else { - al = .5 * fabs(M_PI / lp.lam - lp.lam / M_PI); - al2 = al * al; - g = sqrt(1. - p2 * p2); - g = g / (p2 + g - 1.); - g2 = g * g; - p2 = g * (2. / p2 - 1.); - p2 = p2 * p2; - xy.x = g - p2; g = p2 + al2; - xy.x = M_PI * (al * xy.x + sqrt(al2 * xy.x * xy.x - g * (g2 - p2))) / g; - if (lp.lam < 0.) xy.x = -xy.x; - xy.y = fabs(xy.x / M_PI); - xy.y = 1. - xy.y * (xy.y + 2. * al); - if (xy.y < -TOL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } - if (xy.y < 0.) - xy.y = 0.; - else - xy.y = sqrt(xy.y) * (lp.phi < 0. ? -M_PI : M_PI); - } - - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - double t, c0, c1, c2, c3, al, r2, r, m, d, ay, x2, y2; - - x2 = xy.x * xy.x; - if ((ay = fabs(xy.y)) < TOL) { - lp.phi = 0.; - t = x2 * x2 + TPISQ * (x2 + HPISQ); - lp.lam = fabs(xy.x) <= TOL ? 0. : - .5 * (x2 - PISQ + sqrt(t)) / xy.x; - return (lp); - } - y2 = xy.y * xy.y; - r = x2 + y2; r2 = r * r; - c1 = - M_PI * ay * (r + PISQ); - c3 = r2 + M_TWOPI * (ay * r + M_PI * (y2 + M_PI * (ay + M_HALFPI))); - c2 = c1 + PISQ * (r - 3. * y2); - c0 = M_PI * ay; - c2 /= c3; - al = c1 / c3 - THIRD * c2 * c2; - m = 2. * sqrt(-THIRD * al); - d = C2_27 * c2 * c2 * c2 + (c0 * c0 - THIRD * c2 * c1) / c3; - if (((t = fabs(d = 3. * d / (al * m))) - TOL) <= 1.) { - d = t > 1. ? (d > 0. ? 0. : M_PI) : acos(d); - lp.phi = M_PI * (m * cos(d * THIRD + PI4_3) - THIRD * c2); - if (xy.y < 0.) lp.phi = -lp.phi; - t = r2 + TPISQ * (x2 - y2 + HPISQ); - lp.lam = fabs(xy.x) <= TOL ? 0. : - .5 * (r - PISQ + (t <= 0. ? 0. : sqrt(t))) / xy.x; - } else { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; - } - - return lp; -} - - -PJ *PROJECTION(vandg) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} - diff --git a/src/projections/PJ_vandg2.cpp b/src/projections/PJ_vandg2.cpp deleted file mode 100644 index 61d50044..00000000 --- a/src/projections/PJ_vandg2.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - int vdg3; -}; -} // anonymous namespace - -PROJ_HEAD(vandg2, "van der Grinten II") "\n\tMisc Sph, no inv"; -PROJ_HEAD(vandg3, "van der Grinten III") "\n\tMisc Sph, no inv"; - -#define TOL 1e-10 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double x1, at, bt, ct; - - bt = fabs(M_TWO_D_PI * lp.phi); - if ((ct = 1. - bt * bt) < 0.) - ct = 0.; - else - ct = sqrt(ct); - if (fabs(lp.lam) < TOL) { - xy.x = 0.; - xy.y = M_PI * (lp.phi < 0. ? -bt : bt) / (1. + ct); - } else { - at = 0.5 * fabs(M_PI / lp.lam - lp.lam / M_PI); - if (Q->vdg3) { - x1 = bt / (1. + ct); - xy.x = M_PI * (sqrt(at * at + 1. - x1 * x1) - at); - xy.y = M_PI * x1; - } else { - x1 = (ct * sqrt(1. + at * at) - at * ct * ct) / - (1. + at * at * bt * bt); - xy.x = M_PI * x1; - xy.y = M_PI * sqrt(1. - x1 * (x1 + 2. * at) + TOL); - } - if ( lp.lam < 0.) xy.x = -xy.x; - if ( lp.phi < 0.) xy.y = -xy.y; - } - - return xy; -} - - -PJ *PROJECTION(vandg2) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->vdg3 = 0; - P->fwd = s_forward; - - return P; -} - -PJ *PROJECTION(vandg3) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - Q->vdg3 = 1; - P->es = 0.; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_vandg4.cpp b/src/projections/PJ_vandg4.cpp deleted file mode 100644 index d9a53c87..00000000 --- a/src/projections/PJ_vandg4.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(vandg4, "van der Grinten IV") "\n\tMisc Sph, no inv"; - -#define TOL 1e-10 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - double x1, t, bt, ct, ft, bt2, ct2, dt, dt2; - (void) P; - - if (fabs(lp.phi) < TOL) { - xy.x = lp.lam; - xy.y = 0.; - } else if (fabs(lp.lam) < TOL || fabs(fabs(lp.phi) - M_HALFPI) < TOL) { - xy.x = 0.; - xy.y = lp.phi; - } else { - bt = fabs(M_TWO_D_PI * lp.phi); - bt2 = bt * bt; - ct = 0.5 * (bt * (8. - bt * (2. + bt2)) - 5.) - / (bt2 * (bt - 1.)); - ct2 = ct * ct; - dt = M_TWO_D_PI * lp.lam; - dt = dt + 1. / dt; - dt = sqrt(dt * dt - 4.); - if ((fabs(lp.lam) - M_HALFPI) < 0.) dt = -dt; - dt2 = dt * dt; - x1 = bt + ct; x1 *= x1; - t = bt + 3.*ct; - ft = x1 * (bt2 + ct2 * dt2 - 1.) + (1.-bt2) * ( - bt2 * (t * t + 4. * ct2) + - ct2 * (12. * bt * ct + 4. * ct2) ); - x1 = (dt*(x1 + ct2 - 1.) + 2.*sqrt(ft)) / - (4.* x1 + dt2); - xy.x = M_HALFPI * x1; - xy.y = M_HALFPI * sqrt(1. + dt * fabs(x1) - x1 * x1); - if (lp.lam < 0.) xy.x = -xy.x; - if (lp.phi < 0.) xy.y = -xy.y; - } - return xy; -} - - -PJ *PROJECTION(vandg4) { - P->es = 0.; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_wag2.cpp b/src/projections/PJ_wag2.cpp deleted file mode 100644 index 1bee737a..00000000 --- a/src/projections/PJ_wag2.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(wag2, "Wagner II") "\n\tPCyl, Sph"; - -#define C_x 0.92483 -#define C_y 1.38725 -#define C_p1 0.88022 -#define C_p2 0.88550 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - lp.phi = aasin (P->ctx,C_p1 * sin (C_p2 * lp.phi)); - xy.x = C_x * lp.lam * cos (lp.phi); - xy.y = C_y * lp.phi; - return (xy); -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - lp.phi = xy.y / C_y; - lp.lam = xy.x / (C_x * cos(lp.phi)); - lp.phi = aasin (P->ctx,sin(lp.phi) / C_p1) / C_p2; - return (lp); -} - - -PJ *PROJECTION(wag2) { - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - return P; -} diff --git a/src/projections/PJ_wag3.cpp b/src/projections/PJ_wag3.cpp deleted file mode 100644 index bb1b4d49..00000000 --- a/src/projections/PJ_wag3.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(wag3, "Wagner III") "\n\tPCyl, Sph\n\tlat_ts="; - -#define TWOTHIRD 0.6666666666666666666667 - -namespace { // anonymous namespace -struct pj_opaque { - double C_x; -}; -} // anonymous namespace - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - xy.x = static_cast(P->opaque)->C_x * lp.lam * cos(TWOTHIRD * lp.phi); - xy.y = lp.phi; - return xy; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - lp.phi = xy.y; - lp.lam = xy.x / (static_cast(P->opaque)->C_x * cos(TWOTHIRD * lp.phi)); - return lp; -} - - -PJ *PROJECTION(wag3) { - double ts; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - - P->opaque = Q; - - ts = pj_param (P->ctx, P->params, "rlat_ts").f; - static_cast(P->opaque)->C_x = cos (ts) / cos (2.*ts/3.); - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_wag7.cpp b/src/projections/PJ_wag7.cpp deleted file mode 100644 index c8807f12..00000000 --- a/src/projections/PJ_wag7.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#define PJ_LIB__ - -#include - -#include "projects.h" - -PROJ_HEAD(wag7, "Wagner VII") "\n\tMisc Sph, no inv"; - - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - double theta, ct, D; - - (void) P; /* Shut up compiler warnnings about unused P */ - - theta = asin (xy.y = 0.90630778703664996 * sin(lp.phi)); - xy.x = 2.66723 * (ct = cos (theta)) * sin (lp.lam /= 3.); - xy.y *= 1.24104 * (D = 1/(sqrt (0.5 * (1 + ct * cos (lp.lam))))); - xy.x *= D; - return (xy); -} - - -PJ *PROJECTION(wag7) { - P->fwd = s_forward; - P->inv = nullptr; - P->es = 0.; - return P; -} diff --git a/src/projections/PJ_wink1.cpp b/src/projections/PJ_wink1.cpp deleted file mode 100644 index de2f55ee..00000000 --- a/src/projections/PJ_wink1.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(wink1, "Winkel I") "\n\tPCyl, Sph\n\tlat_ts="; - -namespace { // anonymous namespace -struct pj_opaque { - double cosphi1; -}; -} // anonymous namespace - - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - xy.x = .5 * lp.lam * (static_cast(P->opaque)->cosphi1 + cos(lp.phi)); - xy.y = lp.phi; - return (xy); -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - lp.phi = xy.y; - lp.lam = 2. * xy.x / (static_cast(P->opaque)->cosphi1 + cos(lp.phi)); - return (lp); -} - - -PJ *PROJECTION(wink1) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - static_cast(P->opaque)->cosphi1 = cos (pj_param(P->ctx, P->params, "rlat_ts").f); - P->es = 0.; - P->inv = s_inverse; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/PJ_wink2.cpp b/src/projections/PJ_wink2.cpp deleted file mode 100644 index 74a47283..00000000 --- a/src/projections/PJ_wink2.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -PROJ_HEAD(wink2, "Winkel II") "\n\tPCyl, Sph, no inv\n\tlat_1="; - -namespace { // anonymous namespace -struct pj_opaque { - double cosphi1; -}; -} // anonymous namespace - -#define MAX_ITER 10 -#define LOOP_TOL 1e-7 - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0, 0.0}; - double k, V; - int i; - - xy.y = lp.phi * M_TWO_D_PI; - k = M_PI * sin (lp.phi); - lp.phi *= 1.8; - for (i = MAX_ITER; i ; --i) { - lp.phi -= V = (lp.phi + sin (lp.phi) - k) / - (1. + cos (lp.phi)); - if (fabs (V) < LOOP_TOL) - break; - } - if (!i) - lp.phi = (lp.phi < 0.) ? -M_HALFPI : M_HALFPI; - else - lp.phi *= 0.5; - xy.x = 0.5 * lp.lam * (cos (lp.phi) + static_cast(P->opaque)->cosphi1); - xy.y = M_FORTPI * (sin (lp.phi) + xy.y); - return xy; -} - - -PJ *PROJECTION(wink2) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - static_cast(P->opaque)->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f); - P->es = 0.; - P->inv = nullptr; - P->fwd = s_forward; - - return P; -} diff --git a/src/projections/aea.cpp b/src/projections/aea.cpp new file mode 100644 index 00000000..c4a4a72a --- /dev/null +++ b/src/projections/aea.cpp @@ -0,0 +1,224 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the aea (Albers Equal Area) projection. + * and the leac (Lambert Equal Area Conic) projection + * Author: Gerald Evenden (1995) + * Thomas Knudsen (2016) - revise/add regression tests + * + ****************************************************************************** + * Copyright (c) 1995, Gerald Evenden + * + * 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. + *****************************************************************************/ + +#define PJ_LIB__ +#include "proj.h" +#include +#include "projects.h" +#include "proj_math.h" + + +# define EPS10 1.e-10 +# define TOL7 1.e-7 + +PROJ_HEAD(aea, "Albers Equal Area") "\n\tConic Sph&Ell\n\tlat_1= lat_2="; +PROJ_HEAD(leac, "Lambert Equal Area Conic") "\n\tConic, Sph&Ell\n\tlat_1= south"; + + +/* determine latitude angle phi-1 */ +# define N_ITER 15 +# define EPSILON 1.0e-7 +# define TOL 1.0e-10 +static double phi1_(double qs, double Te, double Tone_es) { + int i; + double Phi, sinpi, cospi, con, com, dphi; + + Phi = asin (.5 * qs); + if (Te < EPSILON) + return( Phi ); + i = N_ITER; + do { + sinpi = sin (Phi); + cospi = cos (Phi); + con = Te * sinpi; + com = 1. - con * con; + dphi = .5 * com * com / cospi * (qs / Tone_es - + sinpi / com + .5 / Te * log ((1. - con) / + (1. + con))); + Phi += dphi; + } while (fabs(dphi) > TOL && --i); + return( i ? Phi : HUGE_VAL ); +} + + +namespace { // anonymous namespace +struct pj_opaque { + double ec; + double n; + double c; + double dd; + double n2; + double rho0; + double rho; + double phi1; + double phi2; + double *en; + int ellips; +}; +} // anonymous namespace + + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + + + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoid/spheroid, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + Q->rho = Q->c - (Q->ellips ? Q->n * pj_qsfn(sin(lp.phi), P->e, P->one_es) : Q->n2 * sin(lp.phi));; + if (Q->rho < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + Q->rho = Q->dd * sqrt(Q->rho); + xy.x = Q->rho * sin( lp.lam *= Q->n ); + xy.y = Q->rho0 - Q->rho * cos(lp.lam); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoid/spheroid, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + if( (Q->rho = hypot(xy.x, xy.y = Q->rho0 - xy.y)) != 0.0 ) { + if (Q->n < 0.) { + Q->rho = -Q->rho; + xy.x = -xy.x; + xy.y = -xy.y; + } + lp.phi = Q->rho / Q->dd; + if (Q->ellips) { + lp.phi = (Q->c - lp.phi * lp.phi) / Q->n; + if (fabs(Q->ec - fabs(lp.phi)) > TOL7) { + if ((lp.phi = phi1_(lp.phi, P->e, P->one_es)) == HUGE_VAL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + } else + lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; + } else if (fabs(lp.phi = (Q->c - lp.phi * lp.phi) / Q->n2) <= 1.) + lp.phi = asin(lp.phi); + else + lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; + lp.lam = atan2(xy.x, xy.y) / Q->n; + } else { + lp.lam = 0.; + lp.phi = Q->n > 0. ? M_HALFPI : - M_HALFPI; + } + return lp; +} + + + +static PJ *setup(PJ *P) { + double cosphi, sinphi; + int secant; + struct pj_opaque *Q = static_cast(P->opaque); + + P->inv = e_inverse; + P->fwd = e_forward; + + if (fabs(Q->phi1 + Q->phi2) < EPS10) + return destructor(P, PJD_ERR_CONIC_LAT_EQUAL); + Q->n = sinphi = sin(Q->phi1); + cosphi = cos(Q->phi1); + secant = fabs(Q->phi1 - Q->phi2) >= EPS10; + if( (Q->ellips = (P->es > 0.))) { + double ml1, m1; + + if (!(Q->en = pj_enfn(P->es))) + return destructor(P, 0); + m1 = pj_msfn(sinphi, cosphi, P->es); + ml1 = pj_qsfn(sinphi, P->e, P->one_es); + if (secant) { /* secant cone */ + double ml2, m2; + + sinphi = sin(Q->phi2); + cosphi = cos(Q->phi2); + m2 = pj_msfn(sinphi, cosphi, P->es); + ml2 = pj_qsfn(sinphi, P->e, P->one_es); + if (ml2 == ml1) + return destructor(P, 0); + + Q->n = (m1 * m1 - m2 * m2) / (ml2 - ml1); + } + Q->ec = 1. - .5 * P->one_es * log((1. - P->e) / + (1. + P->e)) / P->e; + Q->c = m1 * m1 + Q->n * ml1; + Q->dd = 1. / Q->n; + Q->rho0 = Q->dd * sqrt(Q->c - Q->n * pj_qsfn(sin(P->phi0), + P->e, P->one_es)); + } else { + if (secant) Q->n = .5 * (Q->n + sin(Q->phi2)); + Q->n2 = Q->n + Q->n; + Q->c = cosphi * cosphi + Q->n2 * sinphi; + Q->dd = 1. / Q->n; + Q->rho0 = Q->dd * sqrt(Q->c - Q->n2 * sin(P->phi0)); + } + + return P; +} + + +PJ *PROJECTION(aea) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; + Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; + return setup(P); +} + + +PJ *PROJECTION(leac) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + Q->phi2 = pj_param(P->ctx, P->params, "rlat_1").f; + Q->phi1 = pj_param(P->ctx, P->params, "bsouth").i ? - M_HALFPI: M_HALFPI; + return setup(P); +} + diff --git a/src/projections/aeqd.cpp b/src/projections/aeqd.cpp new file mode 100644 index 00000000..1a350d90 --- /dev/null +++ b/src/projections/aeqd.cpp @@ -0,0 +1,327 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the aeqd (Azimuthal Equidistant) projection. + * Author: Gerald Evenden + * + ****************************************************************************** + * Copyright (c) 1995, Gerald Evenden + * + * 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. + *****************************************************************************/ + +#define PJ_LIB__ +#include "geodesic.h" +#include "proj.h" +#include +#include "projects.h" +#include "proj_math.h" + +namespace { // anonymous namespace +enum Mode { + N_POLE = 0, + S_POLE = 1, + EQUIT = 2, + OBLIQ = 3 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double sinph0; + double cosph0; + double *en; + double M1; + double N1; + double Mp; + double He; + double G; + enum Mode mode; + struct geod_geodesic g; +}; +} // anonymous namespace + +PROJ_HEAD(aeqd, "Azimuthal Equidistant") "\n\tAzi, Sph&Ell\n\tlat_0 guam"; + +#define EPS10 1.e-10 +#define TOL 1.e-14 + + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + + +static XY e_guam_fwd(LP lp, PJ *P) { /* Guam elliptical */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cosphi, sinphi, t; + + cosphi = cos(lp.phi); + sinphi = sin(lp.phi); + t = 1. / sqrt(1. - P->es * sinphi * sinphi); + xy.x = lp.lam * cosphi * t; + xy.y = pj_mlfn(lp.phi, sinphi, cosphi, Q->en) - Q->M1 + + .5 * lp.lam * lp.lam * cosphi * sinphi * t; + + return xy; +} + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, cosphi, sinphi, rho; + double azi1, azi2, s12; + double lam1, phi1, lam2, phi2; + + coslam = cos(lp.lam); + cosphi = cos(lp.phi); + sinphi = sin(lp.phi); + switch (Q->mode) { + case N_POLE: + coslam = - coslam; + /*-fallthrough*/ + case S_POLE: + xy.x = (rho = fabs(Q->Mp - pj_mlfn(lp.phi, sinphi, cosphi, Q->en))) * + sin(lp.lam); + xy.y = rho * coslam; + break; + case EQUIT: + case OBLIQ: + if (fabs(lp.lam) < EPS10 && fabs(lp.phi - P->phi0) < EPS10) { + xy.x = xy.y = 0.; + break; + } + + phi1 = P->phi0 / DEG_TO_RAD; lam1 = P->lam0 / DEG_TO_RAD; + phi2 = lp.phi / DEG_TO_RAD; lam2 = (lp.lam+P->lam0) / DEG_TO_RAD; + + geod_inverse(&Q->g, phi1, lam1, phi2, lam2, &s12, &azi1, &azi2); + azi1 *= DEG_TO_RAD; + xy.x = s12 * sin(azi1) / P->a; + xy.y = s12 * cos(azi1) / P->a; + break; + } + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, cosphi, sinphi; + + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + coslam = cos(lp.lam); + switch (Q->mode) { + case EQUIT: + xy.y = cosphi * coslam; + goto oblcon; + case OBLIQ: + xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam; +oblcon: + if (fabs(fabs(xy.y) - 1.) < TOL) + if (xy.y < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + else + xy.x = xy.y = 0.; + else { + xy.y = acos(xy.y); + xy.y /= sin(xy.y); + xy.x = xy.y * cosphi * sin(lp.lam); + xy.y *= (Q->mode == EQUIT) ? sinphi : + Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam; + } + break; + case N_POLE: + lp.phi = -lp.phi; + coslam = -coslam; + /*-fallthrough*/ + case S_POLE: + if (fabs(lp.phi - M_HALFPI) < EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.x = (xy.y = (M_HALFPI + lp.phi)) * sin(lp.lam); + xy.y *= coslam; + break; + } + return xy; +} + + +static LP e_guam_inv(XY xy, PJ *P) { /* Guam elliptical */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double x2, t = 0.0; + int i; + + x2 = 0.5 * xy.x * xy.x; + lp.phi = P->phi0; + for (i = 0; i < 3; ++i) { + t = P->e * sin(lp.phi); + lp.phi = pj_inv_mlfn(P->ctx, Q->M1 + xy.y - + x2 * tan(lp.phi) * (t = sqrt(1. - t * t)), P->es, Q->en); + } + lp.lam = xy.x * t / cos(lp.phi); + return lp; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double c; + double azi1, azi2, s12, x2, y2, lat1, lon1, lat2, lon2; + + if ((c = hypot(xy.x, xy.y)) < EPS10) { + lp.phi = P->phi0; + lp.lam = 0.; + return (lp); + } + if (Q->mode == OBLIQ || Q->mode == EQUIT) { + + x2 = xy.x * P->a; + y2 = xy.y * P->a; + lat1 = P->phi0 / DEG_TO_RAD; + lon1 = P->lam0 / DEG_TO_RAD; + azi1 = atan2(x2, y2) / DEG_TO_RAD; + s12 = sqrt(x2 * x2 + y2 * y2); + geod_direct(&Q->g, lat1, lon1, azi1, s12, &lat2, &lon2, &azi2); + lp.phi = lat2 * DEG_TO_RAD; + lp.lam = lon2 * DEG_TO_RAD; + lp.lam -= P->lam0; + } else { /* Polar */ + lp.phi = pj_inv_mlfn(P->ctx, Q->mode == N_POLE ? Q->Mp - c : Q->Mp + c, + P->es, Q->en); + lp.lam = atan2(xy.x, Q->mode == N_POLE ? -xy.y : xy.y); + } + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cosc, c_rh, sinc; + + if ((c_rh = hypot(xy.x, xy.y)) > M_PI) { + if (c_rh - EPS10 > M_PI) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + c_rh = M_PI; + } else if (c_rh < EPS10) { + lp.phi = P->phi0; + lp.lam = 0.; + return (lp); + } + if (Q->mode == OBLIQ || Q->mode == EQUIT) { + sinc = sin(c_rh); + cosc = cos(c_rh); + if (Q->mode == EQUIT) { + lp.phi = aasin(P->ctx, xy.y * sinc / c_rh); + xy.x *= sinc; + xy.y = cosc * c_rh; + } else { + lp.phi = aasin(P->ctx,cosc * Q->sinph0 + xy.y * sinc * Q->cosph0 / + c_rh); + xy.y = (cosc - Q->sinph0 * sin(lp.phi)) * c_rh; + xy.x *= sinc * Q->cosph0; + } + lp.lam = xy.y == 0. ? 0. : atan2(xy.x, xy.y); + } else if (Q->mode == N_POLE) { + lp.phi = M_HALFPI - c_rh; + lp.lam = atan2(xy.x, -xy.y); + } else { + lp.phi = c_rh - M_HALFPI; + lp.lam = atan2(xy.x, xy.y); + } + return lp; +} + + +PJ *PROJECTION(aeqd) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + geod_init(&Q->g, P->a, P->es / (1 + sqrt(P->one_es))); + + if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) { + Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + Q->sinph0 = P->phi0 < 0. ? -1. : 1.; + Q->cosph0 = 0.; + } else if (fabs(P->phi0) < EPS10) { + Q->mode = EQUIT; + Q->sinph0 = 0.; + Q->cosph0 = 1.; + } else { + Q->mode = OBLIQ; + Q->sinph0 = sin(P->phi0); + Q->cosph0 = cos(P->phi0); + } + if (P->es == 0.0) { + P->inv = s_inverse; + P->fwd = s_forward; + } else { + if (!(Q->en = pj_enfn(P->es))) + return pj_default_destructor (P, 0); + if (pj_param(P->ctx, P->params, "bguam").i) { + Q->M1 = pj_mlfn(P->phi0, Q->sinph0, Q->cosph0, Q->en); + P->inv = e_guam_inv; + P->fwd = e_guam_fwd; + } else { + switch (Q->mode) { + case N_POLE: + Q->Mp = pj_mlfn(M_HALFPI, 1., 0., Q->en); + break; + case S_POLE: + Q->Mp = pj_mlfn(-M_HALFPI, -1., 0., Q->en); + break; + case EQUIT: + case OBLIQ: + P->inv = e_inverse; P->fwd = e_forward; + Q->N1 = 1. / sqrt(1. - P->es * Q->sinph0 * Q->sinph0); + Q->G = Q->sinph0 * (Q->He = P->e / sqrt(P->one_es)); + Q->He *= Q->cosph0; + break; + } + P->inv = e_inverse; + P->fwd = e_forward; + } + } + + return P; +} + + diff --git a/src/projections/airy.cpp b/src/projections/airy.cpp new file mode 100644 index 00000000..0eb5efd7 --- /dev/null +++ b/src/projections/airy.cpp @@ -0,0 +1,155 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the airy (Airy) projection. + * Author: Gerald Evenden (1995) + * Thomas Knudsen (2016) - revise/add regression tests + * + ****************************************************************************** + * Copyright (c) 1995, Gerald Evenden + * + * 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. + *****************************************************************************/ + +#define PJ_LIB__ +#include "proj.h" +#include +#include "projects.h" + +PROJ_HEAD(airy, "Airy") "\n\tMisc Sph, no inv\n\tno_cut lat_b="; + + +namespace { // anonymous namespace +enum Mode { + N_POLE = 0, + S_POLE = 1, + EQUIT = 2, + OBLIQ = 3 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double p_halfpi; + double sinph0; + double cosph0; + double Cb; + enum Mode mode; + int no_cut; /* do not cut at hemisphere limit */ +}; +} // anonymous namespace + + +# define EPS 1.e-10 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double sinlam, coslam, cosphi, sinphi, t, s, Krho, cosz; + + sinlam = sin(lp.lam); + coslam = cos(lp.lam); + switch (Q->mode) { + case EQUIT: + case OBLIQ: + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + cosz = cosphi * coslam; + if (Q->mode == OBLIQ) + cosz = Q->sinph0 * sinphi + Q->cosph0 * cosz; + if (!Q->no_cut && cosz < -EPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + if (fabs(s = 1. - cosz) > EPS) { + t = 0.5 * (1. + cosz); + Krho = -log(t)/s - Q->Cb / t; + } else + Krho = 0.5 - Q->Cb; + xy.x = Krho * cosphi * sinlam; + if (Q->mode == OBLIQ) + xy.y = Krho * (Q->cosph0 * sinphi - + Q->sinph0 * cosphi * coslam); + else + xy.y = Krho * sinphi; + break; + case S_POLE: + case N_POLE: + lp.phi = fabs(Q->p_halfpi - lp.phi); + if (!Q->no_cut && (lp.phi - EPS) > M_HALFPI) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + if ((lp.phi *= 0.5) > EPS) { + t = tan(lp.phi); + Krho = -2.*(log(cos(lp.phi)) / t + t * Q->Cb); + xy.x = Krho * sinlam; + xy.y = Krho * coslam; + if (Q->mode == N_POLE) + xy.y = -xy.y; + } else + xy.x = xy.y = 0.; + } + return xy; +} + + + + +PJ *PROJECTION(airy) { + double beta; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + + P->opaque = Q; + + Q->no_cut = pj_param(P->ctx, P->params, "bno_cut").i; + beta = 0.5 * (M_HALFPI - pj_param(P->ctx, P->params, "rlat_b").f); + if (fabs(beta) < EPS) + Q->Cb = -0.5; + else { + Q->Cb = 1./tan(beta); + Q->Cb *= Q->Cb * log(cos(beta)); + } + + if (fabs(fabs(P->phi0) - M_HALFPI) < EPS) + if (P->phi0 < 0.) { + Q->p_halfpi = -M_HALFPI; + Q->mode = S_POLE; + } else { + Q->p_halfpi = M_HALFPI; + Q->mode = N_POLE; + } + else { + if (fabs(P->phi0) < EPS) + Q->mode = EQUIT; + else { + Q->mode = OBLIQ; + Q->sinph0 = sin(P->phi0); + Q->cosph0 = cos(P->phi0); + } + } + P->fwd = s_forward; + P->es = 0.; + return P; +} + + diff --git a/src/projections/aitoff.cpp b/src/projections/aitoff.cpp new file mode 100644 index 00000000..effd2c29 --- /dev/null +++ b/src/projections/aitoff.cpp @@ -0,0 +1,201 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the aitoff (Aitoff) and wintri (Winkel Tripel) + * projections. + * Author: Gerald Evenden (1995) + * Drazen Tutic, Lovro Gradiser (2015) - add inverse + * Thomas Knudsen (2016) - revise/add regression tests + * + ****************************************************************************** + * Copyright (c) 1995, Gerald Evenden + * + * 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + + +namespace { // anonymous namespace +enum Mode { + AITOFF = 0, + WINKEL_TRIPEL = 1 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double cosphi1; + enum Mode mode; +}; +} // anonymous namespace + + +PROJ_HEAD(aitoff, "Aitoff") "\n\tMisc Sph"; +PROJ_HEAD(wintri, "Winkel Tripel") "\n\tMisc Sph\n\tlat_1"; + + + +#if 0 +FORWARD(s_forward); /* spheroid */ +#endif + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double c, d; + + if((d = acos(cos(lp.phi) * cos(c = 0.5 * lp.lam))) != 0.0) {/* basic Aitoff */ + xy.x = 2. * d * cos(lp.phi) * sin(c) * (xy.y = 1. / sin(d)); + xy.y *= d * sin(lp.phi); + } else + xy.x = xy.y = 0.; + if (Q->mode == WINKEL_TRIPEL) { + xy.x = (xy.x + lp.lam * Q->cosphi1) * 0.5; + xy.y = (xy.y + lp.phi) * 0.5; + } + return (xy); +} + +/*********************************************************************************** +* +* Inverse functions added by Drazen Tutic and Lovro Gradiser based on paper: +* +* I.Özbug Biklirici and Cengizhan Ipbüker. A General Algorithm for the Inverse +* Transformation of Map Projections Using Jacobian Matrices. In Proceedings of the +* Third International Symposium Mathematical & Computational Applications, +* pages 175{182, Turkey, September 2002. +* +* Expected accuracy is defined by EPSILON = 1e-12. Should be appropriate for +* most applications of Aitoff and Winkel Tripel projections. +* +* Longitudes of 180W and 180E can be mixed in solution obtained. +* +* Inverse for Aitoff projection in poles is undefined, longitude value of 0 is assumed. +* +* Contact : dtutic@geof.hr +* Date: 2015-02-16 +* +************************************************************************************/ + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + int iter, MAXITER = 10, round = 0, MAXROUND = 20; + double EPSILON = 1e-12, D, C, f1, f2, f1p, f1l, f2p, f2l, dp, dl, sl, sp, cp, cl, x, y; + + if ((fabs(xy.x) < EPSILON) && (fabs(xy.y) < EPSILON )) { lp.phi = 0.; lp.lam = 0.; return lp; } + + /* initial values for Newton-Raphson method */ + lp.phi = xy.y; lp.lam = xy.x; + do { + iter = 0; + do { + sl = sin(lp.lam * 0.5); cl = cos(lp.lam * 0.5); + sp = sin(lp.phi); cp = cos(lp.phi); + D = cp * cl; + C = 1. - D * D; + D = acos(D) / pow(C, 1.5); + f1 = 2. * D * C * cp * sl; + f2 = D * C * sp; + f1p = 2.* (sl * cl * sp * cp / C - D * sp * sl); + f1l = cp * cp * sl * sl / C + D * cp * cl * sp * sp; + f2p = sp * sp * cl / C + D * sl * sl * cp; + f2l = 0.5 * (sp * cp * sl / C - D * sp * cp * cp * sl * cl); + if (Q->mode == WINKEL_TRIPEL) { + f1 = 0.5 * (f1 + lp.lam * Q->cosphi1); + f2 = 0.5 * (f2 + lp.phi); + f1p *= 0.5; + f1l = 0.5 * (f1l + Q->cosphi1); + f2p = 0.5 * (f2p + 1.); + f2l *= 0.5; + } + f1 -= xy.x; f2 -= xy.y; + dl = (f2 * f1p - f1 * f2p) / (dp = f1p * f2l - f2p * f1l); + dp = (f1 * f2l - f2 * f1l) / dp; + dl = fmod(dl, M_PI); /* set to interval [-M_PI, M_PI] */ + lp.phi -= dp; lp.lam -= dl; + } while ((fabs(dp) > EPSILON || fabs(dl) > EPSILON) && (iter++ < MAXITER)); + if (lp.phi > M_PI_2) lp.phi -= 2.*(lp.phi-M_PI_2); /* correct if symmetrical solution for Aitoff */ + if (lp.phi < -M_PI_2) lp.phi -= 2.*(lp.phi+M_PI_2); /* correct if symmetrical solution for Aitoff */ + if ((fabs(fabs(lp.phi) - M_PI_2) < EPSILON) && (Q->mode == AITOFF)) lp.lam = 0.; /* if pole in Aitoff, return longitude of 0 */ + + /* calculate x,y coordinates with solution obtained */ + if((D = acos(cos(lp.phi) * cos(C = 0.5 * lp.lam))) != 0.0) {/* Aitoff */ + x = 2. * D * cos(lp.phi) * sin(C) * (y = 1. / sin(D)); + y *= D * sin(lp.phi); + } else + x = y = 0.; + if (Q->mode == WINKEL_TRIPEL) { + x = (x + lp.lam * Q->cosphi1) * 0.5; + y = (y + lp.phi) * 0.5; + } + /* if too far from given values of x,y, repeat with better approximation of phi,lam */ + } while (((fabs(xy.x-x) > EPSILON) || (fabs(xy.y-y) > EPSILON)) && (round++ < MAXROUND)); + + if (iter == MAXITER && round == MAXROUND) + { + pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + /* fprintf(stderr, "Warning: Accuracy of 1e-12 not reached. Last increments: dlat=%e and dlon=%e\n", dp, dl); */ + } + + return lp; +} + + +static PJ *setup(PJ *P) { + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + return P; +} + + +PJ *PROJECTION(aitoff) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + Q->mode = AITOFF; + return setup(P); +} + + +PJ *PROJECTION(wintri) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + Q->mode = WINKEL_TRIPEL; + if (pj_param(P->ctx, P->params, "tlat_1").i) { + if ((Q->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f)) == 0.) + return pj_default_destructor (P, PJD_ERR_LAT_LARGER_THAN_90); + } + else /* 50d28' or acos(2/pi) */ + Q->cosphi1 = 0.636619772367581343; + return setup(P); +} diff --git a/src/projections/august.cpp b/src/projections/august.cpp new file mode 100644 index 00000000..b5a21ef7 --- /dev/null +++ b/src/projections/august.cpp @@ -0,0 +1,34 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(august, "August Epicycloidal") "\n\tMisc Sph, no inv"; +#define M 1.333333333333333 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double t, c1, c, x1, x12, y1, y12; + (void) P; + + t = tan(.5 * lp.phi); + c1 = sqrt(1. - t * t); + c = 1. + c1 * cos(lp.lam *= .5); + x1 = sin(lp.lam) * c1 / c; + y1 = t / c; + xy.x = M * x1 * (3. + (x12 = x1 * x1) - 3. * (y12 = y1 * y1)); + xy.y = M * y1 * (3. + 3. * x12 - y12); + return (xy); +} + + + + +PJ *PROJECTION(august) { + P->inv = nullptr; + P->fwd = s_forward; + P->es = 0.; + return P; +} diff --git a/src/projections/bacon.cpp b/src/projections/bacon.cpp new file mode 100644 index 00000000..6c6350fe --- /dev/null +++ b/src/projections/bacon.cpp @@ -0,0 +1,81 @@ +# define HLFPI2 2.46740110027233965467 /* (pi/2)^2 */ +# define EPS 1e-10 +#define PJ_LIB__ +#include +#include + +#include "projects.h" + + +namespace { // anonymous namespace +struct pj_opaque { + int bacn; + int ortl; +}; +} // anonymous namespace + +PROJ_HEAD(apian, "Apian Globular I") "\n\tMisc Sph, no inv"; +PROJ_HEAD(ortel, "Ortelius Oval") "\n\tMisc Sph, no inv"; +PROJ_HEAD(bacon, "Bacon Globular") "\n\tMisc Sph, no inv"; + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double ax, f; + + xy.y = Q->bacn ? M_HALFPI * sin(lp.phi) : lp.phi; + if ((ax = fabs(lp.lam)) >= EPS) { + if (Q->ortl && ax >= M_HALFPI) + xy.x = sqrt(HLFPI2 - lp.phi * lp.phi + EPS) + ax - M_HALFPI; + else { + f = 0.5 * (HLFPI2 / ax + ax); + xy.x = ax - f + sqrt(f * f - xy.y * xy.y); + } + if (lp.lam < 0.) xy.x = - xy.x; + } else + xy.x = 0.; + return (xy); +} + + + +PJ *PROJECTION(bacon) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->bacn = 1; + Q->ortl = 0; + P->es = 0.; + P->fwd = s_forward; + return P; +} + + +PJ *PROJECTION(apian) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->bacn = Q->ortl = 0; + P->es = 0.; + P->fwd = s_forward; + return P; +} + + +PJ *PROJECTION(ortel) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->bacn = 0; + Q->ortl = 1; + P->es = 0.; + P->fwd = s_forward; + return P; +} diff --git a/src/projections/bertin1953.cpp b/src/projections/bertin1953.cpp new file mode 100644 index 00000000..2203d6f1 --- /dev/null +++ b/src/projections/bertin1953.cpp @@ -0,0 +1,96 @@ +/* + Created by Jacques Bertin in 1953, this projection was the go-to choice + of the French cartographic school when they wished to represent phenomena + on a global scale. + + Formula designed by Philippe Rivière, 2017. + https://visionscarto.net/bertin-projection-1953 + + Port to PROJ by Philippe Rivière, 21 September 2018 +*/ + +#define PJ_LIB__ + +#include +#include + +#include "proj_internal.h" +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(bertin1953, "Bertin 1953") + "\n\tMisc Sph no inv."; + +namespace { // anonymous namespace +struct pj_opaque { + double cos_delta_phi, sin_delta_phi, cos_delta_gamma, sin_delta_gamma, deltaLambda; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + double fu = 1.4, k = 12., w = 1.68, d; + + /* Rotate */ + double cosphi, x, y, z, z0; + lp.lam += PJ_TORAD(-16.5); + cosphi = cos(lp.phi); + x = cos(lp.lam) * cosphi; + y = sin(lp.lam) * cosphi; + z = sin(lp.phi); + z0 = z * Q->cos_delta_phi + x * Q->sin_delta_phi; + lp.lam = atan2(y * Q->cos_delta_gamma - z0 * Q->sin_delta_gamma, + x * Q->cos_delta_phi - z * Q->sin_delta_phi); + z0 = z0 * Q->cos_delta_gamma + y * Q->sin_delta_gamma; + lp.phi = asin(z0); + + lp.lam = adjlon(lp.lam); + + /* Adjust pre-projection */ + if (lp.lam + lp.phi < -fu) { + d = (lp.lam - lp.phi + 1.6) * (lp.lam + lp.phi + fu) / 8.; + lp.lam += d; + lp.phi -= 0.8 * d * sin(lp.phi + M_PI / 2.); + } + + /* Project with Hammer (1.68,2) */ + cosphi = cos(lp.phi); + d = sqrt(2./(1. + cosphi * cos(lp.lam / 2.))); + xy.x = w * d * cosphi * sin(lp.lam / 2.); + xy.y = d * sin(lp.phi); + + /* Adjust post-projection */ + d = (1. - cos(lp.lam * lp.phi)) / k; + if (xy.y < 0.) { + xy.x *= 1. + d; + } + if (xy.y > 0.) { + xy.x *= 1. + d / 1.5 * xy.x * xy.x; + } + + return xy; +} + + +PJ *PROJECTION(bertin1953) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + P->lam0 = 0; + P->phi0 = PJ_TORAD(-42.); + + Q->cos_delta_phi = cos(P->phi0); + Q->sin_delta_phi = sin(P->phi0); + Q->cos_delta_gamma = 1.; + Q->sin_delta_gamma = 0.; + + P->es = 0.; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/bipc.cpp b/src/projections/bipc.cpp new file mode 100644 index 00000000..19a6bbe1 --- /dev/null +++ b/src/projections/bipc.cpp @@ -0,0 +1,176 @@ +#define PJ_LIB__ +#include +#include + +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +PROJ_HEAD(bipc, "Bipolar conic of western hemisphere") "\n\tConic Sph"; + +# define EPS 1e-10 +# define EPS10 1e-10 +# define ONEEPS 1.000000001 +# define NITER 10 +# define lamB -.34894976726250681539 +# define n .63055844881274687180 +# define F 1.89724742567461030582 +# define Azab .81650043674686363166 +# define Azba 1.82261843856185925133 +# define T 1.27246578267089012270 +# define rhoc 1.20709121521568721927 +# define cAzc .69691523038678375519 +# define sAzc .71715351331143607555 +# define C45 .70710678118654752469 +# define S45 .70710678118654752410 +# define C20 .93969262078590838411 +# define S20 -.34202014332566873287 +# define R110 1.91986217719376253360 +# define R104 1.81514242207410275904 + + +namespace { // anonymous namespace +struct pj_opaque { + int noskew; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cphi, sphi, tphi, t, al, Az, z, Av, cdlam, sdlam, r; + int tag; + + cphi = cos(lp.phi); + sphi = sin(lp.phi); + cdlam = cos(sdlam = lamB - lp.lam); + sdlam = sin(sdlam); + if (fabs(fabs(lp.phi) - M_HALFPI) < EPS10) { + Az = lp.phi < 0. ? M_PI : 0.; + tphi = HUGE_VAL; + } else { + tphi = sphi / cphi; + Az = atan2(sdlam , C45 * (tphi - cdlam)); + } + if( (tag = (Az > Azba)) ) { + cdlam = cos(sdlam = lp.lam + R110); + sdlam = sin(sdlam); + z = S20 * sphi + C20 * cphi * cdlam; + if (fabs(z) > 1.) { + if (fabs(z) > ONEEPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + else z = z < 0. ? -1. : 1.; + } else + z = acos(z); + if (tphi != HUGE_VAL) + Az = atan2(sdlam, (C20 * tphi - S20 * cdlam)); + Av = Azab; + xy.y = rhoc; + } else { + z = S45 * (sphi + cphi * cdlam); + if (fabs(z) > 1.) { + if (fabs(z) > ONEEPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + else z = z < 0. ? -1. : 1.; + } else + z = acos(z); + Av = Azba; + xy.y = -rhoc; + } + if (z < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + r = F * (t = pow(tan(.5 * z), n)); + if ((al = .5 * (R104 - z)) < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + al = (t + pow(al, n)) / T; + if (fabs(al) > 1.) { + if (fabs(al) > ONEEPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + else al = al < 0. ? -1. : 1.; + } else + al = acos(al); + if (fabs(t = n * (Av - Az)) < al) + r /= cos(al + (tag ? t : -t)); + xy.x = r * sin(t); + xy.y += (tag ? -r : r) * cos(t); + if (Q->noskew) { + t = xy.x; + xy.x = -xy.x * cAzc - xy.y * sAzc; + xy.y = -xy.y * cAzc + t * sAzc; + } + return (xy); +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double t, r, rp, rl, al, z = 0.0, fAz, Az, s, c, Av; + int neg, i; + + if (Q->noskew) { + t = xy.x; + xy.x = -xy.x * cAzc + xy.y * sAzc; + xy.y = -xy.y * cAzc - t * sAzc; + } + if( (neg = (xy.x < 0.)) ) { + xy.y = rhoc - xy.y; + s = S20; + c = C20; + Av = Azab; + } else { + xy.y += rhoc; + s = S45; + c = C45; + Av = Azba; + } + rl = rp = r = hypot(xy.x, xy.y); + fAz = fabs(Az = atan2(xy.x, xy.y)); + for (i = NITER; i ; --i) { + z = 2. * atan(pow(r / F,1 / n)); + al = acos((pow(tan(.5 * z), n) + + pow(tan(.5 * (R104 - z)), n)) / T); + if (fAz < al) + r = rp * cos(al + (neg ? Az : -Az)); + if (fabs(rl - r) < EPS) + break; + rl = r; + } + if (! i) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + Az = Av - Az / n; + lp.phi = asin(s * cos(z) + c * sin(z) * cos(Az)); + lp.lam = atan2(sin(Az), c / tan(z) - s * cos(Az)); + if (neg) + lp.lam -= R110; + else + lp.lam = lamB - lp.lam; + return (lp); +} + + +PJ *PROJECTION(bipc) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->noskew = pj_param(P->ctx, P->params, "bns").i; + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + return P; +} diff --git a/src/projections/boggs.cpp b/src/projections/boggs.cpp new file mode 100644 index 00000000..119357c0 --- /dev/null +++ b/src/projections/boggs.cpp @@ -0,0 +1,43 @@ +#define PJ_LIB__ +#include + +#include "projects.h" + +PROJ_HEAD(boggs, "Boggs Eumorphic") "\n\tPCyl, no inv, Sph"; +# define NITER 20 +# define EPS 1e-7 +# define FXC 2.00276 +# define FXC2 1.11072 +# define FYC 0.49931 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double theta, th1, c; + int i; + (void) P; + + theta = lp.phi; + if (fabs(fabs(lp.phi) - M_HALFPI) < EPS) + xy.x = 0.; + else { + c = sin(theta) * M_PI; + for (i = NITER; i; --i) { + theta -= th1 = (theta + sin(theta) - c) / + (1. + cos(theta)); + if (fabs(th1) < EPS) break; + } + theta *= 0.5; + xy.x = FXC * lp.lam / (1. / cos(lp.phi) + FXC2 / cos(theta)); + } + xy.y = FYC * (lp.phi + M_SQRT2 * sin(theta)); + return (xy); +} + + + +PJ *PROJECTION(boggs) { + P->es = 0.; + P->fwd = s_forward; + return P; +} diff --git a/src/projections/bonne.cpp b/src/projections/bonne.cpp new file mode 100644 index 00000000..385c1c4b --- /dev/null +++ b/src/projections/bonne.cpp @@ -0,0 +1,136 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + + +PROJ_HEAD(bonne, "Bonne (Werner lat_1=90)") + "\n\tConic Sph&Ell\n\tlat_1="; +#define EPS10 1e-10 + +namespace { // anonymous namespace +struct pj_opaque { + double phi1; + double cphi1; + double am1; + double m1; + double *en; +}; +} // anonymous namespace + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double rh, E, c; + + rh = Q->am1 + Q->m1 - pj_mlfn(lp.phi, E = sin(lp.phi), c = cos(lp.phi), Q->en); + E = c * lp.lam / (rh * sqrt(1. - P->es * E * E)); + xy.x = rh * sin(E); + xy.y = Q->am1 - rh * cos(E); + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double E, rh; + + rh = Q->cphi1 + Q->phi1 - lp.phi; + if (fabs(rh) > EPS10) { + xy.x = rh * sin(E = lp.lam * cos(lp.phi) / rh); + xy.y = Q->cphi1 - rh * cos(E); + } else + xy.x = xy.y = 0.; + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double rh; + + rh = hypot(xy.x, xy.y = Q->cphi1 - xy.y); + lp.phi = Q->cphi1 + Q->phi1 - rh; + if (fabs(lp.phi) > M_HALFPI) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) + lp.lam = 0.; + else + lp.lam = rh * atan2(xy.x, xy.y) / cos(lp.phi); + return lp; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double s, rh; + + rh = hypot(xy.x, xy.y = Q->am1 - xy.y); + lp.phi = pj_inv_mlfn(P->ctx, Q->am1 + Q->m1 - rh, P->es, Q->en); + if ((s = fabs(lp.phi)) < M_HALFPI) { + s = sin(lp.phi); + lp.lam = rh * atan2(xy.x, xy.y) * + sqrt(1. - P->es * s * s) / cos(lp.phi); + } else if (fabs(s - M_HALFPI) <= EPS10) + lp.lam = 0.; + else { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + return lp; +} + + + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + +PJ *PROJECTION(bonne) { + double c; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; + if (fabs(Q->phi1) < EPS10) + return destructor (P, PJD_ERR_LAT1_IS_ZERO); + + if (P->es != 0.0) { + Q->en = pj_enfn(P->es); + if (nullptr==Q->en) + return destructor(P, ENOMEM); + Q->m1 = pj_mlfn(Q->phi1, Q->am1 = sin(Q->phi1), + c = cos(Q->phi1), Q->en); + Q->am1 = c / (sqrt(1. - P->es * Q->am1 * Q->am1) * Q->am1); + P->inv = e_inverse; + P->fwd = e_forward; + } else { + if (fabs(Q->phi1) + EPS10 >= M_HALFPI) + Q->cphi1 = 0.; + else + Q->cphi1 = 1. / tan(Q->phi1); + P->inv = s_inverse; + P->fwd = s_forward; + } + return P; +} + + diff --git a/src/projections/calcofi.cpp b/src/projections/calcofi.cpp new file mode 100644 index 00000000..e81e4d2a --- /dev/null +++ b/src/projections/calcofi.cpp @@ -0,0 +1,163 @@ +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" +#include "proj_api.h" + +PROJ_HEAD(calcofi, + "Cal Coop Ocean Fish Invest Lines/Stations") "\n\tCyl, Sph&Ell"; + + +/* Conversions for the California Cooperative Oceanic Fisheries Investigations +Line/Station coordinate system following the algorithm of: +Eber, L.E., and R.P. Hewitt. 1979. Conversion algorithms for the CalCOFI +station grid. California Cooperative Oceanic Fisheries Investigations Reports +20:135-137. (corrected for typographical errors). +http://www.calcofi.org/publications/calcofireports/v20/Vol_20_Eber___Hewitt.pdf +They assume 1 unit of CalCOFI Line == 1/5 degree in longitude or +meridional units at reference point O, and similarly 1 unit of CalCOFI +Station == 1/15 of a degree at O. +By convention, CalCOFI Line/Station conversions use Clarke 1866 but we use +whatever ellipsoid is provided. */ + + +#define EPS10 1.e-10 +#define DEG_TO_LINE 5 +#define DEG_TO_STATION 15 +#define LINE_TO_RAD 0.0034906585039886592 +#define STATION_TO_RAD 0.0011635528346628863 +#define PT_O_LINE 80 /* reference point O is at line 80, */ +#define PT_O_STATION 60 /* station 60, */ +#define PT_O_LAMBDA -2.1144663887911301 /* lon -121.15 and */ +#define PT_O_PHI 0.59602993955606354 /* lat 34.15 */ +#define ROTATION_ANGLE 0.52359877559829882 /*CalCOFI angle of 30 deg in rad */ + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + double oy; /* pt O y value in Mercator */ + double l1; /* l1 and l2 are distances calculated using trig that sum + to the east/west distance between point O and point xy */ + double l2; + double ry; /* r is the point on the same station as o (60) and the same + line as xy xy, r, o form a right triangle */ + + if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + + xy.x = lp.lam; + xy.y = -log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); /* Mercator transform xy*/ + oy = -log(pj_tsfn(PT_O_PHI, sin(PT_O_PHI), P->e)); + l1 = (xy.y - oy) * tan(ROTATION_ANGLE); + l2 = -xy.x - l1 + PT_O_LAMBDA; + ry = l2 * cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE) + xy.y; + ry = pj_phi2(P->ctx, exp(-ry), P->e); /*inverse Mercator*/ + xy.x = PT_O_LINE - RAD_TO_DEG * + (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE); + xy.y = PT_O_STATION + RAD_TO_DEG * + (ry - lp.phi) * DEG_TO_STATION / sin(ROTATION_ANGLE); + /* set a = 1, x0 = 0, and y0 = 0 so that no further unit adjustments + are done */ + + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double oy; + double l1; + double l2; + double ry; + if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.x = lp.lam; + xy.y = log(tan(M_FORTPI + .5 * lp.phi)); + oy = log(tan(M_FORTPI + .5 * PT_O_PHI)); + l1 = (xy.y - oy) * tan(ROTATION_ANGLE); + l2 = -xy.x - l1 + PT_O_LAMBDA; + ry = l2 * cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE) + xy.y; + ry = M_HALFPI - 2. * atan(exp(-ry)); + xy.x = PT_O_LINE - RAD_TO_DEG * + (ry - PT_O_PHI) * DEG_TO_LINE / cos(ROTATION_ANGLE); + xy.y = PT_O_STATION + RAD_TO_DEG * + (ry - lp.phi) * DEG_TO_STATION / sin(ROTATION_ANGLE); + + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + double ry; /* y value of point r */ + double oymctr; /* Mercator-transformed y value of point O */ + double rymctr; /* Mercator-transformed ry */ + double xymctr; /* Mercator-transformed xy.y */ + double l1; + double l2; + + ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) * + cos(ROTATION_ANGLE); + lp.phi = ry - STATION_TO_RAD * (xy.y - PT_O_STATION) * sin(ROTATION_ANGLE); + oymctr = -log(pj_tsfn(PT_O_PHI, sin(PT_O_PHI), P->e)); + rymctr = -log(pj_tsfn(ry, sin(ry), P->e)); + xymctr = -log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); + l1 = (xymctr - oymctr) * tan(ROTATION_ANGLE); + l2 = (rymctr - xymctr) / (cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE)); + lp.lam = PT_O_LAMBDA - (l1 + l2); + + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double ry; + double oymctr; + double rymctr; + double xymctr; + double l1; + double l2; + (void) P; + + ry = PT_O_PHI - LINE_TO_RAD * (xy.x - PT_O_LINE) * + cos(ROTATION_ANGLE); + lp.phi = ry - STATION_TO_RAD * (xy.y - PT_O_STATION) * sin(ROTATION_ANGLE); + oymctr = log(tan(M_FORTPI + .5 * PT_O_PHI)); + rymctr = log(tan(M_FORTPI + .5 * ry)); + xymctr = log(tan(M_FORTPI + .5 * lp.phi)); + l1 = (xymctr - oymctr) * tan(ROTATION_ANGLE); + l2 = (rymctr - xymctr) / (cos(ROTATION_ANGLE) * sin(ROTATION_ANGLE)); + lp.lam = PT_O_LAMBDA - (l1 + l2); + + return lp; +} + + +PJ *PROJECTION(calcofi) { + P->opaque = nullptr; + + /* if the user has specified +lon_0 or +k0 for some reason, + we're going to ignore it so that xy is consistent with point O */ + P->lam0 = 0; + P->ra = 1; + P->a = 1; + P->x0 = 0; + P->y0 = 0; + P->over = 1; + + if (P->es != 0.0) { /* ellipsoid */ + P->inv = e_inverse; + P->fwd = e_forward; + } else { /* sphere */ + P->inv = s_inverse; + P->fwd = s_forward; + } + return P; +} diff --git a/src/projections/cass.cpp b/src/projections/cass.cpp new file mode 100644 index 00000000..c831558c --- /dev/null +++ b/src/projections/cass.cpp @@ -0,0 +1,123 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(cass, "Cassini") "\n\tCyl, Sph&Ell"; + + +# define C1 .16666666666666666666 +# define C2 .00833333333333333333 +# define C3 .04166666666666666666 +# define C4 .33333333333333333333 +# define C5 .06666666666666666666 + + +namespace { // anonymous namespace +struct pj_opaque { + double *en; + double m0; +}; +} // anonymous namespace + + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + double n, t, a1, c, a2, tn; + XY xy = {0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + xy.y = pj_mlfn (lp.phi, n = sin (lp.phi), c = cos (lp.phi), Q->en); + + n = 1./sqrt(1. - P->es * n*n); + tn = tan(lp.phi); t = tn * tn; + a1 = lp.lam * c; + c *= P->es * c / (1 - P->es); + a2 = a1 * a1; + + xy.x = n * a1 * (1. - a2 * t * + (C1 - (8. - t + 8. * c) * a2 * C2)); + xy.y -= Q->m0 - n * tn * a2 * + (.5 + (5. - t + 6. * c) * a2 * C3); + + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + xy.x = asin (cos (lp.phi) * sin (lp.lam)); + xy.y = atan2 (tan (lp.phi), cos (lp.lam)) - P->phi0; + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + double n, t, r, dd, d2, tn, ph1; + LP lp = {0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + ph1 = pj_inv_mlfn (P->ctx, Q->m0 + xy.y, P->es, Q->en); + tn = tan (ph1); t = tn*tn; + n = sin (ph1); + r = 1. / (1. - P->es * n * n); + n = sqrt (r); + r *= (1. - P->es) * n; + dd = xy.x / n; + d2 = dd * dd; + lp.phi = ph1 - (n * tn / r) * d2 * + (.5 - (1. + 3. * t) * d2 * C3); + lp.lam = dd * (1. + t * d2 * + (-C4 + (1. + 3. * t) * d2 * C5)) / cos (ph1); + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double dd; + lp.phi = asin(sin(dd = xy.y + P->phi0) * cos(xy.x)); + lp.lam = atan2(tan(xy.x), cos(dd)); + return lp; +} + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + + +PJ *PROJECTION(cass) { + + /* Spheroidal? */ + if (0==P->es) { + P->inv = s_inverse; + P->fwd = s_forward; + return P; + } + + /* otherwise it's ellipsoidal */ + P->opaque = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==P->opaque) + return pj_default_destructor (P, ENOMEM); + P->destructor = destructor; + + static_cast(P->opaque)->en = pj_enfn (P->es); + if (nullptr==static_cast(P->opaque)->en) + return pj_default_destructor (P, ENOMEM); + + static_cast(P->opaque)->m0 = pj_mlfn (P->phi0, sin (P->phi0), cos (P->phi0), static_cast(P->opaque)->en); + P->inv = e_inverse; + P->fwd = e_forward; + + return P; +} diff --git a/src/projections/cc.cpp b/src/projections/cc.cpp new file mode 100644 index 00000000..152e6e4a --- /dev/null +++ b/src/projections/cc.cpp @@ -0,0 +1,41 @@ +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(cc, "Central Cylindrical") "\n\tCyl, Sph"; +#define EPS10 1.e-10 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + if (fabs (fabs(lp.phi) - M_HALFPI) <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.x = lp.lam; + xy.y = tan(lp.phi); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + (void) P; + lp.phi = atan(xy.y); + lp.lam = xy.x; + return lp; +} + + + +PJ *PROJECTION(cc) { + P->es = 0.; + + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/ccon.cpp b/src/projections/ccon.cpp new file mode 100644 index 00000000..4f7dedb4 --- /dev/null +++ b/src/projections/ccon.cpp @@ -0,0 +1,109 @@ +/****************************************************************************** + * Copyright (c) 2017, Lukasz Komsta + * + * 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. + *****************************************************************************/ + +#define PJ_LIB__ +#include +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +#define EPS10 1e-10 + +namespace { // anonymous namespace +struct pj_opaque { + double phi1; + double ctgphi1; + double sinphi1; + double cosphi1; + double *en; +}; +} // anonymous namespace + +PROJ_HEAD(ccon, "Central Conic") + "\n\tCentral Conic, Sph\n\tlat_1="; + + + +static XY forward (LP lp, PJ *P) { + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double r; + + r = Q->ctgphi1 - tan(lp.phi - Q->phi1); + xy.x = r * sin(lp.lam * Q->sinphi1); + xy.y = Q->ctgphi1 - r * cos(lp.lam * Q->sinphi1); + + return xy; +} + + +static LP inverse (XY xy, PJ *P) { + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + xy.y = Q->ctgphi1 - xy.y; + lp.phi = Q->phi1 - atan(hypot(xy.x,xy.y) - Q->ctgphi1); + lp.lam = atan2(xy.x,xy.y)/Q->sinphi1; + + return lp; +} + + +static PJ *destructor (PJ *P, int errlev) { + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + +PJ *PROJECTION(ccon) { + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; + if (fabs(Q->phi1) < EPS10) + return destructor (P, PJD_ERR_LAT1_IS_ZERO); + + if (!(Q->en = pj_enfn(P->es))) + return destructor(P, ENOMEM); + + Q->sinphi1 = sin(Q->phi1); + Q->cosphi1 = cos(Q->phi1); + Q->ctgphi1 = Q->cosphi1/Q->sinphi1; + + + P->inv = inverse; + P->fwd = forward; + + return P; +} + + diff --git a/src/projections/cea.cpp b/src/projections/cea.cpp new file mode 100644 index 00000000..f8275b62 --- /dev/null +++ b/src/projections/cea.cpp @@ -0,0 +1,103 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + double qp; + double *apa; +}; +} // anonymous namespace + +PROJ_HEAD(cea, "Equal Area Cylindrical") "\n\tCyl, Sph&Ell\n\tlat_ts="; +# define EPS 1e-10 + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + xy.x = P->k0 * lp.lam; + xy.y = 0.5 * pj_qsfn (sin (lp.phi), P->e, P->one_es) / P->k0; + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + xy.x = P->k0 * lp.lam; + xy.y = sin(lp.phi) / P->k0; + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + lp.phi = pj_authlat(asin( 2. * xy.y * P->k0 / static_cast(P->opaque)->qp), static_cast(P->opaque)->apa); + lp.lam = xy.x / P->k0; + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double t; + + if ((t = fabs(xy.y *= P->k0)) - EPS <= 1.) { + if (t >= 1.) + lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; + else + lp.phi = asin(xy.y); + lp.lam = xy.x / P->k0; + } else { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + return (lp); +} + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->apa); + return pj_default_destructor (P, errlev); +} + + +PJ *PROJECTION(cea) { + double t = 0.0; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + + if (pj_param(P->ctx, P->params, "tlat_ts").i) { + P->k0 = cos(t = pj_param(P->ctx, P->params, "rlat_ts").f); + if (P->k0 < 0.) + return pj_default_destructor (P, PJD_ERR_LAT_TS_LARGER_THAN_90); + } + if (P->es != 0.0) { + t = sin(t); + P->k0 /= sqrt(1. - P->es * t * t); + P->e = sqrt(P->es); + if (!(Q->apa = pj_authset(P->es))) + return pj_default_destructor(P, ENOMEM); + + Q->qp = pj_qsfn(1., P->e, P->one_es); + P->inv = e_inverse; + P->fwd = e_forward; + } else { + P->inv = s_inverse; + P->fwd = s_forward; + } + + return P; +} diff --git a/src/projections/chamb.cpp b/src/projections/chamb.cpp new file mode 100644 index 00000000..a490e817 --- /dev/null +++ b/src/projections/chamb.cpp @@ -0,0 +1,141 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +typedef struct { double r, Az; } VECT; +namespace { // anonymous namespace +struct pj_opaque { + struct { /* control point data */ + double phi, lam; + double cosphi, sinphi; + VECT v; + XY p; + double Az; + } c[3]; + XY p; + double beta_0, beta_1, beta_2; +}; +} // anonymous namespace + +PROJ_HEAD(chamb, "Chamberlin Trimetric") "\n\tMisc Sph, no inv" +"\n\tlat_1= lon_1= lat_2= lon_2= lat_3= lon_3="; + +#include +#define THIRD 0.333333333333333333 +#define TOL 1e-9 + +/* distance and azimuth from point 1 to point 2 */ +static VECT vect(projCtx ctx, double dphi, double c1, double s1, double c2, double s2, double dlam) { + VECT v; + double cdl, dp, dl; + + cdl = cos(dlam); + if (fabs(dphi) > 1. || fabs(dlam) > 1.) + v.r = aacos(ctx, s1 * s2 + c1 * c2 * cdl); + else { /* more accurate for smaller distances */ + dp = sin(.5 * dphi); + dl = sin(.5 * dlam); + v.r = 2. * aasin(ctx,sqrt(dp * dp + c1 * c2 * dl * dl)); + } + if (fabs(v.r) > TOL) + v.Az = atan2(c2 * sin(dlam), c1 * s2 - s1 * c2 * cdl); + else + v.r = v.Az = 0.; + return v; +} + +/* law of cosines */ +static double lc(projCtx ctx, double b,double c,double a) { + return aacos(ctx, .5 * (b * b + c * c - a * a) / (b * c)); +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy; + struct pj_opaque *Q = static_cast(P->opaque); + double sinphi, cosphi, a; + VECT v[3]; + int i, j; + + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + for (i = 0; i < 3; ++i) { /* dist/azimiths from control */ + v[i] = vect(P->ctx, lp.phi - Q->c[i].phi, Q->c[i].cosphi, Q->c[i].sinphi, + cosphi, sinphi, lp.lam - Q->c[i].lam); + if (v[i].r == 0.0) + break; + v[i].Az = adjlon(v[i].Az - Q->c[i].v.Az); + } + if (i < 3) /* current point at control point */ + xy = Q->c[i].p; + else { /* point mean of intersepts */ + xy = Q->p; + for (i = 0; i < 3; ++i) { + j = i == 2 ? 0 : i + 1; + a = lc(P->ctx,Q->c[i].v.r, v[i].r, v[j].r); + if (v[i].Az < 0.) + a = -a; + if (! i) { /* coord comp unique to each arc */ + xy.x += v[i].r * cos(a); + xy.y -= v[i].r * sin(a); + } else if (i == 1) { + a = Q->beta_1 - a; + xy.x -= v[i].r * cos(a); + xy.y -= v[i].r * sin(a); + } else { + a = Q->beta_2 - a; + xy.x += v[i].r * cos(a); + xy.y += v[i].r * sin(a); + } + } + xy.x *= THIRD; /* mean of arc intercepts */ + xy.y *= THIRD; + } + return xy; +} + + + +PJ *PROJECTION(chamb) { + int i, j; + char line[10]; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + + for (i = 0; i < 3; ++i) { /* get control point locations */ + (void)sprintf(line, "rlat_%d", i+1); + Q->c[i].phi = pj_param(P->ctx, P->params, line).f; + (void)sprintf(line, "rlon_%d", i+1); + Q->c[i].lam = pj_param(P->ctx, P->params, line).f; + Q->c[i].lam = adjlon(Q->c[i].lam - P->lam0); + Q->c[i].cosphi = cos(Q->c[i].phi); + Q->c[i].sinphi = sin(Q->c[i].phi); + } + for (i = 0; i < 3; ++i) { /* inter ctl pt. distances and azimuths */ + j = i == 2 ? 0 : i + 1; + Q->c[i].v = vect(P->ctx,Q->c[j].phi - Q->c[i].phi, Q->c[i].cosphi, Q->c[i].sinphi, + Q->c[j].cosphi, Q->c[j].sinphi, Q->c[j].lam - Q->c[i].lam); + if (Q->c[i].v.r == 0.0) + return pj_default_destructor (P, PJD_ERR_CONTROL_POINT_NO_DIST); + /* co-linearity problem ignored for now */ + } + Q->beta_0 = lc(P->ctx,Q->c[0].v.r, Q->c[2].v.r, Q->c[1].v.r); + Q->beta_1 = lc(P->ctx,Q->c[0].v.r, Q->c[1].v.r, Q->c[2].v.r); + Q->beta_2 = M_PI - Q->beta_0; + Q->p.y = 2. * (Q->c[0].p.y = Q->c[1].p.y = Q->c[2].v.r * sin(Q->beta_0)); + Q->c[2].p.y = 0.; + Q->c[0].p.x = - (Q->c[1].p.x = 0.5 * Q->c[0].v.r); + Q->p.x = Q->c[2].p.x = Q->c[0].p.x + Q->c[2].v.r * cos(Q->beta_0); + + P->es = 0.; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/collg.cpp b/src/projections/collg.cpp new file mode 100644 index 00000000..7904de29 --- /dev/null +++ b/src/projections/collg.cpp @@ -0,0 +1,53 @@ +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(collg, "Collignon") "\n\tPCyl, Sph"; +#define FXC 1.12837916709551257390 +#define FYC 1.77245385090551602729 +#define ONEEPS 1.0000001 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + if ((xy.y = 1. - sin(lp.phi)) <= 0.) + xy.y = 0.; + else + xy.y = sqrt(xy.y); + xy.x = FXC * lp.lam * xy.y; + xy.y = FYC * (1. - xy.y); + return (xy); +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + lp.phi = xy.y / FYC - 1.; + if (fabs(lp.phi = 1. - lp.phi * lp.phi) < 1.) + lp.phi = asin(lp.phi); + else if (fabs(lp.phi) > ONEEPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } else { + lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; + } + + if ((lp.lam = 1. - sin(lp.phi)) <= 0.) + lp.lam = 0.; + else + lp.lam = xy.x / (FXC * sqrt(lp.lam)); + return (lp); +} + + +PJ *PROJECTION(collg) { + P->es = 0.0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/comill.cpp b/src/projections/comill.cpp new file mode 100644 index 00000000..b6e0192e --- /dev/null +++ b/src/projections/comill.cpp @@ -0,0 +1,84 @@ +/* +The Compact Miller projection was designed by Tom Patterson, US National +Park Service, in 2014. The polynomial equation was developed by Bojan +Savric and Bernhard Jenny, College of Earth, Ocean, and Atmospheric +Sciences, Oregon State University. +Port to PROJ.4 by Bojan Savric, 4 April 2016 +*/ + +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(comill, "Compact Miller") "\n\tCyl, Sph"; + +#define K1 0.9902 +#define K2 0.1604 +#define K3 -0.03054 +#define C1 K1 +#define C2 (3 * K2) +#define C3 (5 * K3) +#define EPS 1e-11 +#define MAX_Y (0.6000207669862655 * M_PI) +/* Not sure at all of the appropriate number for MAX_ITER... */ +#define MAX_ITER 100 + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double lat_sq; + + (void) P; /* silence unused parameter warnings */ + + lat_sq = lp.phi * lp.phi; + xy.x = lp.lam; + xy.y = lp.phi * (K1 + lat_sq * (K2 + K3 * lat_sq)); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double yc, tol, y2, f, fder; + int i; + + (void) P; /* silence unused parameter warnings */ + + /* make sure y is inside valid range */ + if (xy.y > MAX_Y) { + xy.y = MAX_Y; + } else if (xy.y < -MAX_Y) { + xy.y = -MAX_Y; + } + + /* latitude */ + yc = xy.y; + for (i = MAX_ITER; i ; --i) { /* Newton-Raphson */ + y2 = yc * yc; + f = (yc * (K1 + y2 * (K2 + K3 * y2))) - xy.y; + fder = C1 + y2 * (C2 + C3 * y2); + yc -= tol = f / fder; + if (fabs(tol) < EPS) { + break; + } + } + if( i == 0 ) + pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + lp.phi = yc; + + /* longitude */ + lp.lam = xy.x; + + return lp; +} + + +PJ *PROJECTION(comill) { + P->es = 0; + + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/crast.cpp b/src/projections/crast.cpp new file mode 100644 index 00000000..4e4dee8b --- /dev/null +++ b/src/projections/crast.cpp @@ -0,0 +1,40 @@ +#define PJ_LIB__ +#include + +#include "projects.h" + +PROJ_HEAD(crast, "Craster Parabolic (Putnins P4)") "\n\tPCyl, Sph"; + +#define XM 0.97720502380583984317 +#define RXM 1.02332670794648848847 +#define YM 3.06998012383946546542 +#define RYM 0.32573500793527994772 +#define THIRD 0.333333333333333333 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + lp.phi *= THIRD; + xy.x = XM * lp.lam * (2. * cos(lp.phi + lp.phi) - 1.); + xy.y = YM * sin(lp.phi); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + (void) P; + lp.phi = 3. * asin(xy.y * RYM); + lp.lam = xy.x * RXM / (2. * cos((lp.phi + lp.phi) * THIRD) - 1); + return lp; +} + + +PJ *PROJECTION(crast) { + P->es = 0.0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/denoy.cpp b/src/projections/denoy.cpp new file mode 100644 index 00000000..5c337c45 --- /dev/null +++ b/src/projections/denoy.cpp @@ -0,0 +1,32 @@ +#define PJ_LIB__ +#include + +#include "projects.h" + +PROJ_HEAD(denoy, "Denoyer Semi-Elliptical") "\n\tPCyl, no inv, Sph"; + +#define C0 0.95 +#define C1 -0.08333333333333333333 +#define C3 0.00166666666666666666 +#define D1 0.9 +#define D5 0.03 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + (void) P; + xy.y = lp.phi; + xy.x = lp.lam; + lp.lam = fabs(lp.lam); + xy.x *= cos((C0 + lp.lam * (C1 + lp.lam * lp.lam * C3)) * + (lp.phi * (D1 + D5 * lp.phi * lp.phi * lp.phi * lp.phi))); + return xy; +} + + +PJ *PROJECTION(denoy) { + P->es = 0.0; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/eck1.cpp b/src/projections/eck1.cpp new file mode 100644 index 00000000..88a7430c --- /dev/null +++ b/src/projections/eck1.cpp @@ -0,0 +1,41 @@ +#define PJ_LIB__ +#include + +#include "projects.h" + +PROJ_HEAD(eck1, "Eckert I") "\n\tPCyl, Sph"; +#define FC 0.92131773192356127802 +#define RP 0.31830988618379067154 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + xy.x = FC * lp.lam * (1. - RP * fabs(lp.phi)); + xy.y = FC * lp.phi; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + (void) P; + + lp.phi = xy.y / FC; + lp.lam = xy.x / (FC * (1. - RP * fabs(lp.phi))); + + return (lp); +} + + + +PJ *PROJECTION(eck1) { + P->es = 0.0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P +; +} diff --git a/src/projections/eck2.cpp b/src/projections/eck2.cpp new file mode 100644 index 00000000..f76ab4ec --- /dev/null +++ b/src/projections/eck2.cpp @@ -0,0 +1,56 @@ +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(eck2, "Eckert II") "\n\tPCyl, Sph"; + +#define FXC 0.46065886596178063902 +#define FYC 1.44720250911653531871 +#define C13 0.33333333333333333333 +#define ONEEPS 1.0000001 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + xy.x = FXC * lp.lam * (xy.y = sqrt(4. - 3. * sin(fabs(lp.phi)))); + xy.y = FYC * (2. - xy.y); + if ( lp.phi < 0.) xy.y = -xy.y; + + return (xy); +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + (void) P; + + lp.lam = xy.x / (FXC * ( lp.phi = 2. - fabs(xy.y) / FYC) ); + lp.phi = (4. - lp.phi * lp.phi) * C13; + if (fabs(lp.phi) >= 1.) { + if (fabs(lp.phi) > ONEEPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } else { + lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; + } + } else + lp.phi = asin(lp.phi); + if (xy.y < 0) + lp.phi = -lp.phi; + return (lp); +} + + + +PJ *PROJECTION(eck2) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/eck3.cpp b/src/projections/eck3.cpp new file mode 100644 index 00000000..90376631 --- /dev/null +++ b/src/projections/eck3.cpp @@ -0,0 +1,112 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(eck3, "Eckert III") "\n\tPCyl, Sph"; +PROJ_HEAD(putp1, "Putnins P1") "\n\tPCyl, Sph"; +PROJ_HEAD(wag6, "Wagner VI") "\n\tPCyl, Sph"; +PROJ_HEAD(kav7, "Kavraisky VII") "\n\tPCyl, Sph"; + +namespace { // anonymous namespace +struct pj_opaque { + double C_x, C_y, A, B; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + xy.y = Q->C_y * lp.phi; + xy.x = Q->C_x * lp.lam * (Q->A + asqrt(1. - Q->B * lp.phi * lp.phi)); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double denominator; + + lp.phi = xy.y / Q->C_y; + denominator = (Q->C_x * (Q->A + asqrt(1. - Q->B * lp.phi * lp.phi))); + if ( denominator == 0.0) + lp.lam = HUGE_VAL; + else + lp.lam = xy.x / denominator; + return lp; +} + + +static PJ *setup(PJ *P) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + return P; +} + + +PJ *PROJECTION(eck3) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->C_x = 0.42223820031577120149; + Q->C_y = 0.84447640063154240298; + Q->A = 1.0; + Q->B = 0.4052847345693510857755; + + return setup(P); +} + + +PJ *PROJECTION(kav7) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + /* Defined twice in original code - Using 0.866..., + * but leaving the other one here as a safety measure. + * Q->C_x = 0.2632401569273184856851; */ + Q->C_x = 0.8660254037844; + Q->C_y = 1.; + Q->A = 0.; + Q->B = 0.30396355092701331433; + + return setup(P); +} + + +PJ *PROJECTION(wag6) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->C_x = Q->C_y = 0.94745; + Q->A = 0.0; + Q->B = 0.30396355092701331433; + + return setup(P); +} + + +PJ *PROJECTION(putp1) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->C_x = 1.89490; + Q->C_y = 0.94745; + Q->A = -0.5; + Q->B = 0.30396355092701331433; + + return setup(P); +} diff --git a/src/projections/eck4.cpp b/src/projections/eck4.cpp new file mode 100644 index 00000000..4fa4c21f --- /dev/null +++ b/src/projections/eck4.cpp @@ -0,0 +1,63 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(eck4, "Eckert IV") "\n\tPCyl, Sph"; + +#define C_x .42223820031577120149 +#define C_y 1.32650042817700232218 +#define RC_y .75386330736002178205 +#define C_p 3.57079632679489661922 +#define RC_p .28004957675577868795 +#define EPS 1e-7 +#define NITER 6 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double p, V, s, c; + int i; + (void) P; + + p = C_p * sin(lp.phi); + V = lp.phi * lp.phi; + lp.phi *= 0.895168 + V * ( 0.0218849 + V * 0.00826809 ); + for (i = NITER; i ; --i) { + c = cos(lp.phi); + s = sin(lp.phi); + lp.phi -= V = (lp.phi + s * (c + 2.) - p) / + (1. + c * (c + 2.) - s * s); + if (fabs(V) < EPS) + break; + } + if (!i) { + xy.x = C_x * lp.lam; + xy.y = lp.phi < 0. ? -C_y : C_y; + } else { + xy.x = C_x * lp.lam * (1. + cos(lp.phi)); + xy.y = C_y * sin(lp.phi); + } + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double c; + + lp.phi = aasin(P->ctx,xy.y * RC_y); + lp.lam = xy.x / (C_x * (1. + (c = cos(lp.phi)))); + lp.phi = aasin(P->ctx,(lp.phi + sin(lp.phi) * (c + 2.)) * RC_p); + return lp; +} + + +PJ *PROJECTION(eck4) { + P->es = 0.0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/eck5.cpp b/src/projections/eck5.cpp new file mode 100644 index 00000000..f9f28460 --- /dev/null +++ b/src/projections/eck5.cpp @@ -0,0 +1,40 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(eck5, "Eckert V") "\n\tPCyl, Sph"; + +#define XF 0.44101277172455148219 +#define RXF 2.26750802723822639137 +#define YF 0.88202554344910296438 +#define RYF 1.13375401361911319568 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + xy.x = XF * (1. + cos(lp.phi)) * lp.lam; + xy.y = YF * lp.phi; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + (void) P; + lp.lam = RXF * xy.x / (1. + cos( lp.phi = RYF * xy.y)); + + return lp; +} + + +PJ *PROJECTION(eck5) { + P->es = 0.0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/eqc.cpp b/src/projections/eqc.cpp new file mode 100644 index 00000000..3fdb6dc0 --- /dev/null +++ b/src/projections/eqc.cpp @@ -0,0 +1,54 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + double rc; +}; +} // anonymous namespace + +PROJ_HEAD(eqc, "Equidistant Cylindrical (Plate Carree)") + "\n\tCyl, Sph\n\tlat_ts=[, lat_0=0]"; + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + xy.x = Q->rc * lp.lam; + xy.y = lp.phi - P->phi0; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + lp.lam = xy.x / Q->rc; + lp.phi = xy.y + P->phi0; + + return lp; +} + + +PJ *PROJECTION(eqc) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + if ((Q->rc = cos(pj_param(P->ctx, P->params, "rlat_ts").f)) <= 0.) + return pj_default_destructor (P, PJD_ERR_LAT_TS_LARGER_THAN_90); + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + + return P; +} diff --git a/src/projections/eqdc.cpp b/src/projections/eqdc.cpp new file mode 100644 index 00000000..0831fca4 --- /dev/null +++ b/src/projections/eqdc.cpp @@ -0,0 +1,122 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +namespace { // anonymous namespace +struct pj_opaque { + double phi1; + double phi2; + double n; + double rho; + double rho0; + double c; + double *en; + int ellips; +}; +} // anonymous namespace + +PROJ_HEAD(eqdc, "Equidistant Conic") + "\n\tConic, Sph&Ell\n\tlat_1= lat_2="; +# define EPS10 1.e-10 + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + Q->rho = Q->c - (Q->ellips ? pj_mlfn(lp.phi, sin(lp.phi), + cos(lp.phi), Q->en) : lp.phi); + xy.x = Q->rho * sin( lp.lam *= Q->n ); + xy.y = Q->rho0 - Q->rho * cos(lp.lam); + + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + if ((Q->rho = hypot(xy.x, xy.y = Q->rho0 - xy.y)) != 0.0 ) { + if (Q->n < 0.) { + Q->rho = -Q->rho; + xy.x = -xy.x; + xy.y = -xy.y; + } + lp.phi = Q->c - Q->rho; + if (Q->ellips) + lp.phi = pj_inv_mlfn(P->ctx, lp.phi, P->es, Q->en); + lp.lam = atan2(xy.x, xy.y) / Q->n; + } else { + lp.lam = 0.; + lp.phi = Q->n > 0. ? M_HALFPI : -M_HALFPI; + } + return lp; +} + + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + +PJ *PROJECTION(eqdc) { + double cosphi, sinphi; + int secant; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; + Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; + + if (fabs(Q->phi1 + Q->phi2) < EPS10) + return pj_default_destructor (P, PJD_ERR_CONIC_LAT_EQUAL); + + if (!(Q->en = pj_enfn(P->es))) + return pj_default_destructor(P, ENOMEM); + + Q->n = sinphi = sin(Q->phi1); + cosphi = cos(Q->phi1); + secant = fabs(Q->phi1 - Q->phi2) >= EPS10; + if( (Q->ellips = (P->es > 0.)) ) { + double ml1, m1; + + m1 = pj_msfn(sinphi, cosphi, P->es); + ml1 = pj_mlfn(Q->phi1, sinphi, cosphi, Q->en); + if (secant) { /* secant cone */ + sinphi = sin(Q->phi2); + cosphi = cos(Q->phi2); + Q->n = (m1 - pj_msfn(sinphi, cosphi, P->es)) / + (pj_mlfn(Q->phi2, sinphi, cosphi, Q->en) - ml1); + } + Q->c = ml1 + m1 / Q->n; + Q->rho0 = Q->c - pj_mlfn(P->phi0, sin(P->phi0), + cos(P->phi0), Q->en); + } else { + if (secant) + Q->n = (cosphi - cos(Q->phi2)) / (Q->phi2 - Q->phi1); + Q->c = Q->phi1 + cos(Q->phi1) / Q->n; + Q->rho0 = Q->c - P->phi0; + } + + P->inv = e_inverse; + P->fwd = e_forward; + + return P; +} diff --git a/src/projections/eqearth.cpp b/src/projections/eqearth.cpp new file mode 100644 index 00000000..e5c1f974 --- /dev/null +++ b/src/projections/eqearth.cpp @@ -0,0 +1,164 @@ +/* +Equal Earth is a projection inspired by the Robinson projection, but unlike +the Robinson projection retains the relative size of areas. The projection +was designed in 2018 by Bojan Savric, Tom Patterson and Bernhard Jenny. + +Publication: +Bojan Savric, Tom Patterson & Bernhard Jenny (2018). The Equal Earth map +projection, International Journal of Geographical Information Science, +DOI: 10.1080/13658816.2018.1504949 + +Port to PROJ by Juernjakob Dugge, 16 August 2018 +Added ellipsoidal equations by Bojan Savric, 22 August 2018 +*/ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(eqearth, "Equal Earth") "\n\tPCyl, Sph&Ell"; + +/* A1..A4, polynomial coefficients */ +#define A1 1.340264 +#define A2 -0.081106 +#define A3 0.000893 +#define A4 0.003796 +#define M (sqrt(3) / 2.0) + +#define MAX_Y 1.3173627591574 /* 90° latitude on a sphere with radius 1 */ +#define EPS 1e-11 +#define MAX_ITER 12 + +namespace { // anonymous namespace +struct pj_opaque { + double qp; + double rqda; + double *apa; +}; +} // anonymous namespace + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal/spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double sbeta; + double psi, psi2, psi6; + + /* Spheroidal case, using sine latitude */ + sbeta = sin(lp.phi); + + /* In the ellipsoidal case, we convert sbeta to sine of authalic latitude */ + if (P->es != 0.0) { + sbeta = pj_qsfn(sbeta, P->e, 1.0 - P->es) / Q->qp; + + /* Rounding error. */ + if (fabs(sbeta) > 1) + sbeta = sbeta > 0 ? 1 : -1; + } + + /* Equal Earth projection */ + psi = asin(M * sbeta); + psi2 = psi * psi; + psi6 = psi2 * psi2 * psi2; + + xy.x = lp.lam * cos(psi) / (M * (A1 + 3 * A2 * psi2 + psi6 * (7 * A3 + 9 * A4 * psi2))); + xy.y = psi * (A1 + A2 * psi2 + psi6 * (A3 + A4 * psi2)); + + /* Adjusting x and y for authalic radius */ + xy.x *= Q->rqda; + xy.y *= Q->rqda; + + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal/spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double yc, y2, y6; + int i; + + /* Adjusting x and y for authalic radius */ + xy.x /= Q->rqda; + xy.y /= Q->rqda; + + /* Make sure y is inside valid range */ + if (xy.y > MAX_Y) + xy.y = MAX_Y; + else if (xy.y < -MAX_Y) + xy.y = -MAX_Y; + + yc = xy.y; + + /* Newton-Raphson */ + for (i = MAX_ITER; i ; --i) { + double f, fder, tol; + + y2 = yc * yc; + y6 = y2 * y2 * y2; + + f = yc * (A1 + A2 * y2 + y6 * (A3 + A4 * y2)) - xy.y; + fder = A1 + 3 * A2 * y2 + y6 * (7 * A3 + 9 * A4 * y2); + + tol = f / fder; + yc -= tol; + + if (fabs(tol) < EPS) + break; + } + + if( i == 0 ) { + pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + return lp; + } + + /* Longitude */ + y2 = yc * yc; + y6 = y2 * y2 * y2; + + lp.lam = M * xy.x * (A1 + 3 * A2 * y2 + y6 * (7 * A3 + 9 * A4 * y2)) / cos(yc); + + /* Latitude (for spheroidal case, this is latitude */ + lp.phi = asin(sin(yc) / M); + + /* Ellipsoidal case, converting auth. latitude */ + if (P->es != 0.0) + lp.phi = pj_authlat(lp.phi, Q->apa); + + return lp; +} + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->apa); + return pj_default_destructor (P, errlev); +} + + +PJ *PROJECTION(eqearth) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + P->fwd = e_forward; + P->inv = e_inverse; + Q->rqda = 1.0; + + /* Ellipsoidal case */ + if (P->es != 0.0) { + Q->apa = pj_authset(P->es); /* For auth_lat(). */ + if (nullptr == Q->apa) + return destructor(P, ENOMEM); + Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */ + Q->rqda = sqrt(0.5*Q->qp); /* Authalic radius divided by major axis */ + } + + return P; +} diff --git a/src/projections/etmerc.cpp b/src/projections/etmerc.cpp new file mode 100644 index 00000000..05f86f37 --- /dev/null +++ b/src/projections/etmerc.cpp @@ -0,0 +1,362 @@ +/* +** libproj -- library of cartographic projections +** +** Copyright (c) 2008 Gerald I. Evenden +*/ + +/* +** 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. +*/ + +/* The code in this file is largly based upon procedures: + * + * Written by: Knud Poder and Karsten Engsager + * + * Based on math from: R.Koenig and K.H. Weise, "Mathematische + * Grundlagen der hoeheren Geodaesie und Kartographie, + * Springer-Verlag, Berlin/Goettingen" Heidelberg, 1951. + * + * Modified and used here by permission of Reference Networks + * Division, Kort og Matrikelstyrelsen (KMS), Copenhagen, Denmark + * +*/ + +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + + +namespace { // anonymous namespace +struct pj_opaque { + double Qn; /* Merid. quad., scaled to the projection */ \ + double Zb; /* Radius vector in polar coord. systems */ \ + double cgb[6]; /* Constants for Gauss -> Geo lat */ \ + double cbg[6]; /* Constants for Geo lat -> Gauss */ \ + double utg[6]; /* Constants for transv. merc. -> geo */ \ + double gtu[6]; /* Constants for geo -> transv. merc. */ +}; +} // anonymous namespace + +PROJ_HEAD(etmerc, "Extended Transverse Mercator") + "\n\tCyl, Sph\n\tlat_ts=(0)\nlat_0=(0)"; +PROJ_HEAD(utm, "Universal Transverse Mercator (UTM)") + "\n\tCyl, Sph\n\tzone= south"; + +#define PROJ_ETMERC_ORDER 6 + +#ifdef _GNU_SOURCE + inline +#endif +static double gatg(double *p1, int len_p1, double B) { + double *p; + double h = 0, h1, h2 = 0, cos_2B; + + cos_2B = 2*cos(2*B); + p = p1 + len_p1; + h1 = *--p; + while (p - p1) { + h = -h2 + cos_2B*h1 + *--p; + h2 = h1; + h1 = h; + } + return (B + h*sin(2*B)); +} + +/* Complex Clenshaw summation */ +#ifdef _GNU_SOURCE + inline +#endif +static double clenS(double *a, int size, double arg_r, double arg_i, double *R, double *I) { + double *p, r, i, hr, hr1, hr2, hi, hi1, hi2; + double sin_arg_r, cos_arg_r, sinh_arg_i, cosh_arg_i; + + /* arguments */ + p = a + size; +#ifdef _GNU_SOURCE + sincos(arg_r, &sin_arg_r, &cos_arg_r); +#else + sin_arg_r = sin(arg_r); + cos_arg_r = cos(arg_r); +#endif + sinh_arg_i = sinh(arg_i); + cosh_arg_i = cosh(arg_i); + r = 2*cos_arg_r*cosh_arg_i; + i = -2*sin_arg_r*sinh_arg_i; + + /* summation loop */ + hi1 = hr1 = hi = 0; + hr = *--p; + for (; a - p;) { + hr2 = hr1; + hi2 = hi1; + hr1 = hr; + hi1 = hi; + hr = -hr2 + r*hr1 - i*hi1 + *--p; + hi = -hi2 + i*hr1 + r*hi1; + } + + r = sin_arg_r*cosh_arg_i; + i = cos_arg_r*sinh_arg_i; + *R = r*hr - i*hi; + *I = r*hi + i*hr; + return *R; +} + + +/* Real Clenshaw summation */ +static double clens(double *a, int size, double arg_r) { + double *p, r, hr, hr1, hr2, cos_arg_r; + + p = a + size; + cos_arg_r = cos(arg_r); + r = 2*cos_arg_r; + + /* summation loop */ + hr1 = 0; + hr = *--p; + for (; a - p;) { + hr2 = hr1; + hr1 = hr; + hr = -hr2 + r*hr1 + *--p; + } + return sin (arg_r)*hr; +} + + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double sin_Cn, cos_Cn, cos_Ce, sin_Ce, dCn, dCe; + double Cn = lp.phi, Ce = lp.lam; + + /* ell. LAT, LNG -> Gaussian LAT, LNG */ + Cn = gatg (Q->cbg, PROJ_ETMERC_ORDER, Cn); + /* Gaussian LAT, LNG -> compl. sph. LAT */ +#ifdef _GNU_SOURCE + sincos (Cn, &sin_Cn, &cos_Cn); + sincos (Ce, &sin_Ce, &cos_Ce); +#else + sin_Cn = sin (Cn); + cos_Cn = cos (Cn); + sin_Ce = sin (Ce); + cos_Ce = cos (Ce); +#endif + + Cn = atan2 (sin_Cn, cos_Ce*cos_Cn); + Ce = atan2 (sin_Ce*cos_Cn, hypot (sin_Cn, cos_Cn*cos_Ce)); + + /* compl. sph. N, E -> ell. norm. N, E */ + Ce = asinh ( tan (Ce) ); /* Replaces: Ce = log(tan(FORTPI + Ce*0.5)); */ + Cn += clenS (Q->gtu, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe); + Ce += dCe; + if (fabs (Ce) <= 2.623395162778) { + xy.y = Q->Qn * Cn + Q->Zb; /* Northing */ + xy.x = Q->Qn * Ce; /* Easting */ + } else + xy.x = xy.y = HUGE_VAL; + return xy; +} + + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double sin_Cn, cos_Cn, cos_Ce, sin_Ce, dCn, dCe; + double Cn = xy.y, Ce = xy.x; + + /* normalize N, E */ + Cn = (Cn - Q->Zb)/Q->Qn; + Ce = Ce/Q->Qn; + + if (fabs(Ce) <= 2.623395162778) { /* 150 degrees */ + /* norm. N, E -> compl. sph. LAT, LNG */ + Cn += clenS(Q->utg, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe); + Ce += dCe; + Ce = atan (sinh (Ce)); /* Replaces: Ce = 2*(atan(exp(Ce)) - FORTPI); */ + /* compl. sph. LAT -> Gaussian LAT, LNG */ +#ifdef _GNU_SOURCE + sincos (Cn, &sin_Cn, &cos_Cn); + sincos (Ce, &sin_Ce, &cos_Ce); +#else + sin_Cn = sin (Cn); + cos_Cn = cos (Cn); + sin_Ce = sin (Ce); + cos_Ce = cos (Ce); +#endif + Ce = atan2 (sin_Ce, cos_Ce*cos_Cn); + Cn = atan2 (sin_Cn*cos_Ce, hypot (sin_Ce, cos_Ce*cos_Cn)); + /* Gaussian LAT, LNG -> ell. LAT, LNG */ + lp.phi = gatg (Q->cgb, PROJ_ETMERC_ORDER, Cn); + lp.lam = Ce; + } + else + lp.phi = lp.lam = HUGE_VAL; + return lp; +} + + +static PJ *setup(PJ *P) { /* general initialization */ + double f, n, np, Z; + struct pj_opaque *Q = static_cast(P->opaque); + + if (P->es <= 0) { + return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); + } + + /* flattening */ + f = P->es / (1 + sqrt (1 - P->es)); /* Replaces: f = 1 - sqrt(1-P->es); */ + + /* third flattening */ + np = n = f/(2 - f); + + /* COEF. OF TRIG SERIES GEO <-> GAUSS */ + /* cgb := Gaussian -> Geodetic, KW p190 - 191 (61) - (62) */ + /* cbg := Geodetic -> Gaussian, KW p186 - 187 (51) - (52) */ + /* PROJ_ETMERC_ORDER = 6th degree : Engsager and Poder: ICC2007 */ + + Q->cgb[0] = n*( 2 + n*(-2/3.0 + n*(-2 + n*(116/45.0 + n*(26/45.0 + + n*(-2854/675.0 )))))); + Q->cbg[0] = n*(-2 + n*( 2/3.0 + n*( 4/3.0 + n*(-82/45.0 + n*(32/45.0 + + n*( 4642/4725.0)))))); + np *= n; + Q->cgb[1] = np*(7/3.0 + n*( -8/5.0 + n*(-227/45.0 + n*(2704/315.0 + + n*( 2323/945.0))))); + Q->cbg[1] = np*(5/3.0 + n*(-16/15.0 + n*( -13/9.0 + n*( 904/315.0 + + n*(-1522/945.0))))); + np *= n; + /* n^5 coeff corrected from 1262/105 -> -1262/105 */ + Q->cgb[2] = np*( 56/15.0 + n*(-136/35.0 + n*(-1262/105.0 + + n*( 73814/2835.0)))); + Q->cbg[2] = np*(-26/15.0 + n*( 34/21.0 + n*( 8/5.0 + + n*(-12686/2835.0)))); + np *= n; + /* n^5 coeff corrected from 322/35 -> 332/35 */ + Q->cgb[3] = np*(4279/630.0 + n*(-332/35.0 + n*(-399572/14175.0))); + Q->cbg[3] = np*(1237/630.0 + n*( -12/5.0 + n*( -24832/14175.0))); + np *= n; + Q->cgb[4] = np*(4174/315.0 + n*(-144838/6237.0 )); + Q->cbg[4] = np*(-734/315.0 + n*( 109598/31185.0)); + np *= n; + Q->cgb[5] = np*(601676/22275.0 ); + Q->cbg[5] = np*(444337/155925.0); + + /* Constants of the projections */ + /* Transverse Mercator (UTM, ITM, etc) */ + np = n*n; + /* Norm. mer. quad, K&W p.50 (96), p.19 (38b), p.5 (2) */ + Q->Qn = P->k0/(1 + n) * (1 + np*(1/4.0 + np*(1/64.0 + np/256.0))); + /* coef of trig series */ + /* utg := ell. N, E -> sph. N, E, KW p194 (65) */ + /* gtu := sph. N, E -> ell. N, E, KW p196 (69) */ + Q->utg[0] = n*(-0.5 + n*( 2/3.0 + n*(-37/96.0 + n*( 1/360.0 + + n*( 81/512.0 + n*(-96199/604800.0)))))); + Q->gtu[0] = n*( 0.5 + n*(-2/3.0 + n*( 5/16.0 + n*(41/180.0 + + n*(-127/288.0 + n*( 7891/37800.0 )))))); + Q->utg[1] = np*(-1/48.0 + n*(-1/15.0 + n*(437/1440.0 + n*(-46/105.0 + + n*( 1118711/3870720.0))))); + Q->gtu[1] = np*(13/48.0 + n*(-3/5.0 + n*(557/1440.0 + n*(281/630.0 + + n*(-1983433/1935360.0))))); + np *= n; + Q->utg[2] = np*(-17/480.0 + n*( 37/840.0 + n*( 209/4480.0 + + n*( -5569/90720.0 )))); + Q->gtu[2] = np*( 61/240.0 + n*(-103/140.0 + n*(15061/26880.0 + + n*(167603/181440.0)))); + np *= n; + Q->utg[3] = np*(-4397/161280.0 + n*( 11/504.0 + n*( 830251/7257600.0))); + Q->gtu[3] = np*(49561/161280.0 + n*(-179/168.0 + n*(6601661/7257600.0))); + np *= n; + Q->utg[4] = np*(-4583/161280.0 + n*( 108847/3991680.0)); + Q->gtu[4] = np*(34729/80640.0 + n*(-3418889/1995840.0)); + np *= n; + Q->utg[5] = np*(-20648693/638668800.0); + Q->gtu[5] = np*(212378941/319334400.0); + + /* Gaussian latitude value of the origin latitude */ + Z = gatg (Q->cbg, PROJ_ETMERC_ORDER, P->phi0); + + /* Origin northing minus true northing at the origin latitude */ + /* i.e. true northing = N - P->Zb */ + Q->Zb = - Q->Qn*(Z + clens(Q->gtu, PROJ_ETMERC_ORDER, 2*Z)); + P->inv = e_inverse; + P->fwd = e_forward; + return P; +} + + + +PJ *PROJECTION(etmerc) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + return setup (P); +} + + + +/* utm uses etmerc for the underlying projection */ + + +PJ *PROJECTION(utm) { + long zone; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + if (P->es == 0.0) { + proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); + return pj_default_destructor(P, ENOMEM); + } + if (P->lam0 < -1000.0 || P->lam0 > 1000.0) { + return pj_default_destructor(P, PJD_ERR_INVALID_UTM_ZONE); + } + + P->y0 = pj_param (P->ctx, P->params, "bsouth").i ? 10000000. : 0.; + P->x0 = 500000.; + if (pj_param (P->ctx, P->params, "tzone").i) /* zone input ? */ + { + zone = pj_param(P->ctx, P->params, "izone").i; + if (zone > 0 && zone <= 60) + --zone; + else { + return pj_default_destructor(P, PJD_ERR_INVALID_UTM_ZONE); + } + } + else /* nearest central meridian input */ + { + zone = lround((floor ((adjlon (P->lam0) + M_PI) * 30. / M_PI))); + if (zone < 0) + zone = 0; + else if (zone >= 60) + zone = 59; + } + P->lam0 = (zone + .5) * M_PI / 30. - M_PI; + P->k0 = 0.9996; + P->phi0 = 0.; + + return setup (P); +} diff --git a/src/projections/fahey.cpp b/src/projections/fahey.cpp new file mode 100644 index 00000000..85e0ab69 --- /dev/null +++ b/src/projections/fahey.cpp @@ -0,0 +1,41 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(fahey, "Fahey") "\n\tPcyl, Sph"; + +#define TOL 1e-6 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + xy.x = tan(0.5 * lp.phi); + xy.y = 1.819152 * xy.x; + xy.x = 0.819152 * lp.lam * asqrt(1 - xy.x * xy.x); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + (void) P; + + xy.y /= 1.819152; + lp.phi = 2. * atan(xy.y); + xy.y = 1. - xy.y * xy.y; + lp.lam = fabs(xy.y) < TOL ? 0. : xy.x / (0.819152 * sqrt(xy.y)); + return lp; +} + + +PJ *PROJECTION(fahey) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/fouc_s.cpp b/src/projections/fouc_s.cpp new file mode 100644 index 00000000..c5e711de --- /dev/null +++ b/src/projections/fouc_s.cpp @@ -0,0 +1,72 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(fouc_s, "Foucaut Sinusoidal") "\n\tPCyl, Sph"; + +#define MAX_ITER 10 +#define LOOP_TOL 1e-7 + +namespace { // anonymous namespace +struct pj_opaque { + double n, n1; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double t; + + t = cos(lp.phi); + xy.x = lp.lam * t / (Q->n + Q->n1 * t); + xy.y = Q->n * lp.phi + Q->n1 * sin(lp.phi); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double V; + int i; + + if (Q->n != 0.0) { + lp.phi = xy.y; + for (i = MAX_ITER; i ; --i) { + lp.phi -= V = (Q->n * lp.phi + Q->n1 * sin(lp.phi) - xy.y ) / + (Q->n + Q->n1 * cos(lp.phi)); + if (fabs(V) < LOOP_TOL) + break; + } + if (!i) + lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; + } else + lp.phi = aasin(P->ctx,xy.y); + V = cos(lp.phi); + lp.lam = xy.x * (Q->n + Q->n1 * V) / V; + return lp; +} + + +PJ *PROJECTION(fouc_s) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->n = pj_param(P->ctx, P->params, "dn").f; + if (Q->n < 0. || Q->n > 1.) + return pj_default_destructor (P, PJD_ERR_N_OUT_OF_RANGE); + + Q->n1 = 1. - Q->n; + P->es = 0; + P->inv = s_inverse; + P->fwd = s_forward; + return P; +} diff --git a/src/projections/gall.cpp b/src/projections/gall.cpp new file mode 100644 index 00000000..a8697482 --- /dev/null +++ b/src/projections/gall.cpp @@ -0,0 +1,44 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(gall, "Gall (Gall Stereographic)") "\n\tCyl, Sph"; + +#define YF 1.70710678118654752440 +#define XF 0.70710678118654752440 +#define RYF 0.58578643762690495119 +#define RXF 1.41421356237309504880 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + xy.x = XF * lp.lam; + xy.y = YF * tan(.5 * lp.phi); + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + (void) P; + + lp.lam = RXF * xy.x; + lp.phi = 2. * atan(xy.y * RYF); + + return lp; +} + + +PJ *PROJECTION(gall) { + P->es = 0.0; + + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/geos.cpp b/src/projections/geos.cpp new file mode 100644 index 00000000..90fb01ab --- /dev/null +++ b/src/projections/geos.cpp @@ -0,0 +1,238 @@ +/* +** libproj -- library of cartographic projections +** +** Copyright (c) 2004 Gerald I. Evenden +** Copyright (c) 2012 Martin Raspaud +** +** See also (section 4.4.3.2): +** http://www.eumetsat.int/en/area4/msg/news/us_doc/cgms_03_26.pdf +** +** 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. +*/ + +#define PJ_LIB__ +#include +#include +#include + +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +namespace { // anonymous namespace +struct pj_opaque { + double h; + double radius_p; + double radius_p2; + double radius_p_inv2; + double radius_g; + double radius_g_1; + double C; + int flip_axis; +}; +} // anonymous namespace + +PROJ_HEAD(geos, "Geostationary Satellite View") "\n\tAzi, Sph&Ell\n\th="; + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double Vx, Vy, Vz, tmp; + + /* Calculation of the three components of the vector from satellite to + ** position on earth surface (lon,lat).*/ + tmp = cos(lp.phi); + Vx = cos (lp.lam) * tmp; + Vy = sin (lp.lam) * tmp; + Vz = sin (lp.phi); + + /* Check visibility*/ + + + /* Calculation based on view angles from satellite.*/ + tmp = Q->radius_g - Vx; + + if(Q->flip_axis) { + xy.x = Q->radius_g_1 * atan(Vy / hypot(Vz, tmp)); + xy.y = Q->radius_g_1 * atan(Vz / tmp); + } else { + xy.x = Q->radius_g_1 * atan(Vy / tmp); + xy.y = Q->radius_g_1 * atan(Vz / hypot(Vy, tmp)); + } + + return xy; +} + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double r, Vx, Vy, Vz, tmp; + + /* Calculation of geocentric latitude. */ + lp.phi = atan (Q->radius_p2 * tan (lp.phi)); + + /* Calculation of the three components of the vector from satellite to + ** position on earth surface (lon,lat).*/ + r = (Q->radius_p) / hypot(Q->radius_p * cos (lp.phi), sin (lp.phi)); + Vx = r * cos (lp.lam) * cos (lp.phi); + Vy = r * sin (lp.lam) * cos (lp.phi); + Vz = r * sin (lp.phi); + + /* Check visibility. */ + if (((Q->radius_g - Vx) * Vx - Vy * Vy - Vz * Vz * Q->radius_p_inv2) < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + + /* Calculation based on view angles from satellite. */ + tmp = Q->radius_g - Vx; + + if(Q->flip_axis) { + xy.x = Q->radius_g_1 * atan (Vy / hypot (Vz, tmp)); + xy.y = Q->radius_g_1 * atan (Vz / tmp); + } else { + xy.x = Q->radius_g_1 * atan (Vy / tmp); + xy.y = Q->radius_g_1 * atan (Vz / hypot (Vy, tmp)); + } + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double Vx, Vy, Vz, a, b, det, k; + + /* Setting three components of vector from satellite to position.*/ + Vx = -1.0; + if(Q->flip_axis) { + Vz = tan (xy.y / (Q->radius_g - 1.0)); + Vy = tan (xy.x / (Q->radius_g - 1.0)) * sqrt (1.0 + Vz * Vz); + } else { + Vy = tan (xy.x / (Q->radius_g - 1.0)); + Vz = tan (xy.y / (Q->radius_g - 1.0)) * sqrt (1.0 + Vy * Vy); + } + + /* Calculation of terms in cubic equation and determinant.*/ + a = Vy * Vy + Vz * Vz + Vx * Vx; + b = 2 * Q->radius_g * Vx; + if ((det = (b * b) - 4 * a * Q->C) < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + + /* Calculation of three components of vector from satellite to position.*/ + k = (-b - sqrt(det)) / (2 * a); + Vx = Q->radius_g + k * Vx; + Vy *= k; + Vz *= k; + + /* Calculation of longitude and latitude.*/ + lp.lam = atan2 (Vy, Vx); + lp.phi = atan (Vz * cos (lp.lam) / Vx); + + return lp; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double Vx, Vy, Vz, a, b, det, k; + + /* Setting three components of vector from satellite to position.*/ + Vx = -1.0; + + if(Q->flip_axis) { + Vz = tan (xy.y / Q->radius_g_1); + Vy = tan (xy.x / Q->radius_g_1) * hypot(1.0, Vz); + } else { + Vy = tan (xy.x / Q->radius_g_1); + Vz = tan (xy.y / Q->radius_g_1) * hypot(1.0, Vy); + } + + /* Calculation of terms in cubic equation and determinant.*/ + a = Vz / Q->radius_p; + a = Vy * Vy + a * a + Vx * Vx; + b = 2 * Q->radius_g * Vx; + if ((det = (b * b) - 4 * a * Q->C) < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + + /* Calculation of three components of vector from satellite to position.*/ + k = (-b - sqrt(det)) / (2. * a); + Vx = Q->radius_g + k * Vx; + Vy *= k; + Vz *= k; + + /* Calculation of longitude and latitude.*/ + lp.lam = atan2 (Vy, Vx); + lp.phi = atan (Vz * cos (lp.lam) / Vx); + lp.phi = atan (Q->radius_p_inv2 * tan (lp.phi)); + + return lp; +} + + +PJ *PROJECTION(geos) { + char *sweep_axis; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + if ((Q->h = pj_param(P->ctx, P->params, "dh").f) <= 0.) + return pj_default_destructor (P, PJD_ERR_H_LESS_THAN_ZERO); + + sweep_axis = pj_param(P->ctx, P->params, "ssweep").s; + if (sweep_axis == nullptr) + Q->flip_axis = 0; + else { + if ((sweep_axis[0] != 'x' && sweep_axis[0] != 'y') || + sweep_axis[1] != '\0') + return pj_default_destructor (P, PJD_ERR_INVALID_SWEEP_AXIS); + + if (sweep_axis[0] == 'x') + Q->flip_axis = 1; + else + Q->flip_axis = 0; + } + + Q->radius_g_1 = Q->h / P->a; + Q->radius_g = 1. + Q->radius_g_1; + Q->C = Q->radius_g * Q->radius_g - 1.0; + if (P->es != 0.0) { + Q->radius_p = sqrt (P->one_es); + Q->radius_p2 = P->one_es; + Q->radius_p_inv2 = P->rone_es; + P->inv = e_inverse; + P->fwd = e_forward; + } else { + Q->radius_p = Q->radius_p2 = Q->radius_p_inv2 = 1.0; + P->inv = s_inverse; + P->fwd = s_forward; + } + + return P; +} diff --git a/src/projections/gins8.cpp b/src/projections/gins8.cpp new file mode 100644 index 00000000..cc422437 --- /dev/null +++ b/src/projections/gins8.cpp @@ -0,0 +1,33 @@ +#define PJ_LIB__ +#include "projects.h" + +PROJ_HEAD(gins8, "Ginsburg VIII (TsNIIGAiK)") "\n\tPCyl, Sph, no inv"; + +#define Cl 0.000952426 +#define Cp 0.162388 +#define C12 0.08333333333333333 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double t = lp.phi * lp.phi; + (void) P; + + xy.y = lp.phi * (1. + t * C12); + xy.x = lp.lam * (1. - Cp * t); + t = lp.lam * lp.lam; + xy.x *= (0.87 - Cl * t * t); + + return xy; +} + + +PJ *PROJECTION(gins8) { + P->es = 0.0; + P->inv = nullptr; + P->fwd = s_forward; + + return P; +} + + diff --git a/src/projections/gn_sinu.cpp b/src/projections/gn_sinu.cpp new file mode 100644 index 00000000..530de229 --- /dev/null +++ b/src/projections/gn_sinu.cpp @@ -0,0 +1,189 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(gn_sinu, "General Sinusoidal Series") "\n\tPCyl, Sph\n\tm= n="; +PROJ_HEAD(sinu, "Sinusoidal (Sanson-Flamsteed)") "\n\tPCyl, Sph&Ell"; +PROJ_HEAD(eck6, "Eckert VI") "\n\tPCyl, Sph"; +PROJ_HEAD(mbtfps, "McBryde-Thomas Flat-Polar Sinusoidal") "\n\tPCyl, Sph"; + +#define EPS10 1e-10 +#define MAX_ITER 8 +#define LOOP_TOL 1e-7 + +namespace { // anonymous namespace +struct pj_opaque { + double *en; + double m, n, C_x, C_y; +}; +} // anonymous namespace + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + double s, c; + + xy.y = pj_mlfn(lp.phi, s = sin(lp.phi), c = cos(lp.phi), static_cast(P->opaque)->en); + xy.x = lp.lam * c / sqrt(1. - P->es * s * s); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + double s; + + if ((s = fabs(lp.phi = pj_inv_mlfn(P->ctx, xy.y, P->es, static_cast(P->opaque)->en))) < M_HALFPI) { + s = sin(lp.phi); + lp.lam = xy.x * sqrt(1. - P->es * s * s) / cos(lp.phi); + } else if ((s - EPS10) < M_HALFPI) { + lp.lam = 0.; + } else { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + } + + return lp; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + if (Q->m == 0.0) + lp.phi = Q->n != 1. ? aasin(P->ctx,Q->n * sin(lp.phi)): lp.phi; + else { + double k, V; + int i; + + k = Q->n * sin(lp.phi); + for (i = MAX_ITER; i ; --i) { + lp.phi -= V = (Q->m * lp.phi + sin(lp.phi) - k) / + (Q->m + cos(lp.phi)); + if (fabs(V) < LOOP_TOL) + break; + } + if (!i) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + + } + xy.x = Q->C_x * lp.lam * (Q->m + cos(lp.phi)); + xy.y = Q->C_y * lp.phi; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + xy.y /= Q->C_y; + lp.phi = (Q->m != 0.0) ? aasin(P->ctx,(Q->m * xy.y + sin(xy.y)) / Q->n) : + ( Q->n != 1. ? aasin(P->ctx,sin(xy.y) / Q->n) : xy.y ); + lp.lam = xy.x / (Q->C_x * (Q->m + cos(xy.y))); + return lp; +} + + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + + +/* for spheres, only */ +static void setup(PJ *P) { + struct pj_opaque *Q = static_cast(P->opaque); + P->es = 0; + P->inv = s_inverse; + P->fwd = s_forward; + + Q->C_x = (Q->C_y = sqrt((Q->m + 1.) / Q->n))/(Q->m + 1.); +} + + +PJ *PROJECTION(sinu) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + if (!(Q->en = pj_enfn(P->es))) + return pj_default_destructor (P, ENOMEM); + + if (P->es != 0.0) { + P->inv = e_inverse; + P->fwd = e_forward; + } else { + Q->n = 1.; + Q->m = 0.; + setup(P); + } + return P; +} + + +PJ *PROJECTION(eck6) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + Q->m = 1.; + Q->n = 2.570796326794896619231321691; + setup(P); + + return P; +} + + +PJ *PROJECTION(mbtfps) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + Q->m = 0.5; + Q->n = 1.785398163397448309615660845; + setup(P); + + return P; +} + + +PJ *PROJECTION(gn_sinu) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + if (pj_param(P->ctx, P->params, "tn").i && pj_param(P->ctx, P->params, "tm").i) { + Q->n = pj_param(P->ctx, P->params, "dn").f; + Q->m = pj_param(P->ctx, P->params, "dm").f; + if (Q->n <= 0 || Q->m < 0) + return destructor (P, PJD_ERR_INVALID_M_OR_N); + } else + return destructor (P, PJD_ERR_INVALID_M_OR_N); + + setup(P); + + return P; +} diff --git a/src/projections/gnom.cpp b/src/projections/gnom.cpp new file mode 100644 index 00000000..a4b5e35d --- /dev/null +++ b/src/projections/gnom.cpp @@ -0,0 +1,147 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +PROJ_HEAD(gnom, "Gnomonic") "\n\tAzi, Sph"; + +#define EPS10 1.e-10 + +namespace { // anonymous namespace +enum Mode { + N_POLE = 0, + S_POLE = 1, + EQUIT = 2, + OBLIQ = 3 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double sinph0; + double cosph0; + enum Mode mode; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, cosphi, sinphi; + + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + coslam = cos(lp.lam); + + switch (Q->mode) { + case EQUIT: + xy.y = cosphi * coslam; + break; + case OBLIQ: + xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam; + break; + case S_POLE: + xy.y = - sinphi; + break; + case N_POLE: + xy.y = sinphi; + break; + } + + if (xy.y <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + + xy.x = (xy.y = 1. / xy.y) * cosphi * sin(lp.lam); + switch (Q->mode) { + case EQUIT: + xy.y *= sinphi; + break; + case OBLIQ: + xy.y *= Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam; + break; + case N_POLE: + coslam = - coslam; + /*-fallthrough*/ + case S_POLE: + xy.y *= cosphi * coslam; + break; + } + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double rh, cosz, sinz; + + rh = hypot(xy.x, xy.y); + sinz = sin(lp.phi = atan(rh)); + cosz = sqrt(1. - sinz * sinz); + + if (fabs(rh) <= EPS10) { + lp.phi = P->phi0; + lp.lam = 0.; + } else { + switch (Q->mode) { + case OBLIQ: + lp.phi = cosz * Q->sinph0 + xy.y * sinz * Q->cosph0 / rh; + if (fabs(lp.phi) >= 1.) + lp.phi = lp.phi > 0. ? M_HALFPI : - M_HALFPI; + else + lp.phi = asin(lp.phi); + xy.y = (cosz - Q->sinph0 * sin(lp.phi)) * rh; + xy.x *= sinz * Q->cosph0; + break; + case EQUIT: + lp.phi = xy.y * sinz / rh; + if (fabs(lp.phi) >= 1.) + lp.phi = lp.phi > 0. ? M_HALFPI : - M_HALFPI; + else + lp.phi = asin(lp.phi); + xy.y = cosz * rh; + xy.x *= sinz; + break; + case S_POLE: + lp.phi -= M_HALFPI; + break; + case N_POLE: + lp.phi = M_HALFPI - lp.phi; + xy.y = -xy.y; + break; + } + lp.lam = atan2(xy.x, xy.y); + } + return lp; +} + + +PJ *PROJECTION(gnom) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) { + Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + } else if (fabs(P->phi0) < EPS10) { + Q->mode = EQUIT; + } else { + Q->mode = OBLIQ; + Q->sinph0 = sin(P->phi0); + Q->cosph0 = cos(P->phi0); + } + + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + + return P; +} diff --git a/src/projections/goode.cpp b/src/projections/goode.cpp new file mode 100644 index 00000000..c79d125e --- /dev/null +++ b/src/projections/goode.cpp @@ -0,0 +1,84 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(goode, "Goode Homolosine") "\n\tPCyl, Sph"; + +#define Y_COR 0.05280 +#define PHI_LIM 0.71093078197902358062 + +C_NAMESPACE PJ *pj_sinu(PJ *), *pj_moll(PJ *); + +namespace { // anonymous namespace +struct pj_opaque { + PJ *sinu; + PJ *moll; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy; + struct pj_opaque *Q = static_cast(P->opaque); + + if (fabs(lp.phi) <= PHI_LIM) + xy = Q->sinu->fwd(lp, Q->sinu); + else { + xy = Q->moll->fwd(lp, Q->moll); + xy.y -= lp.phi >= 0.0 ? Y_COR : -Y_COR; + } + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp; + struct pj_opaque *Q = static_cast(P->opaque); + + if (fabs(xy.y) <= PHI_LIM) + lp = Q->sinu->inv(xy, Q->sinu); + else { + xy.y += xy.y >= 0.0 ? Y_COR : -Y_COR; + lp = Q->moll->inv(xy, Q->moll); + } + return lp; +} + + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + pj_free (static_cast(P->opaque)->sinu); + pj_free (static_cast(P->opaque)->moll); + return pj_default_destructor (P, errlev); +} + + + +PJ *PROJECTION(goode) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + P->es = 0.; + if (!(Q->sinu = pj_sinu(nullptr)) || !(Q->moll = pj_moll(nullptr))) + return destructor (P, ENOMEM); + Q->sinu->es = 0.; + Q->sinu->ctx = P->ctx; + Q->moll->ctx = P->ctx; + if (!(Q->sinu = pj_sinu(Q->sinu)) || !(Q->moll = pj_moll(Q->moll))) + return destructor (P, ENOMEM); + + P->fwd = s_forward; + P->inv = s_inverse; + + return P; +} diff --git a/src/projections/gstmerc.cpp b/src/projections/gstmerc.cpp new file mode 100644 index 00000000..9b819bac --- /dev/null +++ b/src/projections/gstmerc.cpp @@ -0,0 +1,74 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(gstmerc, "Gauss-Schreiber Transverse Mercator (aka Gauss-Laborde Reunion)") + "\n\tCyl, Sph&Ell\n\tlat_0= lon_0= k_0="; + +namespace { // anonymous namespace +struct pj_opaque { + double lamc; + double phic; + double c; + double n1; + double n2; + double XS; + double YS; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double L, Ls, sinLs1, Ls1; + + L = Q->n1*lp.lam; + Ls = Q->c + Q->n1 * log(pj_tsfn(-1.0 * lp.phi, -1.0 * sin(lp.phi), P->e)); + sinLs1 = sin(L) / cosh(Ls); + Ls1 = log(pj_tsfn(-1.0 * asin(sinLs1), 0.0, 0.0)); + xy.x = (Q->XS + Q->n2*Ls1) * P->ra; + xy.y = (Q->YS + Q->n2*atan(sinh(Ls) / cos(L))) * P->ra; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double L, LC, sinC; + + L = atan(sinh((xy.x * P->a - Q->XS) / Q->n2) / cos((xy.y * P->a - Q->YS) / Q->n2)); + sinC = sin((xy.y * P->a - Q->YS) / Q->n2) / cosh((xy.x * P->a - Q->XS) / Q->n2); + LC = log(pj_tsfn(-1.0 * asin(sinC), 0.0, 0.0)); + lp.lam = L / Q->n1; + lp.phi = -1.0 * pj_phi2(P->ctx, exp((LC - Q->c) / Q->n1), P->e); + + return lp; +} + + +PJ *PROJECTION(gstmerc) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->lamc = P->lam0; + Q->n1 = sqrt(1.0 + P->es * pow(cos(P->phi0), 4.0) / (1.0 - P->es)); + Q->phic = asin(sin(P->phi0) / Q->n1); + Q->c = log(pj_tsfn(-1.0 * Q->phic, 0.0, 0.0)) + - Q->n1 * log(pj_tsfn(-1.0 * P->phi0, -1.0 * sin(P->phi0), P->e)); + Q->n2 = P->k0 * P->a * sqrt(1.0 - P->es) / (1.0 - P->es * sin(P->phi0) * sin(P->phi0)); + Q->XS = 0; + Q->YS = -1.0 * Q->n2 * Q->phic; + + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/hammer.cpp b/src/projections/hammer.cpp new file mode 100644 index 00000000..d4caa656 --- /dev/null +++ b/src/projections/hammer.cpp @@ -0,0 +1,77 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(hammer, "Hammer & Eckert-Greifendorff") + "\n\tMisc Sph, \n\tW= M="; + +#define EPS 1.0e-10 + +namespace { // anonymous namespace +struct pj_opaque { + double w; + double m, rm; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cosphi, d; + + d = sqrt(2./(1. + (cosphi = cos(lp.phi)) * cos(lp.lam *= Q->w))); + xy.x = Q->m * d * cosphi * sin(lp.lam); + xy.y = Q->rm * d * sin(lp.phi); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double z; + + z = sqrt(1. - 0.25*Q->w*Q->w*xy.x*xy.x - 0.25*xy.y*xy.y); + if (fabs(2.*z*z-1.) < EPS) { + lp.lam = HUGE_VAL; + lp.phi = HUGE_VAL; + proj_errno_set(P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); + } else { + lp.lam = aatan2(Q->w * xy.x * z,2. * z * z - 1)/Q->w; + lp.phi = aasin(P->ctx,z * xy.y); + } + return lp; +} + + +PJ *PROJECTION(hammer) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + if (pj_param(P->ctx, P->params, "tW").i) { + if ((Q->w = fabs(pj_param(P->ctx, P->params, "dW").f)) <= 0.) + return pj_default_destructor (P, PJD_ERR_W_OR_M_ZERO_OR_LESS); + } else + Q->w = .5; + if (pj_param(P->ctx, P->params, "tM").i) { + if ((Q->m = fabs(pj_param(P->ctx, P->params, "dM").f)) <= 0.) + return pj_default_destructor (P, PJD_ERR_W_OR_M_ZERO_OR_LESS); + } else + Q->m = 1.; + + Q->rm = 1. / Q->m; + Q->m /= Q->w; + + P->es = 0.; + P->fwd = s_forward; + P->inv = s_inverse; + + return P; +} diff --git a/src/projections/hatano.cpp b/src/projections/hatano.cpp new file mode 100644 index 00000000..019671cc --- /dev/null +++ b/src/projections/hatano.cpp @@ -0,0 +1,83 @@ +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(hatano, "Hatano Asymmetrical Equal Area") "\n\tPCyl, Sph"; + +#define NITER 20 +#define EPS 1e-7 +#define ONETOL 1.000001 +#define CN 2.67595 +#define CS 2.43763 +#define RCN 0.37369906014686373063 +#define RCS 0.41023453108141924738 +#define FYCN 1.75859 +#define FYCS 1.93052 +#define RYCN 0.56863737426006061674 +#define RYCS 0.51799515156538134803 +#define FXC 0.85 +#define RXC 1.17647058823529411764 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double th1, c; + int i; + (void) P; + + c = sin(lp.phi) * (lp.phi < 0. ? CS : CN); + for (i = NITER; i; --i) { + lp.phi -= th1 = (lp.phi + sin(lp.phi) - c) / (1. + cos(lp.phi)); + if (fabs(th1) < EPS) break; + } + xy.x = FXC * lp.lam * cos(lp.phi *= .5); + xy.y = sin(lp.phi) * (lp.phi < 0. ? FYCS : FYCN); + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double th; + + th = xy.y * ( xy.y < 0. ? RYCS : RYCN); + if (fabs(th) > 1.) { + if (fabs(th) > ONETOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } else { + th = th > 0. ? M_HALFPI : - M_HALFPI; + } + } else { + th = asin(th); + } + + lp.lam = RXC * xy.x / cos(th); + th += th; + lp.phi = (th + sin(th)) * (xy.y < 0. ? RCS : RCN); + if (fabs(lp.phi) > 1.) { + if (fabs(lp.phi) > ONETOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } else { + lp.phi = lp.phi > 0. ? M_HALFPI : - M_HALFPI; + } + } else { + lp.phi = asin(lp.phi); + } + + return (lp); +} + + +PJ *PROJECTION(hatano) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/healpix.cpp b/src/projections/healpix.cpp new file mode 100644 index 00000000..7f0b3e83 --- /dev/null +++ b/src/projections/healpix.cpp @@ -0,0 +1,674 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the HEALPix and rHEALPix projections. + * For background see . + * Authors: Alex Raichev (raichev@cs.auckland.ac.nz) + * Michael Speth (spethm@landcareresearch.co.nz) + * Notes: Raichev implemented these projections in Python and + * Speth translated them into C here. + ****************************************************************************** + * 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 substcounteral 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. + *****************************************************************************/ +#define PJ_LIB__ + +#include +#include + +#include "proj_internal.h" +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(healpix, "HEALPix") "\n\tSph&Ell"; +PROJ_HEAD(rhealpix, "rHEALPix") "\n\tSph&Ell\n\tnorth_square= south_square="; + +/* Matrix for counterclockwise rotation by pi/2: */ +# define R1 {{ 0,-1},{ 1, 0}} +/* Matrix for counterclockwise rotation by pi: */ +# define R2 {{-1, 0},{ 0,-1}} +/* Matrix for counterclockwise rotation by 3*pi/2: */ +# define R3 {{ 0, 1},{-1, 0}} +/* Identity matrix */ +# define IDENT {{1, 0},{0, 1}} +/* IDENT, R1, R2, R3, R1 inverse, R2 inverse, R3 inverse:*/ +# define ROT {IDENT, R1, R2, R3, R3, R2, R1} +/* Fuzz to handle rounding errors: */ +# define EPS 1e-15 + +namespace { // anonymous namespace +struct pj_opaque { + int north_square; + int south_square; + double qp; + double *apa; +}; +} // anonymous namespace + +typedef struct { + int cn; /* An integer 0--3 indicating the position of the polar cap. */ + double x, y; /* Coordinates of the pole point (point of most extreme latitude on the polar caps). */ + enum Region {north, south, equatorial} region; +} CapMap; + +static const double rot[7][2][2] = ROT; + +/** + * Returns the sign of the double. + * @param v the parameter whose sign is returned. + * @return 1 for positive number, -1 for negative, and 0 for zero. + **/ +static double sign (double v) { + return v > 0 ? 1 : (v < 0 ? -1 : 0); +} + + +/** + * Return the index of the matrix in ROT. + * @param index ranges from -3 to 3. + */ +static int get_rotate_index(int index) { + switch(index) { + case 0: + return 0; + case 1: + return 1; + case 2: + return 2; + case 3: + return 3; + case -1: + return 4; + case -2: + return 5; + case -3: + return 6; + } + return 0; +} + + +/** + * Return 1 if point (testx, testy) lies in the interior of the polygon + * determined by the vertices in vert, and return 0 otherwise. + * See http://paulbourke.net/geometry/polygonmesh/ for more details. + * @param nvert the number of vertices in the polygon. + * @param vert the (x, y)-coordinates of the polygon's vertices + **/ +static int pnpoly(int nvert, double vert[][2], double testx, double testy) { + int i; + int counter = 0; + double xinters; + XY p1, p2; + + /* Check for boundrary cases */ + for (i = 0; i < nvert; i++) { + if (testx == vert[i][0] && testy == vert[i][1]) { + return 1; + } + } + + p1.x = vert[0][0]; + p1.y = vert[0][1]; + + for (i = 1; i < nvert; i++) { + p2.x = vert[i % nvert][0]; + p2.y = vert[i % nvert][1]; + if (testy > MIN(p1.y, p2.y) && + testy <= MAX(p1.y, p2.y) && + testx <= MAX(p1.x, p2.x) && + p1.y != p2.y) + { + xinters = (testy-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x; + if (p1.x == p2.x || testx <= xinters) + counter++; + } + p1 = p2; + } + + if (counter % 2 == 0) { + return 0; + } else { + return 1; + } +} + + +/** + * Return 1 if (x, y) lies in (the interior or boundary of) the image of the + * HEALPix projection (in case proj=0) or in the image the rHEALPix projection + * (in case proj=1), and return 0 otherwise. + * @param north_square the position of the north polar square (rHEALPix only) + * @param south_square the position of the south polar square (rHEALPix only) + **/ +static int in_image(double x, double y, int proj, int north_square, + int south_square) { + if (proj == 0) { + double healpixVertsJit[][2] = { + {-M_PI - EPS, M_FORTPI}, + {-3*M_FORTPI, M_HALFPI + EPS}, + {-M_HALFPI, M_FORTPI + EPS}, + {-M_FORTPI, M_HALFPI + EPS}, + {0.0, M_FORTPI + EPS}, + {M_FORTPI, M_HALFPI + EPS}, + {M_HALFPI, M_FORTPI + EPS}, + {3*M_FORTPI, M_HALFPI + EPS}, + {M_PI + EPS, M_FORTPI}, + {M_PI + EPS, -M_FORTPI}, + {3*M_FORTPI, -M_HALFPI - EPS}, + {M_HALFPI, -M_FORTPI - EPS}, + {M_FORTPI, -M_HALFPI - EPS}, + {0.0, -M_FORTPI - EPS}, + {-M_FORTPI, -M_HALFPI - EPS}, + {-M_HALFPI, -M_FORTPI - EPS}, + {-3*M_FORTPI, -M_HALFPI - EPS}, + {-M_PI - EPS, -M_FORTPI} + }; + return pnpoly((int)sizeof(healpixVertsJit)/ + sizeof(healpixVertsJit[0]), healpixVertsJit, x, y); + } else { + /** + * Assigning each element by index to avoid warnings such as + * 'initializer element is not computable at load time'. + * Before C99 this was not allowed and to keep as portable as + * possible we do it the C89 way here. + * We need to assign the array this way because the input is + * dynamic (north_square and south_square vars are unknown at + * compile time). + **/ + double rhealpixVertsJit[12][2]; + rhealpixVertsJit[0][0] = -M_PI - EPS; + rhealpixVertsJit[0][1] = M_FORTPI + EPS; + rhealpixVertsJit[1][0] = -M_PI + north_square*M_HALFPI- EPS; + rhealpixVertsJit[1][1] = M_FORTPI + EPS; + rhealpixVertsJit[2][0] = -M_PI + north_square*M_HALFPI- EPS; + rhealpixVertsJit[2][1] = 3*M_FORTPI + EPS; + rhealpixVertsJit[3][0] = -M_PI + (north_square + 1.0)*M_HALFPI + EPS; + rhealpixVertsJit[3][1] = 3*M_FORTPI + EPS; + rhealpixVertsJit[4][0] = -M_PI + (north_square + 1.0)*M_HALFPI + EPS; + rhealpixVertsJit[4][1] = M_FORTPI + EPS; + rhealpixVertsJit[5][0] = M_PI + EPS; + rhealpixVertsJit[5][1] = M_FORTPI + EPS; + rhealpixVertsJit[6][0] = M_PI + EPS; + rhealpixVertsJit[6][1] = -M_FORTPI - EPS; + rhealpixVertsJit[7][0] = -M_PI + (south_square + 1.0)*M_HALFPI + EPS; + rhealpixVertsJit[7][1] = -M_FORTPI - EPS; + rhealpixVertsJit[8][0] = -M_PI + (south_square + 1.0)*M_HALFPI + EPS; + rhealpixVertsJit[8][1] = -3*M_FORTPI - EPS; + rhealpixVertsJit[9][0] = -M_PI + south_square*M_HALFPI - EPS; + rhealpixVertsJit[9][1] = -3*M_FORTPI - EPS; + rhealpixVertsJit[10][0] = -M_PI + south_square*M_HALFPI - EPS; + rhealpixVertsJit[10][1] = -M_FORTPI - EPS; + rhealpixVertsJit[11][0] = -M_PI - EPS; + rhealpixVertsJit[11][1] = -M_FORTPI - EPS; + + return pnpoly((int)sizeof(rhealpixVertsJit)/ + sizeof(rhealpixVertsJit[0]), rhealpixVertsJit, x, y); + } +} + + +/** + * Return the authalic latitude of latitude alpha (if inverse=0) or + * return the approximate latitude of authalic latitude alpha (if inverse=1). + * P contains the relevant ellipsoid parameters. + **/ +static double auth_lat(PJ *P, double alpha, int inverse) { + struct pj_opaque *Q = static_cast(P->opaque); + if (inverse == 0) { + /* Authalic latitude. */ + double q = pj_qsfn(sin(alpha), P->e, 1.0 - P->es); + double qp = Q->qp; + double ratio = q/qp; + + if (fabs(ratio) > 1) { + /* Rounding error. */ + ratio = sign(ratio); + } + return asin(ratio); + } else { + /* Approximation to inverse authalic latitude. */ + return pj_authlat(alpha, Q->apa); + } +} + + +/** + * Return the HEALPix projection of the longitude-latitude point lp on + * the unit sphere. +**/ +static XY healpix_sphere(LP lp) { + double lam = lp.lam; + double phi = lp.phi; + double phi0 = asin(2.0/3.0); + XY xy; + + /* equatorial region */ + if ( fabs(phi) <= phi0) { + xy.x = lam; + xy.y = 3*M_PI/8*sin(phi); + } else { + double lamc; + double sigma = sqrt(3*(1 - fabs(sin(phi)))); + double cn = floor(2*lam / M_PI + 2); + if (cn >= 4) { + cn = 3; + } + lamc = -3*M_FORTPI + M_HALFPI*cn; + xy.x = lamc + (lam - lamc)*sigma; + xy.y = sign(phi)*M_FORTPI*(2 - sigma); + } + return xy; +} + + +/** + * Return the inverse of healpix_sphere(). +**/ +static LP healpix_sphere_inverse(XY xy) { + LP lp; + double x = xy.x; + double y = xy.y; + double y0 = M_FORTPI; + + /* Equatorial region. */ + if (fabs(y) <= y0) { + lp.lam = x; + lp.phi = asin(8*y/(3*M_PI)); + } else if (fabs(y) < M_HALFPI) { + double cn = floor(2*x/M_PI + 2); + double xc, tau; + if (cn >= 4) { + cn = 3; + } + xc = -3*M_FORTPI + M_HALFPI*cn; + tau = 2.0 - 4*fabs(y)/M_PI; + lp.lam = xc + (x - xc)/tau; + lp.phi = sign(y)*asin(1.0 - pow(tau, 2)/3.0); + } else { + lp.lam = -M_PI; + lp.phi = sign(y)*M_HALFPI; + } + return (lp); +} + + +/** + * Return the vector sum a + b, where a and b are 2-dimensional vectors. + * @param ret holds a + b. + **/ +static void vector_add(const double a[2], const double b[2], double *ret) { + int i; + for(i = 0; i < 2; i++) { + ret[i] = a[i] + b[i]; + } +} + + +/** + * Return the vector difference a - b, where a and b are 2-dimensional vectors. + * @param ret holds a - b. + **/ +static void vector_sub(const double a[2], const double b[2], double*ret) { + int i; + for(i = 0; i < 2; i++) { + ret[i] = a[i] - b[i]; + } +} + + +/** + * Return the 2 x 1 matrix product a*b, where a is a 2 x 2 matrix and + * b is a 2 x 1 matrix. + * @param ret holds a*b. + **/ +static void dot_product(const double a[2][2], const double b[2], double *ret) { + int i, j; + int length = 2; + for(i = 0; i < length; i++) { + ret[i] = 0; + for(j = 0; j < length; j++) { + ret[i] += a[i][j]*b[j]; + } + } +} + + +/** + * Return the number of the polar cap, the pole point coordinates, and + * the region that (x, y) lies in. + * If inverse=0, then assume (x,y) lies in the image of the HEALPix + * projection of the unit sphere. + * If inverse=1, then assume (x,y) lies in the image of the + * (north_square, south_square)-rHEALPix projection of the unit sphere. + **/ +static CapMap get_cap(double x, double y, int north_square, int south_square, + int inverse) { + CapMap capmap; + double c; + + capmap.x = x; + capmap.y = y; + if (inverse == 0) { + if (y > M_FORTPI) { + capmap.region = CapMap::north; + c = M_HALFPI; + } else if (y < -M_FORTPI) { + capmap.region = CapMap::south; + c = -M_HALFPI; + } else { + capmap.region = CapMap::equatorial; + capmap.cn = 0; + return capmap; + } + /* polar region */ + if (x < -M_HALFPI) { + capmap.cn = 0; + capmap.x = (-3*M_FORTPI); + capmap.y = c; + } else if (x >= -M_HALFPI && x < 0) { + capmap.cn = 1; + capmap.x = -M_FORTPI; + capmap.y = c; + } else if (x >= 0 && x < M_HALFPI) { + capmap.cn = 2; + capmap.x = M_FORTPI; + capmap.y = c; + } else { + capmap.cn = 3; + capmap.x = 3*M_FORTPI; + capmap.y = c; + } + } else { + if (y > M_FORTPI) { + capmap.region = CapMap::north; + capmap.x = -3*M_FORTPI + north_square*M_HALFPI; + capmap.y = M_HALFPI; + x = x - north_square*M_HALFPI; + } else if (y < -M_FORTPI) { + capmap.region = CapMap::south; + capmap.x = -3*M_FORTPI + south_square*M_HALFPI; + capmap.y = -M_HALFPI; + x = x - south_square*M_HALFPI; + } else { + capmap.region = CapMap::equatorial; + capmap.cn = 0; + return capmap; + } + /* Polar Region, find the HEALPix polar cap number that + x, y moves to when rHEALPix polar square is disassembled. */ + if (capmap.region == CapMap::north) { + if (y >= -x - M_FORTPI - EPS && y < x + 5*M_FORTPI - EPS) { + capmap.cn = (north_square + 1) % 4; + } else if (y > -x -M_FORTPI + EPS && y >= x + 5*M_FORTPI - EPS) { + capmap.cn = (north_square + 2) % 4; + } else if (y <= -x -M_FORTPI + EPS && y > x + 5*M_FORTPI + EPS) { + capmap.cn = (north_square + 3) % 4; + } else { + capmap.cn = north_square; + } + } else if (capmap.region == CapMap::south) { + if (y <= x + M_FORTPI + EPS && y > -x - 5*M_FORTPI + EPS) { + capmap.cn = (south_square + 1) % 4; + } else if (y < x + M_FORTPI - EPS && y <= -x - 5*M_FORTPI + EPS) { + capmap.cn = (south_square + 2) % 4; + } else if (y >= x + M_FORTPI - EPS && y < -x - 5*M_FORTPI - EPS) { + capmap.cn = (south_square + 3) % 4; + } else { + capmap.cn = south_square; + } + } + } + return capmap; +} + + +/** + * Rearrange point (x, y) in the HEALPix projection by + * combining the polar caps into two polar squares. + * Put the north polar square in position north_square and + * the south polar square in position south_square. + * If inverse=1, then uncombine the polar caps. + * @param north_square integer between 0 and 3. + * @param south_square integer between 0 and 3. + **/ +static XY combine_caps(double x, double y, int north_square, int south_square, + int inverse) { + XY xy; + double v[2]; + double c[2]; + double vector[2]; + double v_min_c[2]; + double ret_dot[2]; + const double (*tmpRot)[2]; + int pole = 0; + + CapMap capmap = get_cap(x, y, north_square, south_square, inverse); + if (capmap.region == CapMap::equatorial) { + xy.x = capmap.x; + xy.y = capmap.y; + return xy; + } + + v[0] = x; v[1] = y; + c[0] = capmap.x; c[1] = capmap.y; + + if (inverse == 0) { + /* Rotate (x, y) about its polar cap tip and then translate it to + north_square or south_square. */ + + if (capmap.region == CapMap::north) { + pole = north_square; + tmpRot = rot[get_rotate_index(capmap.cn - pole)]; + } else { + pole = south_square; + tmpRot = rot[get_rotate_index(-1*(capmap.cn - pole))]; + } + } else { + /* Inverse function. + Unrotate (x, y) and then translate it back. */ + + /* disassemble */ + if (capmap.region == CapMap::north) { + pole = north_square; + tmpRot = rot[get_rotate_index(-1*(capmap.cn - pole))]; + } else { + pole = south_square; + tmpRot = rot[get_rotate_index(capmap.cn - pole)]; + } + } + + vector_sub(v, c, v_min_c); + dot_product(tmpRot, v_min_c, ret_dot); + { + double a[2]; + /* Workaround cppcheck git issue */ + double* pa = a; + pa[0] = -3*M_FORTPI + ((inverse == 0) ? pole : capmap.cn) *M_HALFPI; + pa[1] = ((capmap.region == CapMap::north) ? 1 : -1) *M_HALFPI; + vector_add(ret_dot, a, vector); + } + + xy.x = vector[0]; + xy.y = vector[1]; + return xy; +} + + +static XY s_healpix_forward(LP lp, PJ *P) { /* sphere */ + (void) P; + return healpix_sphere(lp); +} + + +static XY e_healpix_forward(LP lp, PJ *P) { /* ellipsoid */ + lp.phi = auth_lat(P, lp.phi, 0); + return healpix_sphere(lp); +} + + +static LP s_healpix_inverse(XY xy, PJ *P) { /* sphere */ + /* Check whether (x, y) lies in the HEALPix image */ + if (in_image(xy.x, xy.y, 0, 0, 0) == 0) { + LP lp; + lp.lam = HUGE_VAL; + lp.phi = HUGE_VAL; + pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); + return lp; + } + return healpix_sphere_inverse(xy); +} + + +static LP e_healpix_inverse(XY xy, PJ *P) { /* ellipsoid */ + LP lp = {0.0,0.0}; + + /* Check whether (x, y) lies in the HEALPix image. */ + if (in_image(xy.x, xy.y, 0, 0, 0) == 0) { + lp.lam = HUGE_VAL; + lp.phi = HUGE_VAL; + pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); + return lp; + } + lp = healpix_sphere_inverse(xy); + lp.phi = auth_lat(P, lp.phi, 1); + return lp; +} + + +static XY s_rhealpix_forward(LP lp, PJ *P) { /* sphere */ + struct pj_opaque *Q = static_cast(P->opaque); + + XY xy = healpix_sphere(lp); + return combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 0); +} + + +static XY e_rhealpix_forward(LP lp, PJ *P) { /* ellipsoid */ + struct pj_opaque *Q = static_cast(P->opaque); + XY xy; + lp.phi = auth_lat(P, lp.phi, 0); + xy = healpix_sphere(lp); + return combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 0); +} + + +static LP s_rhealpix_inverse(XY xy, PJ *P) { /* sphere */ + struct pj_opaque *Q = static_cast(P->opaque); + + /* Check whether (x, y) lies in the rHEALPix image. */ + if (in_image(xy.x, xy.y, 1, Q->north_square, Q->south_square) == 0) { + LP lp; + lp.lam = HUGE_VAL; + lp.phi = HUGE_VAL; + pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); + return lp; + } + xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); + return healpix_sphere_inverse(xy); +} + + +static LP e_rhealpix_inverse(XY xy, PJ *P) { /* ellipsoid */ + struct pj_opaque *Q = static_cast(P->opaque); + LP lp = {0.0,0.0}; + + /* Check whether (x, y) lies in the rHEALPix image. */ + if (in_image(xy.x, xy.y, 1, Q->north_square, Q->south_square) == 0) { + lp.lam = HUGE_VAL; + lp.phi = HUGE_VAL; + pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); + return lp; + } + xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); + lp = healpix_sphere_inverse(xy); + lp.phi = auth_lat(P, lp.phi, 1); + return lp; +} + + +static PJ *destructor (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->apa); + return pj_default_destructor (P, errlev); +} + + +PJ *PROJECTION(healpix) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + if (P->es != 0.0) { + Q->apa = pj_authset(P->es); /* For auth_lat(). */ + if (nullptr==Q->apa) + return destructor(P, ENOMEM); + Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */ + P->a = P->a*sqrt(0.5*Q->qp); /* Set P->a to authalic radius. */ + pj_calc_ellipsoid_params (P, P->a, P->es); /* Ensure we have a consistent parameter set */ + P->fwd = e_healpix_forward; + P->inv = e_healpix_inverse; + } else { + P->fwd = s_healpix_forward; + P->inv = s_healpix_inverse; + } + + return P; +} + + +PJ *PROJECTION(rhealpix) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + Q->north_square = pj_param(P->ctx, P->params,"inorth_square").i; + Q->south_square = pj_param(P->ctx, P->params,"isouth_square").i; + + /* Check for valid north_square and south_square inputs. */ + if (Q->north_square < 0 || Q->north_square > 3) + return destructor (P, PJD_ERR_AXIS); + if (Q->south_square < 0 || Q->south_square > 3) + return destructor (P, PJD_ERR_AXIS); + if (P->es != 0.0) { + Q->apa = pj_authset(P->es); /* For auth_lat(). */ + if (nullptr==Q->apa) + return destructor(P, ENOMEM); + Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */ + P->a = P->a*sqrt(0.5*Q->qp); /* Set P->a to authalic radius. */ + P->ra = 1.0/P->a; + P->fwd = e_rhealpix_forward; + P->inv = e_rhealpix_inverse; + } else { + P->fwd = s_rhealpix_forward; + P->inv = s_rhealpix_inverse; + } + + return P; +} 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 +#include + +#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(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(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(P->opaque)->pj[i]) + static_cast(P->opaque)->pj[i]->destructor(static_cast(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(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; +} diff --git a/src/projections/imw_p.cpp b/src/projections/imw_p.cpp new file mode 100644 index 00000000..012c5caa --- /dev/null +++ b/src/projections/imw_p.cpp @@ -0,0 +1,217 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(imw_p, "International Map of the World Polyconic") + "\n\tMod. Polyconic, Ell\n\tlat_1= and lat_2= [lon_1=]"; + +#define TOL 1e-10 +#define EPS 1e-10 + +namespace { // anonymous namespace +enum Mode { + NONE_IS_ZERO = 0, /* phi_1 and phi_2 != 0 */ + PHI_1_IS_ZERO = 1, /* phi_1 = 0 */ + PHI_2_IS_ZERO = -1 /* phi_2 = 0 */ +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double P, Pp, Q, Qp, R_1, R_2, sphi_1, sphi_2, C2; + double phi_1, phi_2, lam_1; + double *en; + enum Mode mode; +}; +} // anonymous namespace + + +static int phi12(PJ *P, double *del, double *sig) { + struct pj_opaque *Q = static_cast(P->opaque); + int err = 0; + + if (!pj_param(P->ctx, P->params, "tlat_1").i || + !pj_param(P->ctx, P->params, "tlat_2").i) { + err = PJD_ERR_LAT_1_2_UNSPECIFIED; + } else { + Q->phi_1 = pj_param(P->ctx, P->params, "rlat_1").f; + Q->phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; + *del = 0.5 * (Q->phi_2 - Q->phi_1); + *sig = 0.5 * (Q->phi_2 + Q->phi_1); + err = (fabs(*del) < EPS || fabs(*sig) < EPS) ? PJD_ERR_ABS_LAT1_EQ_ABS_LAT2 : 0; + } + return err; +} + + +static XY loc_for(LP lp, PJ *P, double *yc) { + struct pj_opaque *Q = static_cast(P->opaque); + XY xy; + + if (lp.phi == 0.0) { + xy.x = lp.lam; + xy.y = 0.; + } else { + double xa, ya, xb, yb, xc, D, B, m, sp, t, R, C; + + sp = sin(lp.phi); + m = pj_mlfn(lp.phi, sp, cos(lp.phi), Q->en); + xa = Q->Pp + Q->Qp * m; + ya = Q->P + Q->Q * m; + R = 1. / (tan(lp.phi) * sqrt(1. - P->es * sp * sp)); + C = sqrt(R * R - xa * xa); + if (lp.phi < 0.) C = - C; + C += ya - R; + if (Q->mode == PHI_2_IS_ZERO) { + xb = lp.lam; + yb = Q->C2; + } else { + t = lp.lam * Q->sphi_2; + xb = Q->R_2 * sin(t); + yb = Q->C2 + Q->R_2 * (1. - cos(t)); + } + if (Q->mode == PHI_1_IS_ZERO) { + xc = lp.lam; + *yc = 0.; + } else { + t = lp.lam * Q->sphi_1; + xc = Q->R_1 * sin(t); + *yc = Q->R_1 * (1. - cos(t)); + } + D = (xb - xc)/(yb - *yc); + B = xc + D * (C + R - *yc); + xy.x = D * sqrt(R * R * (1 + D * D) - B * B); + if (lp.phi > 0) + xy.x = - xy.x; + xy.x = (B + xy.x) / (1. + D * D); + xy.y = sqrt(R * R - xy.x * xy.x); + if (lp.phi > 0) + xy.y = - xy.y; + xy.y += C + R; + } + return xy; +} + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + double yc; + XY xy = loc_for(lp, P, &yc); + return (xy); +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + XY t; + double yc = 0.0; + int i = 0; + const int N_MAX_ITER = 1000; /* Arbitrarily chosen number... */ + + lp.phi = Q->phi_2; + lp.lam = xy.x / cos(lp.phi); + do { + t = loc_for(lp, P, &yc); + lp.phi = ((lp.phi - Q->phi_1) * (xy.y - yc) / (t.y - yc)) + Q->phi_1; + lp.lam = lp.lam * xy.x / t.x; + i ++; + } while (i < N_MAX_ITER && + (fabs(t.x - xy.x) > TOL || fabs(t.y - xy.y) > TOL)); + + if( i == N_MAX_ITER ) + { + lp.lam = lp.phi = HUGE_VAL; + } + + return lp; +} + + +static void xy(PJ *P, double phi, double *x, double *y, double *sp, double *R) { + double F; + + *sp = sin(phi); + *R = 1./(tan(phi) * sqrt(1. - P->es * *sp * *sp )); + F = static_cast(P->opaque)->lam_1 * *sp; + *y = *R * (1 - cos(F)); + *x = *R * sin(F); +} + + +static PJ *destructor (PJ *P, int errlev) { + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + if( static_cast(P->opaque)->en ) + pj_dealloc (static_cast(P->opaque)->en); + + return pj_default_destructor(P, errlev); +} + + +PJ *PROJECTION(imw_p) { + double del, sig, s, t, x1, x2, T2, y1, m1, m2, y2; + int err; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + if (!(Q->en = pj_enfn(P->es))) return pj_default_destructor (P, ENOMEM); + if( (err = phi12(P, &del, &sig)) != 0) { + return destructor(P, err); + } + if (Q->phi_2 < Q->phi_1) { /* make sure P->phi_1 most southerly */ + del = Q->phi_1; + Q->phi_1 = Q->phi_2; + Q->phi_2 = del; + } + if (pj_param(P->ctx, P->params, "tlon_1").i) + Q->lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; + else { /* use predefined based upon latitude */ + sig = fabs(sig * RAD_TO_DEG); + if (sig <= 60) sig = 2.; + else if (sig <= 76) sig = 4.; + else sig = 8.; + Q->lam_1 = sig * DEG_TO_RAD; + } + Q->mode = NONE_IS_ZERO; + if (Q->phi_1 != 0.0) + xy(P, Q->phi_1, &x1, &y1, &Q->sphi_1, &Q->R_1); + else { + Q->mode = PHI_1_IS_ZERO; + y1 = 0.; + x1 = Q->lam_1; + } + if (Q->phi_2 != 0.0) + xy(P, Q->phi_2, &x2, &T2, &Q->sphi_2, &Q->R_2); + else { + Q->mode = PHI_2_IS_ZERO; + T2 = 0.; + x2 = Q->lam_1; + } + m1 = pj_mlfn(Q->phi_1, Q->sphi_1, cos(Q->phi_1), Q->en); + m2 = pj_mlfn(Q->phi_2, Q->sphi_2, cos(Q->phi_2), Q->en); + t = m2 - m1; + s = x2 - x1; + y2 = sqrt(t * t - s * s) + y1; + Q->C2 = y2 - T2; + t = 1. / t; + Q->P = (m2 * y1 - m1 * y2) * t; + Q->Q = (y2 - y1) * t; + Q->Pp = (m2 * x1 - m1 * x2) * t; + Q->Qp = (x2 - x1) * t; + + P->fwd = e_forward; + P->inv = e_inverse; + P->destructor = destructor; + + return P; +} diff --git a/src/projections/isea.cpp b/src/projections/isea.cpp new file mode 100644 index 00000000..522e6813 --- /dev/null +++ b/src/projections/isea.cpp @@ -0,0 +1,1098 @@ +/* + * This code was entirely written by Nathan Wagner + * and is in the public domain. + */ + +#include +#include +#include +#include +#include +#include + +#define PJ_LIB__ +#include "proj_internal.h" +#include "proj_math.h" +#include "proj.h" +#include "projects.h" + +#define DEG36 0.62831853071795864768 +#define DEG72 1.25663706143591729537 +#define DEG90 M_PI_2 +#define DEG108 1.88495559215387594306 +#define DEG120 2.09439510239319549229 +#define DEG144 2.51327412287183459075 +#define DEG180 M_PI + +/* sqrt(5)/M_PI */ +#define ISEA_SCALE 0.8301572857837594396028083 + +/* 26.565051177 degrees */ +#define V_LAT 0.46364760899944494524 + +/* 52.62263186 */ +#define E_RAD 0.91843818702186776133 + +/* 10.81231696 */ +#define F_RAD 0.18871053072122403508 + +/* R tan(g) sin(60) */ +#define TABLE_G 0.6615845383 + +/* H = 0.25 R tan g = */ +#define TABLE_H 0.1909830056 + +/* in radians */ +#define ISEA_STD_LAT 1.01722196792335072101 +#define ISEA_STD_LON .19634954084936207740 + +namespace { // anonymous namespace +struct hex { + int iso; + long x, y, z; +}; +} // anonymous namespace + +/* y *must* be positive down as the xy /iso conversion assumes this */ +static void hex_xy(struct hex *h) { + if (!h->iso) return; + if (h->x >= 0) { + h->y = -h->y - (h->x+1)/2; + } else { + /* need to round toward -inf, not toward zero, so x-1 */ + h->y = -h->y - h->x/2; + } + h->iso = 0; +} + +static void hex_iso(struct hex *h) { + if (h->iso) return; + + if (h->x >= 0) { + h->y = (-h->y - (h->x+1)/2); + } else { + /* need to round toward -inf, not toward zero, so x-1 */ + h->y = (-h->y - (h->x)/2); + } + + h->z = -h->x - h->y; + h->iso = 1; +} + +static void hexbin2(double width, double x, double y, long *i, long *j) { + double z, rx, ry, rz; + double abs_dx, abs_dy, abs_dz; + long ix, iy, iz, s; + struct hex h; + + x = x / cos(30 * M_PI / 180.0); /* rotated X coord */ + y = y - x / 2.0; /* adjustment for rotated X */ + + /* adjust for actual hexwidth */ + x /= width; + y /= width; + + z = -x - y; + + rx = floor(x + 0.5); + ix = lround(rx); + ry = floor(y + 0.5); + iy = lround(ry); + rz = floor(z + 0.5); + iz = lround(rz); + + s = ix + iy + iz; + + if (s) { + abs_dx = fabs(rx - x); + abs_dy = fabs(ry - y); + abs_dz = fabs(rz - z); + + if (abs_dx >= abs_dy && abs_dx >= abs_dz) { + ix -= s; + } else if (abs_dy >= abs_dx && abs_dy >= abs_dz) { + iy -= s; + } else { + iz -= s; + } + } + h.x = ix; + h.y = iy; + h.z = iz; + h.iso = 1; + + hex_xy(&h); + *i = h.x; + *j = h.y; +} + +namespace { // anonymous namespace +enum isea_poly { ISEA_NONE, ISEA_ICOSAHEDRON = 20 }; +enum isea_topology { ISEA_HEXAGON=6, ISEA_TRIANGLE=3, ISEA_DIAMOND=4 }; +enum isea_address_form { ISEA_GEO, ISEA_Q2DI, ISEA_SEQNUM, ISEA_INTERLEAVE, + ISEA_PLANE, ISEA_Q2DD, ISEA_PROJTRI, ISEA_VERTEX2DD, ISEA_HEX +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct isea_dgg { + int polyhedron; /* ignored, icosahedron */ + double o_lat, o_lon, o_az; /* orientation, radians */ + int pole; /* true if standard snyder */ + int topology; /* ignored, hexagon */ + int aperture; /* valid values depend on partitioning method */ + int resolution; + double radius; /* radius of the earth in meters, ignored 1.0 */ + int output; /* an isea_address_form */ + int triangle; /* triangle of last transformed point */ + int quad; /* quad of last transformed point */ + unsigned long serial; +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct isea_pt { + double x, y; +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct isea_geo { + double lon, lat; +}; +} // anonymous namespace + +/* ENDINC */ + +namespace { // anonymous namespace +enum snyder_polyhedron { + SNYDER_POLY_HEXAGON, SNYDER_POLY_PENTAGON, + SNYDER_POLY_TETRAHEDRON, SNYDER_POLY_CUBE, + SNYDER_POLY_OCTAHEDRON, SNYDER_POLY_DODECAHEDRON, + SNYDER_POLY_ICOSAHEDRON +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct snyder_constants { + double g, G, theta; + /* cppcheck-suppress unusedStructMember */ + double ea_w, ea_a, ea_b, g_w, g_a, g_b; +}; +} // anonymous namespace + +/* TODO put these in radians to avoid a later conversion */ +static const struct snyder_constants constants[] = { + {23.80018260, 62.15458023, 60.0, 3.75, 1.033, 0.968, 5.09, 1.195, 1.0}, + {20.07675127, 55.69063953, 54.0, 2.65, 1.030, 0.983, 3.59, 1.141, 1.027}, + {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {37.37736814, 36.0, 30.0, 17.27, 1.163, 0.860, 13.14, 1.584, 1.0}, +}; + +static struct isea_geo vertex[] = { + {0.0, DEG90}, + {DEG180, V_LAT}, + {-DEG108, V_LAT}, + {-DEG36, V_LAT}, + {DEG36, V_LAT}, + {DEG108, V_LAT}, + {-DEG144, -V_LAT}, + {-DEG72, -V_LAT}, + {0.0, -V_LAT}, + {DEG72, -V_LAT}, + {DEG144, -V_LAT}, + {0.0, -DEG90} +}; + +/* TODO make an isea_pt array of the vertices as well */ + +static int tri_v1[] = {0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 2, 3, 4, 5, 1, 11, 11, 11, 11, 11}; + +/* triangle Centers */ +static const struct isea_geo icostriangles[] = { + {0.0, 0.0}, + {-DEG144, E_RAD}, + {-DEG72, E_RAD}, + {0.0, E_RAD}, + {DEG72, E_RAD}, + {DEG144, E_RAD}, + {-DEG144, F_RAD}, + {-DEG72, F_RAD}, + {0.0, F_RAD}, + {DEG72, F_RAD}, + {DEG144, F_RAD}, + {-DEG108, -F_RAD}, + {-DEG36, -F_RAD}, + {DEG36, -F_RAD}, + {DEG108, -F_RAD}, + {DEG180, -F_RAD}, + {-DEG108, -E_RAD}, + {-DEG36, -E_RAD}, + {DEG36, -E_RAD}, + {DEG108, -E_RAD}, + {DEG180, -E_RAD}, +}; + +static double az_adjustment(int triangle) +{ + double adj; + + struct isea_geo v; + struct isea_geo c; + + v = vertex[tri_v1[triangle]]; + c = icostriangles[triangle]; + + /* TODO looks like the adjustment is always either 0 or 180 */ + /* at least if you pick your vertex carefully */ + adj = atan2(cos(v.lat) * sin(v.lon - c.lon), + cos(c.lat) * sin(v.lat) + - sin(c.lat) * cos(v.lat) * cos(v.lon - c.lon)); + return adj; +} + +static struct isea_pt isea_triangle_xy(int triangle) +{ + struct isea_pt c; + const double Rprime = 0.91038328153090290025; + + triangle = (triangle - 1) % 20; + + c.x = TABLE_G * ((triangle % 5) - 2) * 2.0; + if (triangle > 9) { + c.x += TABLE_G; + } + switch (triangle / 5) { + case 0: + c.y = 5.0 * TABLE_H; + break; + case 1: + c.y = TABLE_H; + break; + case 2: + c.y = -TABLE_H; + break; + case 3: + c.y = -5.0 * TABLE_H; + break; + default: + /* should be impossible */ + exit(EXIT_FAILURE); + }; + c.x *= Rprime; + c.y *= Rprime; + + return c; +} + +/* snyder eq 14 */ +static double sph_azimuth(double f_lon, double f_lat, + double t_lon, double t_lat) +{ + double az; + + az = atan2(cos(t_lat) * sin(t_lon - f_lon), + cos(f_lat) * sin(t_lat) + - sin(f_lat) * cos(t_lat) * cos(t_lon - f_lon) + ); + return az; +} + +#ifdef _MSC_VER +#pragma warning( push ) +/* disable unreachable code warning for return 0 */ +#pragma warning( disable : 4702 ) +#endif + +/* coord needs to be in radians */ +static int isea_snyder_forward(struct isea_geo * ll, struct isea_pt * out) +{ + int i; + + /* + * spherical distance from center of polygon face to any of its + * vertexes on the globe + */ + double g; + + /* + * spherical angle between radius vector to center and adjacent edge + * of spherical polygon on the globe + */ + double G; + + /* + * plane angle between radius vector to center and adjacent edge of + * plane polygon + */ + double theta; + + /* additional variables from snyder */ + double q, Rprime, H, Ag, Azprime, Az, dprime, f, rho, + x, y; + + /* variables used to store intermediate results */ + double cot_theta, tan_g, az_offset; + + /* how many multiples of 60 degrees we adjust the azimuth */ + int Az_adjust_multiples; + + struct snyder_constants c; + + /* + * TODO by locality of reference, start by trying the same triangle + * as last time + */ + + /* TODO put these constants in as radians to begin with */ + c = constants[SNYDER_POLY_ICOSAHEDRON]; + theta = PJ_TORAD(c.theta); + g = PJ_TORAD(c.g); + G = PJ_TORAD(c.G); + + for (i = 1; i <= 20; i++) { + double z; + struct isea_geo center; + + center = icostriangles[i]; + + /* step 1 */ + z = acos(sin(center.lat) * sin(ll->lat) + + cos(center.lat) * cos(ll->lat) * cos(ll->lon - center.lon)); + /* not on this triangle */ + if (z > g + 0.000005) { /* TODO DBL_EPSILON */ + continue; + } + + Az = sph_azimuth(center.lon, center.lat, ll->lon, ll->lat); + + /* step 2 */ + + /* This calculates "some" vertex coordinate */ + az_offset = az_adjustment(i); + + Az -= az_offset; + + /* TODO I don't know why we do this. It's not in snyder */ + /* maybe because we should have picked a better vertex */ + if (Az < 0.0) { + Az += 2.0 * M_PI; + } + /* + * adjust Az for the point to fall within the range of 0 to + * 2(90 - theta) or 60 degrees for the hexagon, by + * and therefore 120 degrees for the triangle + * of the icosahedron + * subtracting or adding multiples of 60 degrees to Az and + * recording the amount of adjustment + */ + + Az_adjust_multiples = 0; + while (Az < 0.0) { + Az += DEG120; + Az_adjust_multiples--; + } + while (Az > DEG120 + DBL_EPSILON) { + Az -= DEG120; + Az_adjust_multiples++; + } + + /* step 3 */ + cot_theta = 1.0 / tan(theta); + tan_g = tan(g); /* TODO this is a constant */ + + /* Calculate q from eq 9. */ + /* TODO cot_theta is cot(30) */ + q = atan2(tan_g, cos(Az) + sin(Az) * cot_theta); + + /* not in this triangle */ + if (z > q + 0.000005) { + continue; + } + /* step 4 */ + + /* Apply equations 5-8 and 10-12 in order */ + + /* eq 5 */ + /* Rprime = 0.9449322893 * R; */ + /* R' in the paper is for the truncated */ + Rprime = 0.91038328153090290025; + + /* eq 6 */ + H = acos(sin(Az) * sin(G) * cos(g) - cos(Az) * cos(G)); + + /* eq 7 */ + /* Ag = (Az + G + H - DEG180) * M_PI * R * R / DEG180; */ + Ag = Az + G + H - DEG180; + + /* eq 8 */ + Azprime = atan2(2.0 * Ag, Rprime * Rprime * tan_g * tan_g - 2.0 * Ag * cot_theta); + + /* eq 10 */ + /* cot(theta) = 1.73205080756887729355 */ + dprime = Rprime * tan_g / (cos(Azprime) + sin(Azprime) * cot_theta); + + /* eq 11 */ + f = dprime / (2.0 * Rprime * sin(q / 2.0)); + + /* eq 12 */ + rho = 2.0 * Rprime * f * sin(z / 2.0); + + /* + * add back the same 60 degree multiple adjustment from step + * 2 to Azprime + */ + + Azprime += DEG120 * Az_adjust_multiples; + + /* calculate rectangular coordinates */ + + x = rho * sin(Azprime); + y = rho * cos(Azprime); + + /* + * TODO + * translate coordinates to the origin for the particular + * hexagon on the flattened polyhedral map plot + */ + + out->x = x; + out->y = y; + + return i; + } + + /* + * should be impossible, this implies that the coordinate is not on + * any triangle + */ + + fprintf(stderr, "impossible transform: %f %f is not on any triangle\n", + PJ_TODEG(ll->lon), PJ_TODEG(ll->lat)); + + exit(EXIT_FAILURE); + + /* not reached */ + return 0; /* suppresses a warning */ +} + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +/* + * return the new coordinates of any point in original coordinate system. + * Define a point (newNPold) in original coordinate system as the North Pole in + * new coordinate system, and the great circle connect the original and new + * North Pole as the lon0 longitude in new coordinate system, given any point + * in original coordinate system, this function return the new coordinates. + */ + +/* formula from Snyder, Map Projections: A working manual, p31 */ +/* + * old north pole at np in new coordinates + * could be simplified a bit with fewer intermediates + * + * TODO take a result pointer + */ +static struct isea_geo snyder_ctran(struct isea_geo * np, struct isea_geo * pt) +{ + struct isea_geo npt; + double alpha, phi, lambda, lambda0, beta, lambdap, phip; + double sin_phip; + double lp_b; /* lambda prime minus beta */ + double cos_p, sin_a; + + phi = pt->lat; + lambda = pt->lon; + alpha = np->lat; + beta = np->lon; + lambda0 = beta; + + cos_p = cos(phi); + sin_a = sin(alpha); + + /* mpawm 5-7 */ + sin_phip = sin_a * sin(phi) - cos(alpha) * cos_p * cos(lambda - lambda0); + + /* mpawm 5-8b */ + + /* use the two argument form so we end up in the right quadrant */ + lp_b = atan2(cos_p * sin(lambda - lambda0), + (sin_a * cos_p * cos(lambda - lambda0) + cos(alpha) * sin(phi))); + + lambdap = lp_b + beta; + + /* normalize longitude */ + /* TODO can we just do a modulus ? */ + lambdap = fmod(lambdap, 2 * M_PI); + while (lambdap > M_PI) + lambdap -= 2 * M_PI; + while (lambdap < -M_PI) + lambdap += 2 * M_PI; + + phip = asin(sin_phip); + + npt.lat = phip; + npt.lon = lambdap; + + return npt; +} + +static struct isea_geo isea_ctran(struct isea_geo * np, struct isea_geo * pt, + double lon0) +{ + struct isea_geo npt; + + np->lon += M_PI; + npt = snyder_ctran(np, pt); + np->lon -= M_PI; + + npt.lon -= (M_PI - lon0 + np->lon); + + /* + * snyder is down tri 3, isea is along side of tri1 from vertex 0 to + * vertex 1 these are 180 degrees apart + */ + npt.lon += M_PI; + /* normalize longitude */ + npt.lon = fmod(npt.lon, 2 * M_PI); + while (npt.lon > M_PI) + npt.lon -= 2 * M_PI; + while (npt.lon < -M_PI) + npt.lon += 2 * M_PI; + + return npt; +} + +/* fuller's at 5.2454 west, 2.3009 N, adjacent at 7.46658 deg */ + +static int isea_grid_init(struct isea_dgg * g) +{ + if (!g) + return 0; + + g->polyhedron = 20; + g->o_lat = ISEA_STD_LAT; + g->o_lon = ISEA_STD_LON; + g->o_az = 0.0; + g->aperture = 4; + g->resolution = 6; + g->radius = 1.0; + g->topology = 6; + + return 1; +} + +static void isea_orient_isea(struct isea_dgg * g) +{ + if (!g) + return; + g->o_lat = ISEA_STD_LAT; + g->o_lon = ISEA_STD_LON; + g->o_az = 0.0; +} + +static void isea_orient_pole(struct isea_dgg * g) +{ + if (!g) + return; + g->o_lat = M_PI / 2.0; + g->o_lon = 0.0; + g->o_az = 0; +} + +static int isea_transform(struct isea_dgg * g, struct isea_geo * in, + struct isea_pt * out) +{ + struct isea_geo i, pole; + int tri; + + pole.lat = g->o_lat; + pole.lon = g->o_lon; + + i = isea_ctran(&pole, in, g->o_az); + + tri = isea_snyder_forward(&i, out); + out->x *= g->radius; + out->y *= g->radius; + g->triangle = tri; + + return tri; +} + +#define DOWNTRI(tri) (((tri - 1) / 5) % 2 == 1) + +static void isea_rotate(struct isea_pt * pt, double degrees) +{ + double rad; + + double x, y; + + rad = -degrees * M_PI / 180.0; + while (rad >= 2.0 * M_PI) rad -= 2.0 * M_PI; + while (rad <= -2.0 * M_PI) rad += 2.0 * M_PI; + + x = pt->x * cos(rad) + pt->y * sin(rad); + y = -pt->x * sin(rad) + pt->y * cos(rad); + + pt->x = x; + pt->y = y; +} + +static int isea_tri_plane(int tri, struct isea_pt *pt, double radius) { + struct isea_pt tc; /* center of triangle */ + + if (DOWNTRI(tri)) { + isea_rotate(pt, 180.0); + } + tc = isea_triangle_xy(tri); + tc.x *= radius; + tc.y *= radius; + pt->x += tc.x; + pt->y += tc.y; + + return tri; +} + +/* convert projected triangle coords to quad xy coords, return quad number */ +static int isea_ptdd(int tri, struct isea_pt *pt) { + int downtri, quad; + + downtri = (((tri - 1) / 5) % 2 == 1); + quad = ((tri - 1) % 5) + ((tri - 1) / 10) * 5 + 1; + + isea_rotate(pt, downtri ? 240.0 : 60.0); + if (downtri) { + pt->x += 0.5; + /* pt->y += cos(30.0 * M_PI / 180.0); */ + pt->y += .86602540378443864672; + } + return quad; +} + +static int isea_dddi_ap3odd(struct isea_dgg *g, int quad, struct isea_pt *pt, + struct isea_pt *di) +{ + struct isea_pt v; + double hexwidth; + double sidelength; /* in hexes */ + long d, i; + long maxcoord; + struct hex h; + + /* This is the number of hexes from apex to base of a triangle */ + sidelength = (pow(2.0, g->resolution) + 1.0) / 2.0; + + /* apex to base is cos(30deg) */ + hexwidth = cos(M_PI / 6.0) / sidelength; + + /* TODO I think sidelength is always x.5, so + * (int)sidelength * 2 + 1 might be just as good + */ + maxcoord = lround((sidelength * 2.0)); + + v = *pt; + hexbin2(hexwidth, v.x, v.y, &h.x, &h.y); + h.iso = 0; + hex_iso(&h); + + d = h.x - h.z; + i = h.x + h.y + h.y; + + /* + * you want to test for max coords for the next quad in the same + * "row" first to get the case where both are max + */ + if (quad <= 5) { + if (d == 0 && i == maxcoord) { + /* north pole */ + quad = 0; + d = 0; + i = 0; + } else if (i == maxcoord) { + /* upper right in next quad */ + quad += 1; + if (quad == 6) + quad = 1; + i = maxcoord - d; + d = 0; + } else if (d == maxcoord) { + /* lower right in quad to lower right */ + quad += 5; + d = 0; + } + } else if (quad >= 6) { + if (i == 0 && d == maxcoord) { + /* south pole */ + quad = 11; + d = 0; + i = 0; + } else if (d == maxcoord) { + /* lower right in next quad */ + quad += 1; + if (quad == 11) + quad = 6; + d = maxcoord - i; + i = 0; + } else if (i == maxcoord) { + /* upper right in quad to upper right */ + quad = (quad - 4) % 5; + i = 0; + } + } + + di->x = d; + di->y = i; + + g->quad = quad; + return quad; +} + +static int isea_dddi(struct isea_dgg *g, int quad, struct isea_pt *pt, + struct isea_pt *di) { + struct isea_pt v; + double hexwidth; + long sidelength; /* in hexes */ + struct hex h; + + if (g->aperture == 3 && g->resolution % 2 != 0) { + return isea_dddi_ap3odd(g, quad, pt, di); + } + /* todo might want to do this as an iterated loop */ + if (g->aperture >0) { + sidelength = lround(pow(g->aperture, g->resolution / 2.0)); + } else { + sidelength = g->resolution; + } + + hexwidth = 1.0 / sidelength; + + v = *pt; + isea_rotate(&v, -30.0); + hexbin2(hexwidth, v.x, v.y, &h.x, &h.y); + h.iso = 0; + hex_iso(&h); + + /* we may actually be on another quad */ + if (quad <= 5) { + if (h.x == 0 && h.z == -sidelength) { + /* north pole */ + quad = 0; + h.z = 0; + h.y = 0; + h.x = 0; + } else if (h.z == -sidelength) { + quad = quad + 1; + if (quad == 6) + quad = 1; + h.y = sidelength - h.x; + h.z = h.x - sidelength; + h.x = 0; + } else if (h.x == sidelength) { + quad += 5; + h.y = -h.z; + h.x = 0; + } + } else if (quad >= 6) { + if (h.z == 0 && h.x == sidelength) { + /* south pole */ + quad = 11; + h.x = 0; + h.y = 0; + h.z = 0; + } else if (h.x == sidelength) { + quad = quad + 1; + if (quad == 11) + quad = 6; + h.x = h.y + sidelength; + h.y = 0; + h.z = -h.x; + } else if (h.y == -sidelength) { + quad -= 4; + h.y = 0; + h.z = -h.x; + } + } + di->x = h.x; + di->y = -h.z; + + g->quad = quad; + return quad; +} + +static int isea_ptdi(struct isea_dgg *g, int tri, struct isea_pt *pt, + struct isea_pt *di) { + struct isea_pt v; + int quad; + + v = *pt; + quad = isea_ptdd(tri, &v); + quad = isea_dddi(g, quad, &v, di); + return quad; +} + +/* q2di to seqnum */ + +static long isea_disn(struct isea_dgg *g, int quad, struct isea_pt *di) { + long sidelength; + long sn, height; + long hexes; + + if (quad == 0) { + g->serial = 1; + return g->serial; + } + /* hexes in a quad */ + hexes = lround(pow(g->aperture, g->resolution)); + if (quad == 11) { + g->serial = 1 + 10 * hexes + 1; + return g->serial; + } + if (g->aperture == 3 && g->resolution % 2 == 1) { + height = lround(floor((pow(g->aperture, (g->resolution - 1) / 2.0)))); + sn = ((long)di->x) * height; + sn += ((long)di->y) / height; + sn += (quad - 1) * hexes; + sn += 2; + } else { + sidelength = lround((pow(g->aperture, g->resolution / 2.0))); + sn = lround(floor(((quad - 1) * hexes + sidelength * di->x + di->y + 2))); + } + + g->serial = sn; + return sn; +} + +/* TODO just encode the quad in the d or i coordinate + * quad is 0-11, which can be four bits. + * d' = d << 4 + q, d = d' >> 4, q = d' & 0xf + */ +/* convert a q2di to global hex coord */ +static int isea_hex(struct isea_dgg *g, int tri, + struct isea_pt *pt, struct isea_pt *hex) { + struct isea_pt v; +#ifdef FIXME + long sidelength; + long d, i, x, y; +#endif + int quad; + + quad = isea_ptdi(g, tri, pt, &v); + + hex->x = ((int)v.x << 4) + quad; + hex->y = v.y; + + return 1; +#ifdef FIXME + d = lround(floor(v.x)); + i = lround(floor(v.y)); + + /* Aperture 3 odd resolutions */ + if (g->aperture == 3 && g->resolution % 2 != 0) { + long offset = lround((pow(3.0, g->resolution - 1) + 0.5)); + + d += offset * ((g->quad-1) % 5); + i += offset * ((g->quad-1) % 5); + + if (quad == 0) { + d = 0; + i = offset; + } else if (quad == 11) { + d = 2 * offset; + i = 0; + } else if (quad > 5) { + d += offset; + } + + x = (2*d - i) /3; + y = (2*i - d) /3; + + hex->x = x + offset / 3; + hex->y = y + 2 * offset / 3; + return 1; + } + + /* aperture 3 even resolutions and aperture 4 */ + sidelength = lround((pow(g->aperture, g->resolution / 2.0))); + if (g->quad == 0) { + hex->x = 0; + hex->y = sidelength; + } else if (g->quad == 11) { + hex->x = sidelength * 2; + hex->y = 0; + } else { + hex->x = d + sidelength * ((g->quad-1) % 5); + if (g->quad > 5) hex->x += sidelength; + hex->y = i + sidelength * ((g->quad-1) % 5); + } + + return 1; +#endif +} + +static struct isea_pt isea_forward(struct isea_dgg *g, struct isea_geo *in) +{ + int tri; + struct isea_pt out, coord; + + tri = isea_transform(g, in, &out); + + if (g->output == ISEA_PLANE) { + isea_tri_plane(tri, &out, g->radius); + return out; + } + + /* convert to isea standard triangle size */ + out.x = out.x / g->radius * ISEA_SCALE; + out.y = out.y / g->radius * ISEA_SCALE; + out.x += 0.5; + out.y += 2.0 * .14433756729740644112; + + switch (g->output) { + case ISEA_PROJTRI: + /* nothing to do, already in projected triangle */ + break; + case ISEA_VERTEX2DD: + g->quad = isea_ptdd(tri, &out); + break; + case ISEA_Q2DD: + /* Same as above, we just don't print as much */ + g->quad = isea_ptdd(tri, &out); + break; + case ISEA_Q2DI: + g->quad = isea_ptdi(g, tri, &out, &coord); + return coord; + break; + case ISEA_SEQNUM: + isea_ptdi(g, tri, &out, &coord); + /* disn will set g->serial */ + isea_disn(g, g->quad, &coord); + return coord; + break; + case ISEA_HEX: + isea_hex(g, tri, &out, &coord); + return coord; + break; + } + + return out; +} + +/* + * Proj 4 integration code follows + */ + +PROJ_HEAD(isea, "Icosahedral Snyder Equal Area") "\n\tSph"; + +namespace { // anonymous namespace +struct pj_opaque { + struct isea_dgg dgg; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + struct isea_pt out; + struct isea_geo in; + + in.lon = lp.lam; + in.lat = lp.phi; + + out = isea_forward(&Q->dgg, &in); + + xy.x = out.x; + xy.y = out.y; + + return xy; +} + + +PJ *PROJECTION(isea) { + char *opt; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + + P->fwd = s_forward; + isea_grid_init(&Q->dgg); + + Q->dgg.output = ISEA_PLANE; +/* P->dgg.radius = P->a; / * otherwise defaults to 1 */ + /* calling library will scale, I think */ + + opt = pj_param(P->ctx,P->params, "sorient").s; + if (opt) { + if (!strcmp(opt, "isea")) { + isea_orient_isea(&Q->dgg); + } else if (!strcmp(opt, "pole")) { + isea_orient_pole(&Q->dgg); + } else { + return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); + } + } + + if (pj_param(P->ctx,P->params, "tazi").i) { + Q->dgg.o_az = pj_param(P->ctx,P->params, "razi").f; + } + + if (pj_param(P->ctx,P->params, "tlon_0").i) { + Q->dgg.o_lon = pj_param(P->ctx,P->params, "rlon_0").f; + } + + if (pj_param(P->ctx,P->params, "tlat_0").i) { + Q->dgg.o_lat = pj_param(P->ctx,P->params, "rlat_0").f; + } + + if (pj_param(P->ctx,P->params, "taperture").i) { + Q->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i; + } + + if (pj_param(P->ctx,P->params, "tresolution").i) { + Q->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i; + } + + opt = pj_param(P->ctx,P->params, "smode").s; + if (opt) { + if (!strcmp(opt, "plane")) { + Q->dgg.output = ISEA_PLANE; + } else if (!strcmp(opt, "di")) { + Q->dgg.output = ISEA_Q2DI; + } + else if (!strcmp(opt, "dd")) { + Q->dgg.output = ISEA_Q2DD; + } + else if (!strcmp(opt, "hex")) { + Q->dgg.output = ISEA_HEX; + } + else { + /* TODO verify error code. Possibly eliminate magic */ + return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); + } + } + + if (pj_param(P->ctx,P->params, "trescale").i) { + Q->dgg.radius = ISEA_SCALE; + } + + if (pj_param(P->ctx,P->params, "tresolution").i) { + Q->dgg.resolution = pj_param(P->ctx,P->params, "iresolution").i; + } else { + Q->dgg.resolution = 4; + } + + if (pj_param(P->ctx,P->params, "taperture").i) { + Q->dgg.aperture = pj_param(P->ctx,P->params, "iaperture").i; + } else { + Q->dgg.aperture = 3; + } + + return P; +} 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 +#include + +#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(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(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(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; +} diff --git a/src/projections/labrd.cpp b/src/projections/labrd.cpp new file mode 100644 index 00000000..d3930243 --- /dev/null +++ b/src/projections/labrd.cpp @@ -0,0 +1,132 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(labrd, "Laborde") "\n\tCyl, Sph\n\tSpecial for Madagascar"; +#define EPS 1.e-10 + +namespace { // anonymous namespace +struct pj_opaque { + double kRg, p0s, A, C, Ca, Cb, Cc, Cd; +}; +} // anonymous namespace + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double V1, V2, ps, sinps, cosps, sinps2, cosps2; + double I1, I2, I3, I4, I5, I6, x2, y2, t; + + V1 = Q->A * log( tan(M_FORTPI + .5 * lp.phi) ); + t = P->e * sin(lp.phi); + V2 = .5 * P->e * Q->A * log ((1. + t)/(1. - t)); + ps = 2. * (atan(exp(V1 - V2 + Q->C)) - M_FORTPI); + I1 = ps - Q->p0s; + cosps = cos(ps); cosps2 = cosps * cosps; + sinps = sin(ps); sinps2 = sinps * sinps; + I4 = Q->A * cosps; + I2 = .5 * Q->A * I4 * sinps; + I3 = I2 * Q->A * Q->A * (5. * cosps2 - sinps2) / 12.; + I6 = I4 * Q->A * Q->A; + I5 = I6 * (cosps2 - sinps2) / 6.; + I6 *= Q->A * Q->A * + (5. * cosps2 * cosps2 + sinps2 * (sinps2 - 18. * cosps2)) / 120.; + t = lp.lam * lp.lam; + xy.x = Q->kRg * lp.lam * (I4 + t * (I5 + t * I6)); + xy.y = Q->kRg * (I1 + t * (I2 + t * I3)); + x2 = xy.x * xy.x; + y2 = xy.y * xy.y; + V1 = 3. * xy.x * y2 - xy.x * x2; + V2 = xy.y * y2 - 3. * x2 * xy.y; + xy.x += Q->Ca * V1 + Q->Cb * V2; + xy.y += Q->Ca * V2 - Q->Cb * V1; + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + /* t = 0.0 optimization is to avoid a false positive cppcheck warning */ + /* (cppcheck git beaf29c15867984aa3c2a15cf15bd7576ccde2b3). Might no */ + /* longer be necessary with later versions. */ + double x2, y2, V1, V2, V3, V4, t = 0.0, t2, ps, pe, tpe, s; + double I7, I8, I9, I10, I11, d, Re; + int i; + + x2 = xy.x * xy.x; + y2 = xy.y * xy.y; + V1 = 3. * xy.x * y2 - xy.x * x2; + V2 = xy.y * y2 - 3. * x2 * xy.y; + V3 = xy.x * (5. * y2 * y2 + x2 * (-10. * y2 + x2 )); + V4 = xy.y * (5. * x2 * x2 + y2 * (-10. * x2 + y2 )); + xy.x += - Q->Ca * V1 - Q->Cb * V2 + Q->Cc * V3 + Q->Cd * V4; + xy.y += Q->Cb * V1 - Q->Ca * V2 - Q->Cd * V3 + Q->Cc * V4; + ps = Q->p0s + xy.y / Q->kRg; + pe = ps + P->phi0 - Q->p0s; + + for ( i = 20; i; --i) { + V1 = Q->A * log(tan(M_FORTPI + .5 * pe)); + tpe = P->e * sin(pe); + V2 = .5 * P->e * Q->A * log((1. + tpe)/(1. - tpe)); + t = ps - 2. * (atan(exp(V1 - V2 + Q->C)) - M_FORTPI); + pe += t; + if (fabs(t) < EPS) + break; + } + + t = P->e * sin(pe); + t = 1. - t * t; + Re = P->one_es / ( t * sqrt(t) ); + t = tan(ps); + t2 = t * t; + s = Q->kRg * Q->kRg; + d = Re * P->k0 * Q->kRg; + I7 = t / (2. * d); + I8 = t * (5. + 3. * t2) / (24. * d * s); + d = cos(ps) * Q->kRg * Q->A; + I9 = 1. / d; + d *= s; + I10 = (1. + 2. * t2) / (6. * d); + I11 = (5. + t2 * (28. + 24. * t2)) / (120. * d * s); + x2 = xy.x * xy.x; + lp.phi = pe + x2 * (-I7 + I8 * x2); + lp.lam = xy.x * (I9 + x2 * (-I10 + x2 * I11)); + return lp; +} + + +PJ *PROJECTION(labrd) { + double Az, sinp, R, N, t; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Az = pj_param(P->ctx, P->params, "razi").f; + sinp = sin(P->phi0); + t = 1. - P->es * sinp * sinp; + N = 1. / sqrt(t); + R = P->one_es * N / t; + Q->kRg = P->k0 * sqrt( N * R ); + Q->p0s = atan( sqrt(R / N) * tan(P->phi0) ); + Q->A = sinp / sin(Q->p0s); + t = P->e * sinp; + Q->C = .5 * P->e * Q->A * log((1. + t)/(1. - t)) + + - Q->A * log( tan(M_FORTPI + .5 * P->phi0)) + + log( tan(M_FORTPI + .5 * Q->p0s)); + t = Az + Az; + Q->Ca = (1. - cos(t)) * ( Q->Cb = 1. / (12. * Q->kRg * Q->kRg) ); + Q->Cb *= sin(t); + Q->Cc = 3. * (Q->Ca * Q->Ca - Q->Cb * Q->Cb); + Q->Cd = 6. * Q->Ca * Q->Cb; + + P->inv = e_inverse; + P->fwd = e_forward; + + return P; +} diff --git a/src/projections/laea.cpp b/src/projections/laea.cpp new file mode 100644 index 00000000..dd02c75a --- /dev/null +++ b/src/projections/laea.cpp @@ -0,0 +1,300 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +PROJ_HEAD(laea, "Lambert Azimuthal Equal Area") "\n\tAzi, Sph&Ell"; + +namespace { // anonymous namespace +enum Mode { + N_POLE = 0, + S_POLE = 1, + EQUIT = 2, + OBLIQ = 3 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double sinb1; + double cosb1; + double xmf; + double ymf; + double mmf; + double qp; + double dd; + double rq; + double *apa; + enum Mode mode; +}; +} // anonymous namespace + +#define EPS10 1.e-10 + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, sinlam, sinphi, q, sinb=0.0, cosb=0.0, b=0.0; + + coslam = cos(lp.lam); + sinlam = sin(lp.lam); + sinphi = sin(lp.phi); + q = pj_qsfn(sinphi, P->e, P->one_es); + + if (Q->mode == OBLIQ || Q->mode == EQUIT) { + sinb = q / Q->qp; + cosb = sqrt(1. - sinb * sinb); + } + + switch (Q->mode) { + case OBLIQ: + b = 1. + Q->sinb1 * sinb + Q->cosb1 * cosb * coslam; + break; + case EQUIT: + b = 1. + cosb * coslam; + break; + case N_POLE: + b = M_HALFPI + lp.phi; + q = Q->qp - q; + break; + case S_POLE: + b = lp.phi - M_HALFPI; + q = Q->qp + q; + break; + } + if (fabs(b) < EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + + switch (Q->mode) { + case OBLIQ: + b = sqrt(2. / b); + xy.y = Q->ymf * b * (Q->cosb1 * sinb - Q->sinb1 * cosb * coslam); + goto eqcon; + break; + case EQUIT: + b = sqrt(2. / (1. + cosb * coslam)); + xy.y = b * sinb * Q->ymf; +eqcon: + xy.x = Q->xmf * b * cosb * sinlam; + break; + case N_POLE: + case S_POLE: + if (q >= 0.) { + b = sqrt(q); + xy.x = b * sinlam; + xy.y = coslam * (Q->mode == S_POLE ? b : -b); + } else + xy.x = xy.y = 0.; + break; + } + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, cosphi, sinphi; + + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + coslam = cos(lp.lam); + switch (Q->mode) { + case EQUIT: + xy.y = 1. + cosphi * coslam; + goto oblcon; + case OBLIQ: + xy.y = 1. + Q->sinb1 * sinphi + Q->cosb1 * cosphi * coslam; +oblcon: + if (xy.y <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.y = sqrt(2. / xy.y); + xy.x = xy.y * cosphi * sin(lp.lam); + xy.y *= Q->mode == EQUIT ? sinphi : + Q->cosb1 * sinphi - Q->sinb1 * cosphi * coslam; + break; + case N_POLE: + coslam = -coslam; + /*-fallthrough*/ + case S_POLE: + if (fabs(lp.phi + P->phi0) < EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.y = M_FORTPI - lp.phi * .5; + xy.y = 2. * (Q->mode == S_POLE ? cos(xy.y) : sin(xy.y)); + xy.x = xy.y * sin(lp.lam); + xy.y *= coslam; + break; + } + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cCe, sCe, q, rho, ab=0.0; + + switch (Q->mode) { + case EQUIT: + case OBLIQ: + xy.x /= Q->dd; + xy.y *= Q->dd; + rho = hypot(xy.x, xy.y); + if (rho < EPS10) { + lp.lam = 0.; + lp.phi = P->phi0; + return lp; + } + sCe = 2. * asin(.5 * rho / Q->rq); + cCe = cos(sCe); + sCe = sin(sCe); + xy.x *= sCe; + if (Q->mode == OBLIQ) { + ab = cCe * Q->sinb1 + xy.y * sCe * Q->cosb1 / rho; + xy.y = rho * Q->cosb1 * cCe - xy.y * Q->sinb1 * sCe; + } else { + ab = xy.y * sCe / rho; + xy.y = rho * cCe; + } + break; + case N_POLE: + xy.y = -xy.y; + /*-fallthrough*/ + case S_POLE: + q = (xy.x * xy.x + xy.y * xy.y); + if (q == 0.0) { + lp.lam = 0.; + lp.phi = P->phi0; + return (lp); + } + ab = 1. - q / Q->qp; + if (Q->mode == S_POLE) + ab = - ab; + break; + } + lp.lam = atan2(xy.x, xy.y); + lp.phi = pj_authlat(asin(ab), Q->apa); + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cosz=0.0, rh, sinz=0.0; + + rh = hypot(xy.x, xy.y); + if ((lp.phi = rh * .5 ) > 1.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + lp.phi = 2. * asin(lp.phi); + if (Q->mode == OBLIQ || Q->mode == EQUIT) { + sinz = sin(lp.phi); + cosz = cos(lp.phi); + } + switch (Q->mode) { + case EQUIT: + lp.phi = fabs(rh) <= EPS10 ? 0. : asin(xy.y * sinz / rh); + xy.x *= sinz; + xy.y = cosz * rh; + break; + case OBLIQ: + lp.phi = fabs(rh) <= EPS10 ? P->phi0 : + asin(cosz * Q->sinb1 + xy.y * sinz * Q->cosb1 / rh); + xy.x *= sinz * Q->cosb1; + xy.y = (cosz - sin(lp.phi) * Q->sinb1) * rh; + break; + case N_POLE: + xy.y = -xy.y; + lp.phi = M_HALFPI - lp.phi; + break; + case S_POLE: + lp.phi -= M_HALFPI; + break; + } + lp.lam = (xy.y == 0. && (Q->mode == EQUIT || Q->mode == OBLIQ)) ? + 0. : atan2(xy.x, xy.y); + return (lp); +} + + +static PJ *destructor (PJ *P, int errlev) { + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->apa); + + return pj_default_destructor(P, errlev); +} + + +PJ *PROJECTION(laea) { + double t; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + + t = fabs(P->phi0); + if (fabs(t - M_HALFPI) < EPS10) + Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + else if (fabs(t) < EPS10) + Q->mode = EQUIT; + else + Q->mode = OBLIQ; + if (P->es != 0.0) { + double sinphi; + + P->e = sqrt(P->es); + Q->qp = pj_qsfn(1., P->e, P->one_es); + Q->mmf = .5 / (1. - P->es); + Q->apa = pj_authset(P->es); + if (nullptr==Q->apa) + return destructor(P, ENOMEM); + switch (Q->mode) { + case N_POLE: + case S_POLE: + Q->dd = 1.; + break; + case EQUIT: + Q->dd = 1. / (Q->rq = sqrt(.5 * Q->qp)); + Q->xmf = 1.; + Q->ymf = .5 * Q->qp; + break; + case OBLIQ: + Q->rq = sqrt(.5 * Q->qp); + sinphi = sin(P->phi0); + Q->sinb1 = pj_qsfn(sinphi, P->e, P->one_es) / Q->qp; + Q->cosb1 = sqrt(1. - Q->sinb1 * Q->sinb1); + Q->dd = cos(P->phi0) / (sqrt(1. - P->es * sinphi * sinphi) * + Q->rq * Q->cosb1); + Q->ymf = (Q->xmf = Q->rq) / Q->dd; + Q->xmf *= Q->dd; + break; + } + P->inv = e_inverse; + P->fwd = e_forward; + } else { + if (Q->mode == OBLIQ) { + Q->sinb1 = sin(P->phi0); + Q->cosb1 = cos(P->phi0); + } + P->inv = s_inverse; + P->fwd = s_forward; + } + + return P; +} + diff --git a/src/projections/lagrng.cpp b/src/projections/lagrng.cpp new file mode 100644 index 00000000..8c0150aa --- /dev/null +++ b/src/projections/lagrng.cpp @@ -0,0 +1,98 @@ +#define PJ_LIB__ +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(lagrng, "Lagrange") "\n\tMisc Sph\n\tW="; + +#define TOL 1e-10 + +namespace { // anonymous namespace +struct pj_opaque { + double a1; + double a2; + double hrw; + double hw; + double rw; + double w; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double v, c; + + if (fabs(fabs(lp.phi) - M_HALFPI) < TOL) { + xy.x = 0; + xy.y = lp.phi < 0 ? -2. : 2.; + } else { + lp.phi = sin(lp.phi); + v = Q->a1 * pow((1. + lp.phi)/(1. - lp.phi), Q->hrw); + lp.lam *= Q->rw; + c = 0.5 * (v + 1./v) + cos(lp.lam); + if (c < TOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.x = 2. * sin(lp.lam) / c; + xy.y = (v - 1./v) / c; + } + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double c, x2, y2p, y2m; + + if (fabs(fabs(xy.y) - 2.) < TOL) { + lp.phi = xy.y < 0 ? -M_HALFPI : M_HALFPI; + lp.lam = 0; + } else { + x2 = xy.x * xy.x; + y2p = 2. + xy.y; + y2m = 2. - xy.y; + c = y2p * y2m - x2; + if (fabs(c) < TOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + lp.phi = 2. * atan(pow((y2p * y2p + x2) / (Q->a2 * (y2m * y2m + x2)), Q->hw)) - M_HALFPI; + lp.lam = Q->w * atan2(4. * xy.x, c); + } + return lp; +} + + +PJ *PROJECTION(lagrng) { + double phi1; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->w = pj_param(P->ctx, P->params, "dW").f; + if (Q->w <= 0) + return pj_default_destructor(P, PJD_ERR_W_OR_M_ZERO_OR_LESS); + Q->hw = 0.5 * Q->w; + Q->rw = 1. / Q->w; + Q->hrw = 0.5 * Q->rw; + phi1 = sin(pj_param(P->ctx, P->params, "rlat_1").f); + if (fabs(fabs(phi1) - 1.) < TOL) + return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); + + Q->a1 = pow((1. - phi1)/(1. + phi1), Q->hrw); + Q->a2 = Q->a1 * Q->a1; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} + diff --git a/src/projections/larr.cpp b/src/projections/larr.cpp new file mode 100644 index 00000000..e4d5d240 --- /dev/null +++ b/src/projections/larr.cpp @@ -0,0 +1,28 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(larr, "Larrivee") "\n\tMisc Sph, no inv"; + +#define SIXTH .16666666666666666 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + xy.x = 0.5 * lp.lam * (1. + sqrt(cos(lp.phi))); + xy.y = lp.phi / (cos(0.5 * lp.phi) * cos(SIXTH * lp.lam)); + return xy; +} + + +PJ *PROJECTION(larr) { + + P->es = 0; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/lask.cpp b/src/projections/lask.cpp new file mode 100644 index 00000000..46f23edb --- /dev/null +++ b/src/projections/lask.cpp @@ -0,0 +1,39 @@ +#define PJ_LIB__ +#include "projects.h" + +PROJ_HEAD(lask, "Laskowski") "\n\tMisc Sph, no inv"; + +#define a10 0.975534 +#define a12 -0.119161 +#define a32 -0.0143059 +#define a14 -0.0547009 +#define b01 1.00384 +#define b21 0.0802894 +#define b03 0.0998909 +#define b41 0.000199025 +#define b23 -0.0285500 +#define b05 -0.0491032 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double l2, p2; + (void) P; + + l2 = lp.lam * lp.lam; + p2 = lp.phi * lp.phi; + xy.x = lp.lam * (a10 + p2 * (a12 + l2 * a32 + p2 * a14)); + xy.y = lp.phi * (b01 + l2 * (b21 + p2 * b23 + l2 * b41) + + p2 * (b03 + p2 * b05)); + return xy; +} + + +PJ *PROJECTION(lask) { + + P->fwd = s_forward; + P->es = 0.; + + return P; +} + diff --git a/src/projections/latlong.cpp b/src/projections/latlong.cpp new file mode 100644 index 00000000..1331d59a --- /dev/null +++ b/src/projections/latlong.cpp @@ -0,0 +1,124 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Stub projection implementation for lat/long coordinates. We + * don't actually change the coordinates, but we want proj=latlong + * to act sort of like a projection. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2000, Frank Warmerdam + * + * 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. + *****************************************************************************/ + +/* very loosely based upon DMA code by Bradford W. Drew */ +#define PJ_LIB__ +#include "proj_internal.h" +#include "projects.h" + +PROJ_HEAD(lonlat, "Lat/long (Geodetic)") "\n\t"; +PROJ_HEAD(latlon, "Lat/long (Geodetic alias)") "\n\t"; +PROJ_HEAD(latlong, "Lat/long (Geodetic alias)") "\n\t"; +PROJ_HEAD(longlat, "Lat/long (Geodetic alias)") "\n\t"; + + + static XY latlong_forward(LP lp, PJ *P) { + XY xy = {0.0,0.0}; + (void) P; + xy.x = lp.lam; + xy.y = lp.phi; + return xy; +} + + +static LP latlong_inverse(XY xy, PJ *P) { + LP lp = {0.0,0.0}; + (void) P; + lp.phi = xy.y; + lp.lam = xy.x; + return lp; +} + + + static XYZ latlong_forward_3d (LPZ lpz, PJ *P) { + XYZ xyz = {0,0,0}; + (void) P; + xyz.x = lpz.lam; + xyz.y = lpz.phi; + xyz.z = lpz.z; + return xyz; +} + + +static LPZ latlong_inverse_3d (XYZ xyz, PJ *P) { + LPZ lpz = {0,0,0}; + (void) P; + lpz.lam = xyz.x; + lpz.phi = xyz.y; + lpz.z = xyz.z; + return lpz; +} + +static PJ_COORD latlong_forward_4d (PJ_COORD obs, PJ *P) { + (void) P; + return obs; +} + + +static PJ_COORD latlong_inverse_4d (PJ_COORD obs, PJ *P) { + (void) P; + return obs; +} + + + +static PJ *latlong_setup (PJ *P) { + P->is_latlong = 1; + P->x0 = 0; + P->y0 = 0; + P->inv = latlong_inverse; + P->fwd = latlong_forward; + P->inv3d = latlong_inverse_3d; + P->fwd3d = latlong_forward_3d; + P->inv4d = latlong_inverse_4d; + P->fwd4d = latlong_forward_4d; + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_ANGULAR; + return P; +} + +PJ *PROJECTION(latlong) { + return latlong_setup (P); +} + + +PJ *PROJECTION(longlat) { + return latlong_setup (P); +} + + +PJ *PROJECTION(latlon) { + return latlong_setup (P); +} + + +PJ *PROJECTION(lonlat) { + return latlong_setup (P); +} + diff --git a/src/projections/lcc.cpp b/src/projections/lcc.cpp new file mode 100644 index 00000000..7d6e3f57 --- /dev/null +++ b/src/projections/lcc.cpp @@ -0,0 +1,130 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +PROJ_HEAD(lcc, "Lambert Conformal Conic") + "\n\tConic, Sph&Ell\n\tlat_1= and lat_2= or lat_0, k_0="; + +#define EPS10 1.e-10 + +namespace { // anonymous namespace +struct pj_opaque { + double phi1; + double phi2; + double n; + double rho0; + double c; +}; +} // anonymous namespace + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0., 0.}; + struct pj_opaque *Q = static_cast(P->opaque); + double rho; + + if (fabs(fabs(lp.phi) - M_HALFPI) < EPS10) { + if ((lp.phi * Q->n) <= 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + rho = 0.; + } else { + rho = Q->c * (P->es != 0. ? + pow(pj_tsfn(lp.phi, sin(lp.phi), P->e), Q->n) : + pow(tan(M_FORTPI + .5 * lp.phi), -Q->n)); + } + lp.lam *= Q->n; + xy.x = P->k0 * (rho * sin(lp.lam)); + xy.y = P->k0 * (Q->rho0 - rho * cos(lp.lam)); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0., 0.}; + struct pj_opaque *Q = static_cast(P->opaque); + double rho; + + xy.x /= P->k0; + xy.y /= P->k0; + + xy.y = Q->rho0 - xy.y; + rho = hypot(xy.x, xy.y); + if (rho != 0.) { + if (Q->n < 0.) { + rho = -rho; + xy.x = -xy.x; + xy.y = -xy.y; + } + if (P->es != 0.) { + lp.phi = pj_phi2(P->ctx, pow(rho / Q->c, 1./Q->n), P->e); + if (lp.phi == HUGE_VAL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + + } else + lp.phi = 2. * atan(pow(Q->c / rho, 1./Q->n)) - M_HALFPI; + lp.lam = atan2(xy.x, xy.y) / Q->n; + } else { + lp.lam = 0.; + lp.phi = Q->n > 0. ? M_HALFPI : -M_HALFPI; + } + return lp; +} + + +PJ *PROJECTION(lcc) { + double cosphi, sinphi; + int secant; + struct pj_opaque *Q = static_cast(pj_calloc(1, sizeof (struct pj_opaque))); + + if (nullptr == Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; + if (pj_param(P->ctx, P->params, "tlat_2").i) + Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; + else { + Q->phi2 = Q->phi1; + if (!pj_param(P->ctx, P->params, "tlat_0").i) + P->phi0 = Q->phi1; + } + if (fabs(Q->phi1 + Q->phi2) < EPS10) + return pj_default_destructor(P, PJD_ERR_CONIC_LAT_EQUAL); + + Q->n = sinphi = sin(Q->phi1); + cosphi = cos(Q->phi1); + secant = fabs(Q->phi1 - Q->phi2) >= EPS10; + if (P->es != 0.) { + double ml1, m1; + + m1 = pj_msfn(sinphi, cosphi, P->es); + ml1 = pj_tsfn(Q->phi1, sinphi, P->e); + if (secant) { /* secant cone */ + sinphi = sin(Q->phi2); + Q->n = log(m1 / pj_msfn(sinphi, cos(Q->phi2), P->es)); + Q->n /= log(ml1 / pj_tsfn(Q->phi2, sinphi, P->e)); + } + Q->c = (Q->rho0 = m1 * pow(ml1, -Q->n) / Q->n); + Q->rho0 *= (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) ? 0. : + pow(pj_tsfn(P->phi0, sin(P->phi0), P->e), Q->n); + } else { + if (secant) + Q->n = log(cosphi / cos(Q->phi2)) / + log(tan(M_FORTPI + .5 * Q->phi2) / + tan(M_FORTPI + .5 * Q->phi1)); + Q->c = cosphi * pow(tan(M_FORTPI + .5 * Q->phi1), Q->n) / Q->n; + Q->rho0 = (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) ? 0. : + Q->c * pow(tan(M_FORTPI + .5 * P->phi0), -Q->n); + } + + P->inv = e_inverse; + P->fwd = e_forward; + + return P; +} diff --git a/src/projections/lcca.cpp b/src/projections/lcca.cpp new file mode 100644 index 00000000..70b5dff9 --- /dev/null +++ b/src/projections/lcca.cpp @@ -0,0 +1,164 @@ +/***************************************************************************** + + Lambert Conformal Conic Alternative + ----------------------------------- + + This is Gerald Evenden's 2003 implementation of an alternative + "almost" LCC, which has been in use historically, but which + should NOT be used for new projects - i.e: use this implementation + if you need interoperability with old data represented in this + projection, but not in any other case. + + The code was originally discussed on the PROJ.4 mailing list in + a thread archived over at + + http://lists.maptools.org/pipermail/proj/2003-March/000644.html + + It was discussed again in the thread starting at + + http://lists.maptools.org/pipermail/proj/2017-October/007828.html + and continuing at + http://lists.maptools.org/pipermail/proj/2017-November/007831.html + + which prompted Clifford J. Mugnier to add these clarifying notes: + + The French Army Truncated Cubic Lambert (partially conformal) Conic + projection is the Legal system for the projection in France between + the late 1800s and 1948 when the French Legislature changed the law + to recognize the fully conformal version. + + It was (might still be in one or two North African prior French + Colonies) used in North Africa in Algeria, Tunisia, & Morocco, as + well as in Syria during the Levant. + + Last time I have seen it used was about 30+ years ago in + Algeria when it was used to define Lease Block boundaries for + Petroleum Exploration & Production. + + (signed) + + Clifford J. Mugnier, c.p., c.m.s. + Chief of Geodesy + LSU Center for GeoInformatics + Dept. of Civil Engineering + LOUISIANA STATE UNIVERSITY + +*****************************************************************************/ + +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(lcca, "Lambert Conformal Conic Alternative") + "\n\tConic, Sph&Ell\n\tlat_0="; + +#define MAX_ITER 10 +#define DEL_TOL 1e-12 + +namespace { // anonymous namespace +struct pj_opaque { + double *en; + double r0, l, M0; + double C; +}; +} // anonymous namespace + + +static double fS(double S, double C) { /* func to compute dr */ + + return S * ( 1. + S * S * C); +} + + +static double fSp(double S, double C) { /* deriv of fs */ + + return 1. + 3.* S * S * C; +} + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double S, r, dr; + + S = pj_mlfn(lp.phi, sin(lp.phi), cos(lp.phi), Q->en) - Q->M0; + dr = fS(S, Q->C); + r = Q->r0 - dr; + xy.x = P->k0 * (r * sin( lp.lam *= Q->l ) ); + xy.y = P->k0 * (Q->r0 - r * cos(lp.lam) ); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double theta, dr, S, dif; + int i; + + xy.x /= P->k0; + xy.y /= P->k0; + theta = atan2(xy.x , Q->r0 - xy.y); + dr = xy.y - xy.x * tan(0.5 * theta); + lp.lam = theta / Q->l; + S = dr; + for (i = MAX_ITER; i ; --i) { + S -= (dif = (fS(S, Q->C) - dr) / fSp(S, Q->C)); + if (fabs(dif) < DEL_TOL) break; + } + if (!i) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + lp.phi = pj_inv_mlfn(P->ctx, S + Q->M0, P->es, Q->en); + + return lp; +} + + +static PJ *destructor (PJ *P, int errlev) { + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + +PJ *PROJECTION(lcca) { + double s2p0, N0, R0, tan0; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + (Q->en = pj_enfn(P->es)); + if (!Q->en) + return pj_default_destructor (P, ENOMEM); + + if (P->phi0 == 0.) { + return destructor(P, PJD_ERR_LAT_0_IS_ZERO); + } + Q->l = sin(P->phi0); + Q->M0 = pj_mlfn(P->phi0, Q->l, cos(P->phi0), Q->en); + s2p0 = Q->l * Q->l; + R0 = 1. / (1. - P->es * s2p0); + N0 = sqrt(R0); + R0 *= P->one_es * N0; + tan0 = tan(P->phi0); + Q->r0 = N0 / tan0; + Q->C = 1. / (6. * R0 * N0); + + P->inv = e_inverse; + P->fwd = e_forward; + P->destructor = destructor; + + return P; +} diff --git a/src/projections/loxim.cpp b/src/projections/loxim.cpp new file mode 100644 index 00000000..f68e844a --- /dev/null +++ b/src/projections/loxim.cpp @@ -0,0 +1,77 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(loxim, "Loximuthal") "\n\tPCyl Sph"; + +#define EPS 1e-8 + +namespace { // anonymous namespace +struct pj_opaque { + double phi1; + double cosphi1; + double tanphi1; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + xy.y = lp.phi - Q->phi1; + if (fabs(xy.y) < EPS) + xy.x = lp.lam * Q->cosphi1; + else { + xy.x = M_FORTPI + 0.5 * lp.phi; + if (fabs(xy.x) < EPS || fabs(fabs(xy.x) - M_HALFPI) < EPS) + xy.x = 0.; + else + xy.x = lp.lam * xy.y / log( tan(xy.x) / Q->tanphi1 ); + } + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + lp.phi = xy.y + Q->phi1; + if (fabs(xy.y) < EPS) { + lp.lam = xy.x / Q->cosphi1; + } else { + lp.lam = M_FORTPI + 0.5 * lp.phi; + if (fabs(lp.lam) < EPS || fabs(fabs(lp.lam) - M_HALFPI) < EPS) + lp.lam = 0.; + else + lp.lam = xy.x * log( tan(lp.lam) / Q->tanphi1 ) / xy.y ; + } + return lp; +} + + +PJ *PROJECTION(loxim) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; + Q->cosphi1 = cos(Q->phi1); + if (Q->cosphi1 < EPS) + return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); + + + Q->tanphi1 = tan(M_FORTPI + 0.5 * Q->phi1); + + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + + return P; +} diff --git a/src/projections/lsat.cpp b/src/projections/lsat.cpp new file mode 100644 index 00000000..a0eca1bd --- /dev/null +++ b/src/projections/lsat.cpp @@ -0,0 +1,212 @@ +/* based upon Snyder and Linck, USGS-NMD */ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(lsat, "Space oblique for LANDSAT") + "\n\tCyl, Sph&Ell\n\tlsat= path="; + +#define TOL 1e-7 + +namespace { // anonymous namespace +struct pj_opaque { + double a2, a4, b, c1, c3; + double q, t, u, w, p22, sa, ca, xj, rlm, rlm2; +}; +} // anonymous namespace + +static void seraz0(double lam, double mult, PJ *P) { + struct pj_opaque *Q = static_cast(P->opaque); + double sdsq, h, s, fc, sd, sq, d__1 = 0; + + lam *= DEG_TO_RAD; + sd = sin(lam); + sdsq = sd * sd; + s = Q->p22 * Q->sa * cos(lam) * sqrt((1. + Q->t * sdsq) + / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); + + d__1 = 1. + Q->q * sdsq; + h = sqrt((1. + Q->q * sdsq) / (1. + Q->w * sdsq)) * ((1. + Q->w * sdsq) + / (d__1 * d__1) - Q->p22 * Q->ca); + + sq = sqrt(Q->xj * Q->xj + s * s); + fc = mult * (h * Q->xj - s * s) / sq; + Q->b += fc; + Q->a2 += fc * cos(lam + lam); + Q->a4 += fc * cos(lam * 4.); + fc = mult * s * (h + Q->xj) / sq; + Q->c1 += fc * cos(lam); + Q->c3 += fc * cos(lam * 3.); +} + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + int l, nn; + double lamt = 0.0, xlam, sdsq, c, d, s, lamdp = 0.0, phidp, lampp, tanph; + double lamtp, cl, sd, sp, sav, tanphi; + + if (lp.phi > M_HALFPI) + lp.phi = M_HALFPI; + else if (lp.phi < -M_HALFPI) + lp.phi = -M_HALFPI; + + if (lp.phi >= 0. ) + lampp = M_HALFPI; + else + lampp = M_PI_HALFPI; + tanphi = tan(lp.phi); + for (nn = 0;;) { + double fac; + sav = lampp; + lamtp = lp.lam + Q->p22 * lampp; + cl = cos(lamtp); + if( cl < 0 ) + fac = lampp + sin(lampp) * M_HALFPI; + else + fac = lampp - sin(lampp) * M_HALFPI; + for (l = 50; l >= 0; --l) { + lamt = lp.lam + Q->p22 * sav; + c = cos(lamt); + if (fabs(c) < TOL) + lamt -= TOL; + xlam = (P->one_es * tanphi * Q->sa + sin(lamt) * Q->ca) / c; + lamdp = atan(xlam) + fac; + if (fabs(fabs(sav) - fabs(lamdp)) < TOL) + break; + sav = lamdp; + } + if (!l || ++nn >= 3 || (lamdp > Q->rlm && lamdp < Q->rlm2)) + break; + if (lamdp <= Q->rlm) + lampp = M_TWOPI_HALFPI; + else if (lamdp >= Q->rlm2) + lampp = M_HALFPI; + } + if (l) { + sp = sin(lp.phi); + phidp = aasin(P->ctx,(P->one_es * Q->ca * sp - Q->sa * cos(lp.phi) * + sin(lamt)) / sqrt(1. - P->es * sp * sp)); + tanph = log(tan(M_FORTPI + .5 * phidp)); + sd = sin(lamdp); + sdsq = sd * sd; + s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq) + / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); + d = sqrt(Q->xj * Q->xj + s * s); + xy.x = Q->b * lamdp + Q->a2 * sin(2. * lamdp) + Q->a4 * + sin(lamdp * 4.) - tanph * s / d; + xy.y = Q->c1 * sd + Q->c3 * sin(lamdp * 3.) + tanph * Q->xj / d; + } else + xy.x = xy.y = HUGE_VAL; + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + int nn; + double lamt, sdsq, s, lamdp, phidp, sppsq, dd, sd, sl, fac, scl, sav, spp; + + lamdp = xy.x / Q->b; + nn = 50; + do { + sav = lamdp; + sd = sin(lamdp); + sdsq = sd * sd; + s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq) + / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); + lamdp = xy.x + xy.y * s / Q->xj - Q->a2 * sin( + 2. * lamdp) - Q->a4 * sin(lamdp * 4.) - s / Q->xj * ( + Q->c1 * sin(lamdp) + Q->c3 * sin(lamdp * 3.)); + lamdp /= Q->b; + } while (fabs(lamdp - sav) >= TOL && --nn); + sl = sin(lamdp); + fac = exp(sqrt(1. + s * s / Q->xj / Q->xj) * (xy.y - + Q->c1 * sl - Q->c3 * sin(lamdp * 3.))); + phidp = 2. * (atan(fac) - M_FORTPI); + dd = sl * sl; + if (fabs(cos(lamdp)) < TOL) + lamdp -= TOL; + spp = sin(phidp); + sppsq = spp * spp; + lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) * + Q->ca - spp * Q->sa * sqrt((1. + Q->q * dd) * ( + 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / (1. - sppsq + * (1. + Q->u))); + sl = lamt >= 0. ? 1. : -1.; + scl = cos(lamdp) >= 0. ? 1. : -1; + lamt -= M_HALFPI * (1. - scl) * sl; + lp.lam = lamt - Q->p22 * lamdp; + if (fabs(Q->sa) < TOL) + lp.phi = aasin(P->ctx,spp / sqrt(P->one_es * P->one_es + P->es * sppsq)); + else + lp.phi = atan((tan(lamdp) * cos(lamt) - Q->ca * sin(lamt)) / + (P->one_es * Q->sa)); + return lp; +} + + +PJ *PROJECTION(lsat) { + int land, path; + double lam, alf, esc, ess; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + land = pj_param(P->ctx, P->params, "ilsat").i; + if (land <= 0 || land > 5) + return pj_default_destructor(P, PJD_ERR_LSAT_NOT_IN_RANGE); + + path = pj_param(P->ctx, P->params, "ipath").i; + if (path <= 0 || path > (land <= 3 ? 251 : 233)) + return pj_default_destructor(P, PJD_ERR_PATH_NOT_IN_RANGE); + + if (land <= 3) { + P->lam0 = DEG_TO_RAD * 128.87 - M_TWOPI / 251. * path; + Q->p22 = 103.2669323; + alf = DEG_TO_RAD * 99.092; + } else { + P->lam0 = DEG_TO_RAD * 129.3 - M_TWOPI / 233. * path; + Q->p22 = 98.8841202; + alf = DEG_TO_RAD * 98.2; + } + Q->p22 /= 1440.; + Q->sa = sin(alf); + Q->ca = cos(alf); + if (fabs(Q->ca) < 1e-9) + Q->ca = 1e-9; + esc = P->es * Q->ca * Q->ca; + ess = P->es * Q->sa * Q->sa; + Q->w = (1. - esc) * P->rone_es; + Q->w = Q->w * Q->w - 1.; + Q->q = ess * P->rone_es; + Q->t = ess * (2. - P->es) * P->rone_es * P->rone_es; + Q->u = esc * P->rone_es; + Q->xj = P->one_es * P->one_es * P->one_es; + Q->rlm = M_PI * (1. / 248. + .5161290322580645); + Q->rlm2 = Q->rlm + M_TWOPI; + Q->a2 = Q->a4 = Q->b = Q->c1 = Q->c3 = 0.; + seraz0(0., 1., P); + for (lam = 9.; lam <= 81.0001; lam += 18.) + seraz0(lam, 4., P); + for (lam = 18; lam <= 72.0001; lam += 18.) + seraz0(lam, 2., P); + seraz0(90., 1., P); + Q->a2 /= 30.; + Q->a4 /= 60.; + Q->b /= 30.; + Q->c1 /= 15.; + Q->c3 /= 45.; + + P->inv = e_inverse; + P->fwd = e_forward; + + return P; +} diff --git a/src/projections/mbt_fps.cpp b/src/projections/mbt_fps.cpp new file mode 100644 index 00000000..66ed9458 --- /dev/null +++ b/src/projections/mbt_fps.cpp @@ -0,0 +1,57 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(mbt_fps, "McBryde-Thomas Flat-Pole Sine (No. 2)") "\n\tCyl, Sph"; + +#define MAX_ITER 10 +#define LOOP_TOL 1e-7 +#define C1 0.45503 +#define C2 1.36509 +#define C3 1.41546 +#define C_x 0.22248 +#define C_y 1.44492 +#define C1_2 0.33333333333333333333333333 + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double k, V, t; + int i; + (void) P; + + k = C3 * sin(lp.phi); + for (i = MAX_ITER; i ; --i) { + t = lp.phi / C2; + lp.phi -= V = (C1 * sin(t) + sin(lp.phi) - k) / + (C1_2 * cos(t) + cos(lp.phi)); + if (fabs(V) < LOOP_TOL) + break; + } + t = lp.phi / C2; + xy.x = C_x * lp.lam * (1. + 3. * cos(lp.phi)/cos(t) ); + xy.y = C_y * sin(t); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double t; + + lp.phi = C2 * (t = aasin(P->ctx,xy.y / C_y)); + lp.lam = xy.x / (C_x * (1. + 3. * cos(lp.phi)/cos(t))); + lp.phi = aasin(P->ctx,(C1 * sin(t) + sin(lp.phi)) / C3); + return (lp); +} + + +PJ *PROJECTION(mbt_fps) { + + P->es = 0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/mbtfpp.cpp b/src/projections/mbtfpp.cpp new file mode 100644 index 00000000..276a43eb --- /dev/null +++ b/src/projections/mbtfpp.cpp @@ -0,0 +1,65 @@ +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(mbtfpp, "McBride-Thomas Flat-Polar Parabolic") "\n\tCyl, Sph"; + +#define CS .95257934441568037152 +#define FXC .92582009977255146156 +#define FYC 3.40168025708304504493 +#define C23 .66666666666666666666 +#define C13 .33333333333333333333 +#define ONEEPS 1.0000001 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + lp.phi = asin(CS * sin(lp.phi)); + xy.x = FXC * lp.lam * (2. * cos(C23 * lp.phi) - 1.); + xy.y = FYC * sin(C13 * lp.phi); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + + lp.phi = xy.y / FYC; + if (fabs(lp.phi) >= 1.) { + if (fabs(lp.phi) > ONEEPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } else { + lp.phi = (lp.phi < 0.) ? -M_HALFPI : M_HALFPI; + } + } else + lp.phi = asin(lp.phi); + + lp.lam = xy.x / ( FXC * (2. * cos(C23 * (lp.phi *= 3.)) - 1.) ); + if (fabs(lp.phi = sin(lp.phi) / CS) >= 1.) { + if (fabs(lp.phi) > ONEEPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } else { + lp.phi = (lp.phi < 0.) ? -M_HALFPI : M_HALFPI; + } + } else + lp.phi = asin(lp.phi); + + return lp; +} + + +PJ *PROJECTION(mbtfpp) { + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/mbtfpq.cpp b/src/projections/mbtfpq.cpp new file mode 100644 index 00000000..b7c0eb16 --- /dev/null +++ b/src/projections/mbtfpq.cpp @@ -0,0 +1,74 @@ +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(mbtfpq, "McBryde-Thomas Flat-Polar Quartic") "\n\tCyl, Sph"; + +#define NITER 20 +#define EPS 1e-7 +#define ONETOL 1.000001 +#define C 1.70710678118654752440 +#define RC 0.58578643762690495119 +#define FYC 1.87475828462269495505 +#define RYC 0.53340209679417701685 +#define FXC 0.31245971410378249250 +#define RXC 3.20041258076506210122 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double th1, c; + int i; + (void) P; + + c = C * sin(lp.phi); + for (i = NITER; i; --i) { + lp.phi -= th1 = (sin(.5*lp.phi) + sin(lp.phi) - c) / + (.5*cos(.5*lp.phi) + cos(lp.phi)); + if (fabs(th1) < EPS) break; + } + xy.x = FXC * lp.lam * (1.0 + 2. * cos(lp.phi)/cos(0.5 * lp.phi)); + xy.y = FYC * sin(0.5 * lp.phi); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double t; + + lp.phi = RYC * xy.y; + if (fabs(lp.phi) > 1.) { + if (fabs(lp.phi) > ONETOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + else if (lp.phi < 0.) { t = -1.; lp.phi = -M_PI; } + else { t = 1.; lp.phi = M_PI; } + } else + lp.phi = 2. * asin(t = lp.phi); + lp.lam = RXC * xy.x / (1. + 2. * cos(lp.phi)/cos(0.5 * lp.phi)); + lp.phi = RC * (t + sin(lp.phi)); + if (fabs(lp.phi) > 1.) + if (fabs(lp.phi) > ONETOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + else lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; + else + lp.phi = asin(lp.phi); + return lp; +} + + +PJ *PROJECTION(mbtfpq) { + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/merc.cpp b/src/projections/merc.cpp new file mode 100644 index 00000000..1998234e --- /dev/null +++ b/src/projections/merc.cpp @@ -0,0 +1,101 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj_internal.h" +#include "proj.h" +#include "proj_math.h" +#include "projects.h" + +PROJ_HEAD(merc, "Mercator") "\n\tCyl, Sph&Ell\n\tlat_ts="; +PROJ_HEAD(webmerc, "Web Mercator / Pseudo Mercator") "\n\tCyl, Ell\n\t"; + +#define EPS10 1.e-10 +static double logtanpfpim1(double x) { /* log(tan(x/2 + M_FORTPI)) */ + if (fabs(x) <= DBL_EPSILON) { + /* tan(M_FORTPI + .5 * x) can be approximated by 1.0 + x */ + return log1p(x); + } + return log(tan(M_FORTPI + .5 * x)); +} + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.x = P->k0 * lp.lam; + xy.y = - P->k0 * log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; +} + xy.x = P->k0 * lp.lam; + xy.y = P->k0 * logtanpfpim1(lp.phi); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + if ((lp.phi = pj_phi2(P->ctx, exp(- xy.y / P->k0), P->e)) == HUGE_VAL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; +} + lp.lam = xy.x / P->k0; + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + lp.phi = atan(sinh(xy.y / P->k0)); + lp.lam = xy.x / P->k0; + return lp; +} + + +PJ *PROJECTION(merc) { + double phits=0.0; + int is_phits; + + if( (is_phits = pj_param(P->ctx, P->params, "tlat_ts").i) ) { + phits = fabs(pj_param(P->ctx, P->params, "rlat_ts").f); + if (phits >= M_HALFPI) + return pj_default_destructor(P, PJD_ERR_LAT_TS_LARGER_THAN_90); + } + + if (P->es != 0.0) { /* ellipsoid */ + if (is_phits) + P->k0 = pj_msfn(sin(phits), cos(phits), P->es); + P->inv = e_inverse; + P->fwd = e_forward; + } + + else { /* sphere */ + if (is_phits) + P->k0 = cos(phits); + P->inv = s_inverse; + P->fwd = s_forward; + } + + return P; +} + +PJ *PROJECTION(webmerc) { + + /* Overriding k_0 with fixed parameter */ + P->k0 = 1.0; + + P->inv = s_inverse; + P->fwd = s_forward; + return P; +} diff --git a/src/projections/mill.cpp b/src/projections/mill.cpp new file mode 100644 index 00000000..3ea9636f --- /dev/null +++ b/src/projections/mill.cpp @@ -0,0 +1,37 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(mill, "Miller Cylindrical") "\n\tCyl, Sph"; + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + xy.x = lp.lam; + xy.y = log(tan(M_FORTPI + lp.phi * .4)) * 1.25; + + return (xy); +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + (void) P; + + lp.lam = xy.x; + lp.phi = 2.5 * (atan(exp(.8 * xy.y)) - M_FORTPI); + + return (lp); +} + + +PJ *PROJECTION(mill) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/misrsom.cpp b/src/projections/misrsom.cpp new file mode 100644 index 00000000..c84b96e3 --- /dev/null +++ b/src/projections/misrsom.cpp @@ -0,0 +1,219 @@ +/****************************************************************************** + * This implements Space Oblique Mercator (SOM) projection, used by the + * Multi-angle Imaging SpectroRadiometer (MISR) products, from the NASA EOS Terra + * platform. + * + * The code is identical to that of Landsat SOM (PJ_lsat.c) with the following + * parameter changes: + * + * inclination angle = 98.30382 degrees + * period of revolution = 98.88 minutes + * ascending longitude = 129.3056 degrees - (360 / 233) * path_number + * + * and the following code change: + * + * Q->rlm = PI * (1. / 248. + .5161290322580645); + * + * changed to: + * + * Q->rlm = 0 + * + *****************************************************************************/ +/* based upon Snyder and Linck, USGS-NMD */ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(misrsom, "Space oblique for MISR") + "\n\tCyl, Sph&Ell\n\tpath="; + +#define TOL 1e-7 + +namespace { // anonymous namespace +struct pj_opaque { + double a2, a4, b, c1, c3; + double q, t, u, w, p22, sa, ca, xj, rlm, rlm2; +}; +} // anonymous namespace + +static void seraz0(double lam, double mult, PJ *P) { + struct pj_opaque *Q = static_cast(P->opaque); + double sdsq, h, s, fc, sd, sq, d__1; + + lam *= DEG_TO_RAD; + sd = sin(lam); + sdsq = sd * sd; + s = Q->p22 * Q->sa * cos(lam) * sqrt((1. + Q->t * sdsq) / (( + 1. + Q->w * sdsq) * (1. + Q->q * sdsq))); + d__1 = 1. + Q->q * sdsq; + h = sqrt((1. + Q->q * sdsq) / (1. + Q->w * sdsq)) * ((1. + + Q->w * sdsq) / (d__1 * d__1) - Q->p22 * Q->ca); + sq = sqrt(Q->xj * Q->xj + s * s); + Q->b += fc = mult * (h * Q->xj - s * s) / sq; + Q->a2 += fc * cos(lam + lam); + Q->a4 += fc * cos(lam * 4.); + fc = mult * s * (h + Q->xj) / sq; + Q->c1 += fc * cos(lam); + Q->c3 += fc * cos(lam * 3.); +} + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + int l, nn; + double lamt = 0.0, xlam, sdsq, c, d, s, lamdp = 0.0, phidp, lampp, tanph; + double lamtp, cl, sd, sp, sav, tanphi; + + if (lp.phi > M_HALFPI) + lp.phi = M_HALFPI; + else if (lp.phi < -M_HALFPI) + lp.phi = -M_HALFPI; + if (lp.phi >= 0. ) + lampp = M_HALFPI; + else + lampp = M_PI_HALFPI; + tanphi = tan(lp.phi); + for (nn = 0;;) { + double fac; + sav = lampp; + lamtp = lp.lam + Q->p22 * lampp; + cl = cos(lamtp); + if( cl < 0 ) + fac = lampp + sin(lampp) * M_HALFPI; + else + fac = lampp - sin(lampp) * M_HALFPI; + for (l = 50; l; --l) { + lamt = lp.lam + Q->p22 * sav; + if (fabs(c = cos(lamt)) < TOL) + lamt -= TOL; + xlam = (P->one_es * tanphi * Q->sa + sin(lamt) * Q->ca) / c; + lamdp = atan(xlam) + fac; + if (fabs(fabs(sav) - fabs(lamdp)) < TOL) + break; + sav = lamdp; + } + if (!l || ++nn >= 3 || (lamdp > Q->rlm && lamdp < Q->rlm2)) + break; + if (lamdp <= Q->rlm) + lampp = M_TWOPI_HALFPI; + else if (lamdp >= Q->rlm2) + lampp = M_HALFPI; + } + if (l) { + sp = sin(lp.phi); + phidp = aasin(P->ctx,(P->one_es * Q->ca * sp - Q->sa * cos(lp.phi) * + sin(lamt)) / sqrt(1. - P->es * sp * sp)); + tanph = log(tan(M_FORTPI + .5 * phidp)); + sd = sin(lamdp); + sdsq = sd * sd; + s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq) + / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); + d = sqrt(Q->xj * Q->xj + s * s); + xy.x = Q->b * lamdp + Q->a2 * sin(2. * lamdp) + Q->a4 * + sin(lamdp * 4.) - tanph * s / d; + xy.y = Q->c1 * sd + Q->c3 * sin(lamdp * 3.) + tanph * Q->xj / d; + } else + xy.x = xy.y = HUGE_VAL; + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + int nn; + double lamt, sdsq, s, lamdp, phidp, sppsq, dd, sd, sl, fac, scl, sav, spp; + + lamdp = xy.x / Q->b; + nn = 50; + do { + sav = lamdp; + sd = sin(lamdp); + sdsq = sd * sd; + s = Q->p22 * Q->sa * cos(lamdp) * sqrt((1. + Q->t * sdsq) + / ((1. + Q->w * sdsq) * (1. + Q->q * sdsq))); + lamdp = xy.x + xy.y * s / Q->xj - Q->a2 * sin( + 2. * lamdp) - Q->a4 * sin(lamdp * 4.) - s / Q->xj * ( + Q->c1 * sin(lamdp) + Q->c3 * sin(lamdp * 3.)); + lamdp /= Q->b; + } while (fabs(lamdp - sav) >= TOL && --nn); + sl = sin(lamdp); + fac = exp(sqrt(1. + s * s / Q->xj / Q->xj) * (xy.y - + Q->c1 * sl - Q->c3 * sin(lamdp * 3.))); + phidp = 2. * (atan(fac) - M_FORTPI); + dd = sl * sl; + if (fabs(cos(lamdp)) < TOL) + lamdp -= TOL; + spp = sin(phidp); + sppsq = spp * spp; + lamt = atan(((1. - sppsq * P->rone_es) * tan(lamdp) * + Q->ca - spp * Q->sa * sqrt((1. + Q->q * dd) * ( + 1. - sppsq) - sppsq * Q->u) / cos(lamdp)) / (1. - sppsq + * (1. + Q->u))); + sl = lamt >= 0. ? 1. : -1.; + scl = cos(lamdp) >= 0. ? 1. : -1; + lamt -= M_HALFPI * (1. - scl) * sl; + lp.lam = lamt - Q->p22 * lamdp; + if (fabs(Q->sa) < TOL) + lp.phi = aasin(P->ctx,spp / sqrt(P->one_es * P->one_es + P->es * sppsq)); + else + lp.phi = atan((tan(lamdp) * cos(lamt) - Q->ca * sin(lamt)) / + (P->one_es * Q->sa)); + return lp; +} + + +PJ *PROJECTION(misrsom) { + int path; + double lam, alf, esc, ess; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + path = pj_param(P->ctx, P->params, "ipath").i; + if (path <= 0 || path > 233) + return pj_default_destructor(P, PJD_ERR_PATH_NOT_IN_RANGE); + + P->lam0 = DEG_TO_RAD * 129.3056 - M_TWOPI / 233. * path; + alf = 98.30382 * DEG_TO_RAD; + Q->p22 = 98.88 / 1440.0; + + Q->sa = sin(alf); + Q->ca = cos(alf); + if (fabs(Q->ca) < 1e-9) + Q->ca = 1e-9; + esc = P->es * Q->ca * Q->ca; + ess = P->es * Q->sa * Q->sa; + Q->w = (1. - esc) * P->rone_es; + Q->w = Q->w * Q->w - 1.; + Q->q = ess * P->rone_es; + Q->t = ess * (2. - P->es) * P->rone_es * P->rone_es; + Q->u = esc * P->rone_es; + Q->xj = P->one_es * P->one_es * P->one_es; + Q->rlm = 0; + Q->rlm2 = Q->rlm + M_TWOPI; + Q->a2 = Q->a4 = Q->b = Q->c1 = Q->c3 = 0.; + seraz0(0., 1., P); + for (lam = 9.; lam <= 81.0001; lam += 18.) + seraz0(lam, 4., P); + for (lam = 18; lam <= 72.0001; lam += 18.) + seraz0(lam, 2., P); + seraz0(90., 1., P); + Q->a2 /= 30.; + Q->a4 /= 60.; + Q->b /= 30.; + Q->c1 /= 15.; + Q->c3 /= 45.; + + P->inv = e_inverse; + P->fwd = e_forward; + + return P; +} diff --git a/src/projections/mod_ster.cpp b/src/projections/mod_ster.cpp new file mode 100644 index 00000000..7c4f363b --- /dev/null +++ b/src/projections/mod_ster.cpp @@ -0,0 +1,282 @@ +/* based upon Snyder and Linck, USGS-NMD */ +#define PJ_LIB__ +#include +#include "projects.h" +#include "proj_math.h" + +PROJ_HEAD(mil_os, "Miller Oblated Stereographic") "\n\tAzi(mod)"; +PROJ_HEAD(lee_os, "Lee Oblated Stereographic") "\n\tAzi(mod)"; +PROJ_HEAD(gs48, "Mod. Stereographic of 48 U.S.") "\n\tAzi(mod)"; +PROJ_HEAD(alsk, "Mod. Stereographic of Alaska") "\n\tAzi(mod)"; +PROJ_HEAD(gs50, "Mod. Stereographic of 50 U.S.") "\n\tAzi(mod)"; + +#define EPSLN 1e-12 + +namespace { // anonymous namespace +struct pj_opaque { + const COMPLEX *zcoeff; \ + double cchio, schio; \ + int n; +}; +} // anonymous namespace + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double sinlon, coslon, esphi, chi, schi, cchi, s; + COMPLEX p; + + sinlon = sin(lp.lam); + coslon = cos(lp.lam); + esphi = P->e * sin(lp.phi); + chi = 2. * atan(tan((M_HALFPI + lp.phi) * .5) * + pow((1. - esphi) / (1. + esphi), P->e * .5)) - M_HALFPI; + schi = sin(chi); + cchi = cos(chi); + s = 2. / (1. + Q->schio * schi + Q->cchio * cchi * coslon); + p.r = s * cchi * sinlon; + p.i = s * (Q->cchio * schi - Q->schio * cchi * coslon); + p = pj_zpoly1(p, Q->zcoeff, Q->n); + xy.x = p.r; + xy.y = p.i; + + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + int nn; + COMPLEX p, fxy, fpxy, dp; + double den, rh = 0.0, z, sinz = 0.0, cosz = 0.0, chi, phi = 0.0, esphi; + + p.r = xy.x; + p.i = xy.y; + for (nn = 20; nn ;--nn) { + fxy = pj_zpolyd1(p, Q->zcoeff, Q->n, &fpxy); + fxy.r -= xy.x; + fxy.i -= xy.y; + den = fpxy.r * fpxy.r + fpxy.i * fpxy.i; + dp.r = -(fxy.r * fpxy.r + fxy.i * fpxy.i) / den; + dp.i = -(fxy.i * fpxy.r - fxy.r * fpxy.i) / den; + p.r += dp.r; + p.i += dp.i; + if ((fabs(dp.r) + fabs(dp.i)) <= EPSLN) + break; + } + if (nn) { + rh = hypot(p.r, p.i); + z = 2. * atan(.5 * rh); + sinz = sin(z); + cosz = cos(z); + lp.lam = P->lam0; + if (fabs(rh) <= EPSLN) { + /* if we end up here input coordinates were (0,0). + * pj_inv() adds P->lam0 to lp.lam, this way we are + * sure to get the correct offset */ + lp.lam = 0.0; + lp.phi = P->phi0; + return lp; + } + chi = aasin(P->ctx, cosz * Q->schio + p.i * sinz * Q->cchio / rh); + phi = chi; + for (nn = 20; nn ;--nn) { + double dphi; + esphi = P->e * sin(phi); + dphi = 2. * atan(tan((M_HALFPI + chi) * .5) * + pow((1. + esphi) / (1. - esphi), P->e * .5)) - M_HALFPI - phi; + phi += dphi; + if (fabs(dphi) <= EPSLN) + break; + } + } + if (nn) { + lp.phi = phi; + lp.lam = atan2(p.r * sinz, rh * Q->cchio * cosz - p.i * + Q->schio * sinz); + } else + lp.lam = lp.phi = HUGE_VAL; + return lp; +} + + +static PJ *setup(PJ *P) { /* general initialization */ + struct pj_opaque *Q = static_cast(P->opaque); + double esphi, chio; + + if (P->es != 0.0) { + esphi = P->e * sin(P->phi0); + chio = 2. * atan(tan((M_HALFPI + P->phi0) * .5) * + pow((1. - esphi) / (1. + esphi), P->e * .5)) - M_HALFPI; + } else + chio = P->phi0; + Q->schio = sin(chio); + Q->cchio = cos(chio); + P->inv = e_inverse; + P->fwd = e_forward; + + return P; +} + + +/* Miller Oblated Stereographic */ +PJ *PROJECTION(mil_os) { + static const COMPLEX AB[] = { + {0.924500, 0.}, + {0., 0.}, + {0.019430, 0.} + }; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->n = 2; + P->lam0 = DEG_TO_RAD * 20.; + P->phi0 = DEG_TO_RAD * 18.; + Q->zcoeff = AB; + P->es = 0.; + + return setup(P); +} + + +/* Lee Oblated Stereographic */ +PJ *PROJECTION(lee_os) { + static const COMPLEX AB[] = { + {0.721316, 0.}, + {0., 0.}, + {-0.0088162, -0.00617325} + }; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->n = 2; + P->lam0 = DEG_TO_RAD * -165.; + P->phi0 = DEG_TO_RAD * -10.; + Q->zcoeff = AB; + P->es = 0.; + + return setup(P); +} + + +PJ *PROJECTION(gs48) { + static const COMPLEX /* 48 United States */ + AB[] = { + {0.98879, 0.}, + {0., 0.}, + {-0.050909, 0.}, + {0., 0.}, + {0.075528, 0.} + }; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->n = 4; + P->lam0 = DEG_TO_RAD * -96.; + P->phi0 = DEG_TO_RAD * 39.; + Q->zcoeff = AB; + P->es = 0.; + P->a = 6370997.; + + return setup(P); +} + + +PJ *PROJECTION(alsk) { + static const COMPLEX ABe[] = { /* Alaska ellipsoid */ + { .9945303, 0.}, + { .0052083, -.0027404}, + { .0072721, .0048181}, + {-.0151089, -.1932526}, + { .0642675, -.1381226}, + { .3582802, -.2884586}, + }; + + static const COMPLEX ABs[] = { /* Alaska sphere */ + { .9972523, 0.}, + { .0052513, -.0041175}, + { .0074606, .0048125}, + {-.0153783, -.1968253}, + { .0636871, -.1408027}, + { .3660976, -.2937382} + }; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->n = 5; + P->lam0 = DEG_TO_RAD * -152.; + P->phi0 = DEG_TO_RAD * 64.; + if (P->es != 0.0) { /* fixed ellipsoid/sphere */ + Q->zcoeff = ABe; + P->a = 6378206.4; + P->e = sqrt(P->es = 0.00676866); + } else { + Q->zcoeff = ABs; + P->a = 6370997.; + } + + return setup(P); +} + + +PJ *PROJECTION(gs50) { + static const COMPLEX ABe[] = { /* GS50 ellipsoid */ + { .9827497, 0.}, + { .0210669, .0053804}, + {-.1031415, -.0571664}, + {-.0323337, -.0322847}, + { .0502303, .1211983}, + { .0251805, .0895678}, + {-.0012315, -.1416121}, + { .0072202, -.1317091}, + {-.0194029, .0759677}, + {-.0210072, .0834037} + }; + + static const COMPLEX ABs[] = { /* GS50 sphere */ + { .9842990, 0.}, + { .0211642, .0037608}, + {-.1036018, -.0575102}, + {-.0329095, -.0320119}, + { .0499471, .1223335}, + { .0260460, .0899805}, + { .0007388, -.1435792}, + { .0075848, -.1334108}, + {-.0216473, .0776645}, + {-.0225161, .0853673} + }; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->n = 9; + P->lam0 = DEG_TO_RAD * -120.; + P->phi0 = DEG_TO_RAD * 45.; + if (P->es != 0.0) { /* fixed ellipsoid/sphere */ + Q->zcoeff = ABe; + P->a = 6378206.4; + P->e = sqrt(P->es = 0.00676866); + } else { + Q->zcoeff = ABs; + P->a = 6370997.; + } + + return setup(P); +} + diff --git a/src/projections/moll.cpp b/src/projections/moll.cpp new file mode 100644 index 00000000..c877a1bb --- /dev/null +++ b/src/projections/moll.cpp @@ -0,0 +1,112 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(moll, "Mollweide") "\n\tPCyl, Sph"; +PROJ_HEAD(wag4, "Wagner IV") "\n\tPCyl, Sph"; +PROJ_HEAD(wag5, "Wagner V") "\n\tPCyl, Sph"; + +#define MAX_ITER 10 +#define LOOP_TOL 1e-7 + +namespace { // anonymous namespace +struct pj_opaque { + double C_x, C_y, C_p; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double k, V; + int i; + + k = Q->C_p * sin(lp.phi); + for (i = MAX_ITER; i ; --i) { + lp.phi -= V = (lp.phi + sin(lp.phi) - k) / + (1. + cos(lp.phi)); + if (fabs(V) < LOOP_TOL) + break; + } + if (!i) + lp.phi = (lp.phi < 0.) ? -M_HALFPI : M_HALFPI; + else + lp.phi *= 0.5; + xy.x = Q->C_x * lp.lam * cos(lp.phi); + xy.y = Q->C_y * sin(lp.phi); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + lp.phi = aasin(P->ctx, xy.y / Q->C_y); + lp.lam = xy.x / (Q->C_x * cos(lp.phi)); + if (fabs(lp.lam) < M_PI) { + lp.phi += lp.phi; + lp.phi = aasin(P->ctx, (lp.phi + sin(lp.phi)) / Q->C_p); + } else { + lp.lam = lp.phi = HUGE_VAL; + } + return lp; +} + + +static PJ * setup(PJ *P, double p) { + struct pj_opaque *Q = static_cast(P->opaque); + double r, sp, p2 = p + p; + + P->es = 0; + sp = sin(p); + r = sqrt(M_TWOPI * sp / (p2 + sin(p2))); + + Q->C_x = 2. * r / M_PI; + Q->C_y = r / sp; + Q->C_p = p2 + sin(p2); + + P->inv = s_inverse; + P->fwd = s_forward; + return P; +} + + +PJ *PROJECTION(moll) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + return setup(P, M_HALFPI); +} + + +PJ *PROJECTION(wag4) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + return setup(P, M_PI/3.); +} + +PJ *PROJECTION(wag5) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + P->es = 0; + Q->C_x = 0.90977; + Q->C_y = 1.65014; + Q->C_p = 3.00896; + + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/natearth.cpp b/src/projections/natearth.cpp new file mode 100644 index 00000000..27a6b137 --- /dev/null +++ b/src/projections/natearth.cpp @@ -0,0 +1,100 @@ +/* +The Natural Earth projection was designed by Tom Patterson, US National Park +Service, in 2007, using Flex Projector. The shape of the original projection +was defined at every 5 degrees and piece-wise cubic spline interpolation was +used to compute the complete graticule. +The code here uses polynomial functions instead of cubic splines and +is therefore much simpler to program. The polynomial approximation was +developed by Bojan Savric, in collaboration with Tom Patterson and Bernhard +Jenny, Institute of Cartography, ETH Zurich. It slightly deviates from +Patterson's original projection by adding additional curvature to meridians +where they meet the horizontal pole line. This improvement is by intention +and designed in collaboration with Tom Patterson. +Port to PROJ.4 by Bernhard Jenny, 6 June 2011 +*/ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(natearth, "Natural Earth") "\n\tPCyl, Sph"; + +#define A0 0.8707 +#define A1 -0.131979 +#define A2 -0.013791 +#define A3 0.003971 +#define A4 -0.001529 +#define B0 1.007226 +#define B1 0.015085 +#define B2 -0.044475 +#define B3 0.028874 +#define B4 -0.005916 +#define C0 B0 +#define C1 (3 * B1) +#define C2 (7 * B2) +#define C3 (9 * B3) +#define C4 (11 * B4) +#define EPS 1e-11 +#define MAX_Y (0.8707 * 0.52 * M_PI) +/* Not sure at all of the appropriate number for MAX_ITER... */ +#define MAX_ITER 100 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double phi2, phi4; + (void) P; + + phi2 = lp.phi * lp.phi; + phi4 = phi2 * phi2; + xy.x = lp.lam * (A0 + phi2 * (A1 + phi2 * (A2 + phi4 * phi2 * (A3 + phi2 * A4)))); + xy.y = lp.phi * (B0 + phi2 * (B1 + phi4 * (B2 + B3 * phi2 + B4 * phi4))); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double yc, tol, y2, y4, f, fder; + int i; + (void) P; + + /* make sure y is inside valid range */ + if (xy.y > MAX_Y) { + xy.y = MAX_Y; + } else if (xy.y < -MAX_Y) { + xy.y = -MAX_Y; + } + + /* latitude */ + yc = xy.y; + for (i = MAX_ITER; i ; --i) { /* Newton-Raphson */ + y2 = yc * yc; + y4 = y2 * y2; + f = (yc * (B0 + y2 * (B1 + y4 * (B2 + B3 * y2 + B4 * y4)))) - xy.y; + fder = C0 + y2 * (C1 + y4 * (C2 + C3 * y2 + C4 * y4)); + yc -= tol = f / fder; + if (fabs(tol) < EPS) { + break; + } + } + if( i == 0 ) + pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + lp.phi = yc; + + /* longitude */ + y2 = yc * yc; + lp.lam = xy.x / (A0 + y2 * (A1 + y2 * (A2 + y2 * y2 * y2 * (A3 + y2 * A4)))); + + return lp; +} + + +PJ *PROJECTION(natearth) { + P->es = 0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/natearth2.cpp b/src/projections/natearth2.cpp new file mode 100644 index 00000000..f6aba671 --- /dev/null +++ b/src/projections/natearth2.cpp @@ -0,0 +1,97 @@ +/* +The Natural Earth II projection was designed by Tom Patterson, US National +Park Service, in 2012, using Flex Projector. The polynomial equation was +developed by Bojan Savric and Bernhard Jenny, College of Earth, Ocean, +and Atmospheric Sciences, Oregon State University. +Port to PROJ.4 by Bojan Savric, 4 April 2016 +*/ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(natearth2, "Natural Earth 2") "\n\tPCyl, Sph"; + +#define A0 0.84719 +#define A1 -0.13063 +#define A2 -0.04515 +#define A3 0.05494 +#define A4 -0.02326 +#define A5 0.00331 +#define B0 1.01183 +#define B1 -0.02625 +#define B2 0.01926 +#define B3 -0.00396 +#define C0 B0 +#define C1 (9 * B1) +#define C2 (11 * B2) +#define C3 (13 * B3) +#define EPS 1e-11 +#define MAX_Y (0.84719 * 0.535117535153096 * M_PI) +/* Not sure at all of the appropriate number for MAX_ITER... */ +#define MAX_ITER 100 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double phi2, phi4, phi6; + (void) P; + + phi2 = lp.phi * lp.phi; + phi4 = phi2 * phi2; + phi6 = phi2 * phi4; + + xy.x = lp.lam * (A0 + A1 * phi2 + phi6 * phi6 * (A2 + A3 * phi2 + A4 * phi4 + A5 * phi6)); + xy.y = lp.phi * (B0 + phi4 * phi4 * (B1 + B2 * phi2 + B3 * phi4)); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double yc, tol, y2, y4, y6, f, fder; + int i; + (void) P; + + /* make sure y is inside valid range */ + if (xy.y > MAX_Y) { + xy.y = MAX_Y; + } else if (xy.y < -MAX_Y) { + xy.y = -MAX_Y; + } + + /* latitude */ + yc = xy.y; + for (i = MAX_ITER; i ; --i) { /* Newton-Raphson */ + y2 = yc * yc; + y4 = y2 * y2; + f = (yc * (B0 + y4 * y4 * (B1 + B2 * y2 + B3 * y4))) - xy.y; + fder = C0 + y4 * y4 * (C1 + C2 * y2 + C3 * y4); + yc -= tol = f / fder; + if (fabs(tol) < EPS) { + break; + } + } + if( i == 0 ) + pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + lp.phi = yc; + + /* longitude */ + y2 = yc * yc; + y4 = y2 * y2; + y6 = y2 * y4; + + lp.lam = xy.x / (A0 + A1 * y2 + y6 * y6 * (A2 + A3 * y2 + A4 * y4 + A5 * y6)); + + return lp; +} + + +PJ *PROJECTION(natearth2) { + P->es = 0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/nell.cpp b/src/projections/nell.cpp new file mode 100644 index 00000000..2a7ea32c --- /dev/null +++ b/src/projections/nell.cpp @@ -0,0 +1,51 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(nell, "Nell") "\n\tPCyl, Sph"; + +#define MAX_ITER 10 +#define LOOP_TOL 1e-7 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double k, V; + int i; + (void) P; + + k = 2. * sin(lp.phi); + V = lp.phi * lp.phi; + lp.phi *= 1.00371 + V * (-0.0935382 + V * -0.011412); + for (i = MAX_ITER; i ; --i) { + lp.phi -= V = (lp.phi + sin(lp.phi) - k) / + (1. + cos(lp.phi)); + if (fabs(V) < LOOP_TOL) + break; + } + xy.x = 0.5 * lp.lam * (1. + cos(lp.phi)); + xy.y = lp.phi; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + lp.lam = 2. * xy.x / (1. + cos(xy.y)); + lp.phi = aasin(P->ctx,0.5 * (xy.y + sin(xy.y))); + + return lp; +} + + +PJ *PROJECTION(nell) { + + P->es = 0; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/nell_h.cpp b/src/projections/nell_h.cpp new file mode 100644 index 00000000..28c3ace7 --- /dev/null +++ b/src/projections/nell_h.cpp @@ -0,0 +1,53 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(nell_h, "Nell-Hammer") "\n\tPCyl, Sph"; + +#define NITER 9 +#define EPS 1e-7 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + xy.x = 0.5 * lp.lam * (1. + cos(lp.phi)); + xy.y = 2.0 * (lp.phi - tan(0.5 *lp.phi)); + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double V, c, p; + int i; + (void) P; + + p = 0.5 * xy.y; + for (i = NITER; i ; --i) { + c = cos(0.5 * lp.phi); + lp.phi -= V = (lp.phi - tan(lp.phi/2) - p)/(1. - 0.5/(c*c)); + if (fabs(V) < EPS) + break; + } + if (!i) { + lp.phi = p < 0. ? -M_HALFPI : M_HALFPI; + lp.lam = 2. * xy.x; + } else + lp.lam = 2. * xy.x / (1. + cos(lp.phi)); + + return lp; +} + + +PJ *PROJECTION(nell_h) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/nocol.cpp b/src/projections/nocol.cpp new file mode 100644 index 00000000..541d08b2 --- /dev/null +++ b/src/projections/nocol.cpp @@ -0,0 +1,54 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(nicol, "Nicolosi Globular") "\n\tMisc Sph, no inv"; + +#define EPS 1e-10 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + (void) P; + + if (fabs(lp.lam) < EPS) { + xy.x = 0; + xy.y = lp.phi; + } else if (fabs(lp.phi) < EPS) { + xy.x = lp.lam; + xy.y = 0.; + } else if (fabs(fabs(lp.lam) - M_HALFPI) < EPS) { + xy.x = lp.lam * cos(lp.phi); + xy.y = M_HALFPI * sin(lp.phi); + } else if (fabs(fabs(lp.phi) - M_HALFPI) < EPS) { + xy.x = 0; + xy.y = lp.phi; + } else { + double tb, c, d, m, n, r2, sp; + + tb = M_HALFPI / lp.lam - lp.lam / M_HALFPI; + c = lp.phi / M_HALFPI; + d = (1 - c * c)/((sp = sin(lp.phi)) - c); + r2 = tb / d; + r2 *= r2; + m = (tb * sp / d - 0.5 * tb)/(1. + r2); + n = (sp / r2 + 0.5 * d)/(1. + 1./r2); + xy.x = cos(lp.phi); + xy.x = sqrt(m * m + xy.x * xy.x / (1. + r2)); + xy.x = M_HALFPI * ( m + (lp.lam < 0. ? -xy.x : xy.x)); + xy.y = sqrt(n * n - (sp * sp / r2 + d * sp - 1.) / + (1. + 1./r2)); + xy.y = M_HALFPI * ( n + (lp.phi < 0. ? xy.y : -xy.y )); + } + return (xy); +} + + +PJ *PROJECTION(nicol) { + P->es = 0.; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/nsper.cpp b/src/projections/nsper.cpp new file mode 100644 index 00000000..f93010f8 --- /dev/null +++ b/src/projections/nsper.cpp @@ -0,0 +1,202 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +namespace { // anonymous namespace +enum Mode { + N_POLE = 0, + S_POLE = 1, + EQUIT = 2, + OBLIQ = 3 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double height; + double sinph0; + double cosph0; + double p; + double rp; + double pn1; + double pfact; + double h; + double cg; + double sg; + double sw; + double cw; + enum Mode mode; + int tilt; +}; +} // anonymous namespace + +PROJ_HEAD(nsper, "Near-sided perspective") "\n\tAzi, Sph\n\th="; +PROJ_HEAD(tpers, "Tilted perspective") "\n\tAzi, Sph\n\ttilt= azi= h="; + +# define EPS10 1.e-10 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, cosphi, sinphi; + + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + coslam = cos(lp.lam); + switch (Q->mode) { + case OBLIQ: + xy.y = Q->sinph0 * sinphi + Q->cosph0 * cosphi * coslam; + break; + case EQUIT: + xy.y = cosphi * coslam; + break; + case S_POLE: + xy.y = - sinphi; + break; + case N_POLE: + xy.y = sinphi; + break; + } + if (xy.y < Q->rp) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.y = Q->pn1 / (Q->p - xy.y); + xy.x = xy.y * cosphi * sin(lp.lam); + switch (Q->mode) { + case OBLIQ: + xy.y *= (Q->cosph0 * sinphi - + Q->sinph0 * cosphi * coslam); + break; + case EQUIT: + xy.y *= sinphi; + break; + case N_POLE: + coslam = - coslam; + /*-fallthrough*/ + case S_POLE: + xy.y *= cosphi * coslam; + break; + } + if (Q->tilt) { + double yt, ba; + + yt = xy.y * Q->cg + xy.x * Q->sg; + ba = 1. / (yt * Q->sw * Q->h + Q->cw); + xy.x = (xy.x * Q->cg - xy.y * Q->sg) * Q->cw * ba; + xy.y = yt * ba; + } + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double rh, cosz, sinz; + + if (Q->tilt) { + double bm, bq, yt; + + yt = 1./(Q->pn1 - xy.y * Q->sw); + bm = Q->pn1 * xy.x * yt; + bq = Q->pn1 * xy.y * Q->cw * yt; + xy.x = bm * Q->cg + bq * Q->sg; + xy.y = bq * Q->cg - bm * Q->sg; + } + rh = hypot(xy.x, xy.y); + if ((sinz = 1. - rh * rh * Q->pfact) < 0.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + sinz = (Q->p - sqrt(sinz)) / (Q->pn1 / rh + rh / Q->pn1); + cosz = sqrt(1. - sinz * sinz); + if (fabs(rh) <= EPS10) { + lp.lam = 0.; + lp.phi = P->phi0; + } else { + switch (Q->mode) { + case OBLIQ: + lp.phi = asin(cosz * Q->sinph0 + xy.y * sinz * Q->cosph0 / rh); + xy.y = (cosz - Q->sinph0 * sin(lp.phi)) * rh; + xy.x *= sinz * Q->cosph0; + break; + case EQUIT: + lp.phi = asin(xy.y * sinz / rh); + xy.y = cosz * rh; + xy.x *= sinz; + break; + case N_POLE: + lp.phi = asin(cosz); + xy.y = -xy.y; + break; + case S_POLE: + lp.phi = - asin(cosz); + break; + } + lp.lam = atan2(xy.x, xy.y); + } + return lp; +} + + +static PJ *setup(PJ *P) { + struct pj_opaque *Q = static_cast(P->opaque); + + if ((Q->height = pj_param(P->ctx, P->params, "dh").f) <= 0.) + return pj_default_destructor(P, PJD_ERR_H_LESS_THAN_ZERO); + + if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) + Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + else if (fabs(P->phi0) < EPS10) + Q->mode = EQUIT; + else { + Q->mode = OBLIQ; + Q->sinph0 = sin(P->phi0); + Q->cosph0 = cos(P->phi0); + } + Q->pn1 = Q->height / P->a; /* normalize by radius */ + Q->p = 1. + Q->pn1; + Q->rp = 1. / Q->p; + Q->h = 1. / Q->pn1; + Q->pfact = (Q->p + 1.) * Q->h; + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + + return P; +} + + +PJ *PROJECTION(nsper) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->tilt = 0; + + return setup(P); +} + + +PJ *PROJECTION(tpers) { + double omega, gamma; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + omega = pj_param(P->ctx, P->params, "rtilt").f; + gamma = pj_param(P->ctx, P->params, "razi").f; + Q->tilt = 1; + Q->cg = cos(gamma); Q->sg = sin(gamma); + Q->cw = cos(omega); Q->sw = sin(omega); + + return setup(P); +} + diff --git a/src/projections/nzmg.cpp b/src/projections/nzmg.cpp new file mode 100644 index 00000000..bf0862fb --- /dev/null +++ b/src/projections/nzmg.cpp @@ -0,0 +1,123 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the nzmg (New Zealand Map Grid) projection. + * Very loosely based upon DMA code by Bradford W. Drew + * Author: Gerald Evenden + * + ****************************************************************************** + * Copyright (c) 1995, Gerald Evenden + * + * 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. + *****************************************************************************/ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(nzmg, "New Zealand Map Grid") "\n\tfixed Earth"; + +#define EPSLN 1e-10 +#define SEC5_TO_RAD 0.4848136811095359935899141023 +#define RAD_TO_SEC5 2.062648062470963551564733573 + +static const COMPLEX bf[] = { + { .7557853228, 0.0}, + { .249204646, 0.003371507}, + {-.001541739, 0.041058560}, + {-.10162907, 0.01727609}, + {-.26623489, -0.36249218}, + {-.6870983, -1.1651967} }; + +static const double tphi[] = { 1.5627014243, .5185406398, -.03333098, + -.1052906, -.0368594, .007317, + .01220, .00394, -.0013 }; + +static const double tpsi[] = { .6399175073, -.1358797613, .063294409, -.02526853, .0117879, + -.0055161, .0026906, -.001333, .00067, -.00034 }; + +#define Nbf 5 +#define Ntpsi 9 +#define Ntphi 8 + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + COMPLEX p; + const double *C; + int i; + + lp.phi = (lp.phi - P->phi0) * RAD_TO_SEC5; + for (p.r = *(C = tpsi + (i = Ntpsi)); i ; --i) + p.r = *--C + lp.phi * p.r; + p.r *= lp.phi; + p.i = lp.lam; + p = pj_zpoly1(p, bf, Nbf); + xy.x = p.i; + xy.y = p.r; + + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + int nn, i; + COMPLEX p, f, fp, dp; + double den; + const double *C; + + p.r = xy.y; + p.i = xy.x; + for (nn = 20; nn ;--nn) { + f = pj_zpolyd1(p, bf, Nbf, &fp); + f.r -= xy.y; + f.i -= xy.x; + den = fp.r * fp.r + fp.i * fp.i; + p.r += dp.r = -(f.r * fp.r + f.i * fp.i) / den; + p.i += dp.i = -(f.i * fp.r - f.r * fp.i) / den; + if ((fabs(dp.r) + fabs(dp.i)) <= EPSLN) + break; + } + if (nn) { + lp.lam = p.i; + for (lp.phi = *(C = tphi + (i = Ntphi)); i ; --i) + lp.phi = *--C + p.r * lp.phi; + lp.phi = P->phi0 + p.r * lp.phi * SEC5_TO_RAD; + } else + lp.lam = lp.phi = HUGE_VAL; + + return lp; +} + + +PJ *PROJECTION(nzmg) { + /* force to International major axis */ + P->ra = 1. / (P->a = 6378388.0); + P->lam0 = DEG_TO_RAD * 173.; + P->phi0 = DEG_TO_RAD * -41.; + P->x0 = 2510000.; + P->y0 = 6023150.; + + P->inv = e_inverse; + P->fwd = e_forward; + + + return P; +} diff --git a/src/projections/ob_tran.cpp b/src/projections/ob_tran.cpp new file mode 100644 index 00000000..d34059a9 --- /dev/null +++ b/src/projections/ob_tran.cpp @@ -0,0 +1,245 @@ +#define PJ_LIB__ +#include +#include +#include +#include + +#include "proj.h" +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + struct PJconsts *link; + double lamp; + double cphip, sphip; +}; +} // anonymous namespace + +PROJ_HEAD(ob_tran, "General Oblique Transformation") "\n\tMisc Sph" +"\n\to_proj= plus parameters for projection" +"\n\to_lat_p= o_lon_p= (new pole) or" +"\n\to_alpha= o_lon_c= o_lat_c= or" +"\n\to_lon_1= o_lat_1= o_lon_2= o_lat_2="; + +#define TOL 1e-10 + + +static XY o_forward(LP lp, PJ *P) { /* spheroid */ + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, sinphi, cosphi; + + coslam = cos(lp.lam); + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam + + Q->cphip * sinphi) + Q->lamp); + lp.phi = aasin(P->ctx,Q->sphip * sinphi - Q->cphip * cosphi * coslam); + + return Q->link->fwd(lp, Q->link); +} + + +static XY t_forward(LP lp, PJ *P) { /* spheroid */ + struct pj_opaque *Q = static_cast(P->opaque); + double cosphi, coslam; + + cosphi = cos(lp.phi); + coslam = cos(lp.lam); + lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), sin(lp.phi)) + Q->lamp); + lp.phi = aasin(P->ctx, - cosphi * coslam); + + return Q->link->fwd(lp, Q->link); +} + + +static LP o_inverse(XY xy, PJ *P) { /* spheroid */ + + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, sinphi, cosphi; + + LP lp = Q->link->inv(xy, Q->link); + if (lp.lam != HUGE_VAL) { + coslam = cos(lp.lam -= Q->lamp); + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + lp.phi = aasin(P->ctx,Q->sphip * sinphi + Q->cphip * cosphi * coslam); + lp.lam = aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam - + Q->cphip * sinphi); + } + return lp; +} + + +static LP t_inverse(XY xy, PJ *P) { /* spheroid */ + + struct pj_opaque *Q = static_cast(P->opaque); + double cosphi, t; + + LP lp = Q->link->inv(xy, Q->link); + if (lp.lam != HUGE_VAL) { + cosphi = cos(lp.phi); + t = lp.lam - Q->lamp; + lp.lam = aatan2(cosphi * sin(t), - sin(lp.phi)); + lp.phi = aasin(P->ctx,cosphi * cos(t)); + } + return lp; +} + + +static PJ *destructor(PJ *P, int errlev) { + if (nullptr==P) + return nullptr; + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + if (static_cast(P->opaque)->link) + static_cast(P->opaque)->link->destructor (static_cast(P->opaque)->link, errlev); + + return pj_default_destructor(P, errlev); +} + + + + +/*********************************************************************** + +These functions are modified versions of the functions "argc_params" +and "argv_params" from PJ_pipeline.c + +Basically, they do the somewhat backwards stunt of turning the paralist +representation of the +args back into the original +argv, +argc +representation accepted by pj_init_ctx(). + +This, however, also begs the question of whether we really need the +paralist linked list representation, or if we could do with a simpler +null-terminated argv style array? This would simplfy some code, and +keep memory allocations more localized. + +***********************************************************************/ + +typedef struct {int argc; char **argv;} ARGS; + +/* count the number of args in the linked list */ +static size_t paralist_params_argc (paralist *params) { + size_t argc = 0; + for (; params != nullptr; params = params->next) + argc++; + return argc; +} + + +/* turn paralist into argc/argv style argument list */ +static ARGS ob_tran_target_params (paralist *params) { + int i = 0; + ARGS args = {0, nullptr}; + size_t argc = paralist_params_argc (params); + if (argc < 2) + return args; + + /* all args except the proj_ob_tran */ + args.argv = static_cast(pj_calloc (argc - 1, sizeof (char *))); + if (nullptr==args.argv) + return args; + + /* Copy all args *except* the proj=ob_tran arg to the argv array */ + for (i = 0; params != nullptr; params = params->next) { + if (0==strcmp (params->param, "proj=ob_tran")) + continue; + args.argv[i++] = params->param; + } + args.argc = i; + + /* Then convert the o_proj=xxx element to proj=xxx */ + for (i = 0; i < args.argc; i++) { + if (0!=strncmp (args.argv[i], "o_proj=", 7)) + continue; + args.argv[i] += 2; + break; + } + + return args; +} + + + +PJ *PROJECTION(ob_tran) { + double phip; + char *name; + ARGS args; + PJ *R; /* projection to rotate */ + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return destructor(P, ENOMEM); + + P->opaque = Q; + P->destructor = destructor; + + /* get name of projection to be translated */ + if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) + return destructor(P, PJD_ERR_NO_ROTATION_PROJ); + + /* avoid endless recursion */ + if( strcmp(name, "ob_tran") == 0 ) + return destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); + + /* Create the target projection object to rotate */ + args = ob_tran_target_params (P->params); + R = pj_init_ctx (pj_get_ctx(P), args.argc, args.argv); + pj_dealloc (args.argv); + + if (nullptr==R) + return destructor (P, PJD_ERR_UNKNOWN_PROJECTION_ID); + Q->link = R; + + if (pj_param(P->ctx, P->params, "to_alpha").i) { + double lamc, phic, alpha; + + lamc = pj_param(P->ctx, P->params, "ro_lon_c").f; + phic = pj_param(P->ctx, P->params, "ro_lat_c").f; + alpha = pj_param(P->ctx, P->params, "ro_alpha").f; + + if (fabs(fabs(phic) - M_HALFPI) <= TOL) + return destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); + + Q->lamp = lamc + aatan2(-cos(alpha), -sin(alpha) * sin(phic)); + phip = aasin(P->ctx,cos(phic) * sin(alpha)); + } else if (pj_param(P->ctx, P->params, "to_lat_p").i) { /* specified new pole */ + Q->lamp = pj_param(P->ctx, P->params, "ro_lon_p").f; + phip = pj_param(P->ctx, P->params, "ro_lat_p").f; + } else { /* specified new "equator" points */ + double lam1, lam2, phi1, phi2, con; + + lam1 = pj_param(P->ctx, P->params, "ro_lon_1").f; + phi1 = pj_param(P->ctx, P->params, "ro_lat_1").f; + lam2 = pj_param(P->ctx, P->params, "ro_lon_2").f; + phi2 = pj_param(P->ctx, P->params, "ro_lat_2").f; + if (fabs(phi1 - phi2) <= TOL || (con = fabs(phi1)) <= TOL || + fabs(con - M_HALFPI) <= TOL || fabs(fabs(phi2) - M_HALFPI) <= TOL) + return destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); + + Q->lamp = atan2(cos(phi1) * sin(phi2) * cos(lam1) - + sin(phi1) * cos(phi2) * cos(lam2), + sin(phi1) * cos(phi2) * sin(lam2) - + cos(phi1) * sin(phi2) * sin(lam1)); + phip = atan(-cos(Q->lamp - lam1) / tan(phi1)); + } + + if (fabs(phip) > TOL) { /* oblique */ + Q->cphip = cos(phip); + Q->sphip = sin(phip); + P->fwd = Q->link->fwd ? o_forward : nullptr; + P->inv = Q->link->inv ? o_inverse : nullptr; + } else { /* transverse */ + P->fwd = Q->link->fwd ? t_forward : nullptr; + P->inv = Q->link->inv ? t_inverse : nullptr; + } + + /* Support some rather speculative test cases, where the rotated projection */ + /* is actually latlong. We do not want scaling in that case... */ + if (Q->link->right==PJ_IO_UNITS_ANGULAR) + P->right = PJ_IO_UNITS_PROJECTED; + + + return P; +} diff --git a/src/projections/ocea.cpp b/src/projections/ocea.cpp new file mode 100644 index 00000000..0576ace7 --- /dev/null +++ b/src/projections/ocea.cpp @@ -0,0 +1,102 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(ocea, "Oblique Cylindrical Equal Area") "\n\tCyl, Sph" + "lonc= alpha= or\n\tlat_1= lat_2= lon_1= lon_2="; + +namespace { // anonymous namespace +struct pj_opaque { + double rok; + double rtk; + double sinphi; + double cosphi; + double singam; + double cosgam; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double t; + xy.y = sin(lp.lam); + t = cos(lp.lam); + xy.x = atan((tan(lp.phi) * Q->cosphi + Q->sinphi * xy.y) / t); + if (t < 0.) + xy.x += M_PI; + xy.x *= Q->rtk; + xy.y = Q->rok * (Q->sinphi * sin(lp.phi) - Q->cosphi * cos(lp.phi) * xy.y); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double t, s; + + xy.y /= Q->rok; + xy.x /= Q->rtk; + t = sqrt(1. - xy.y * xy.y); + lp.phi = asin(xy.y * Q->sinphi + t * Q->cosphi * (s = sin(xy.x))); + lp.lam = atan2(t * Q->sinphi * s - xy.y * Q->cosphi, + t * cos(xy.x)); + return lp; +} + + +PJ *PROJECTION(ocea) { + double phi_0=0.0, phi_1, phi_2, lam_1, lam_2, lonz, alpha; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->rok = 1. / P->k0; + Q->rtk = P->k0; + /*If the keyword "alpha" is found in the sentence then use 1point+1azimuth*/ + if ( pj_param(P->ctx, P->params, "talpha").i) { + /*Define Pole of oblique transformation from 1 point & 1 azimuth*/ + alpha = pj_param(P->ctx, P->params, "ralpha").f; + lonz = pj_param(P->ctx, P->params, "rlonc").f; + /*Equation 9-8 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ + Q->singam = atan(-cos(alpha)/(-sin(phi_0) * sin(alpha))) + lonz; + /*Equation 9-7 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ + Q->sinphi = asin(cos(phi_0) * sin(alpha)); + /*If the keyword "alpha" is NOT found in the sentence then use 2points*/ + } else { + /*Define Pole of oblique transformation from 2 points*/ + phi_1 = pj_param(P->ctx, P->params, "rlat_1").f; + phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; + lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; + lam_2 = pj_param(P->ctx, P->params, "rlon_2").f; + /*Equation 9-1 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ + Q->singam = atan2(cos(phi_1) * sin(phi_2) * cos(lam_1) - + sin(phi_1) * cos(phi_2) * cos(lam_2), + sin(phi_1) * cos(phi_2) * sin(lam_2) - + cos(phi_1) * sin(phi_2) * sin(lam_1) ); + + /* take care of P->lam0 wrap-around when +lam_1=-90*/ + if (lam_1 == -M_HALFPI) + Q->singam = -Q->singam; + + /*Equation 9-2 page 80 (http://pubs.usgs.gov/pp/1395/report.pdf)*/ + Q->sinphi = atan(-cos(Q->singam - lam_1) / tan(phi_1)); + } + P->lam0 = Q->singam + M_HALFPI; + Q->cosphi = cos(Q->sinphi); + Q->sinphi = sin(Q->sinphi); + Q->cosgam = cos(Q->singam); + Q->singam = sin(Q->singam); + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + + return P; +} diff --git a/src/projections/oea.cpp b/src/projections/oea.cpp new file mode 100644 index 00000000..0c401b2f --- /dev/null +++ b/src/projections/oea.cpp @@ -0,0 +1,87 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +PROJ_HEAD(oea, "Oblated Equal Area") "\n\tMisc Sph\n\tn= m= theta="; + +namespace { // anonymous namespace +struct pj_opaque { + double theta; + double m, n; + double two_r_m, two_r_n, rm, rn, hm, hn; + double cp0, sp0; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double Az, M, N, cp, sp, cl, shz; + + cp = cos(lp.phi); + sp = sin(lp.phi); + cl = cos(lp.lam); + Az = aatan2(cp * sin(lp.lam), Q->cp0 * sp - Q->sp0 * cp * cl) + Q->theta; + shz = sin(0.5 * aacos(P->ctx, Q->sp0 * sp + Q->cp0 * cp * cl)); + M = aasin(P->ctx, shz * sin(Az)); + N = aasin(P->ctx, shz * cos(Az) * cos(M) / cos(M * Q->two_r_m)); + xy.y = Q->n * sin(N * Q->two_r_n); + xy.x = Q->m * sin(M * Q->two_r_m) * cos(N) / cos(N * Q->two_r_n); + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double N, M, xp, yp, z, Az, cz, sz, cAz; + + N = Q->hn * aasin(P->ctx,xy.y * Q->rn); + M = Q->hm * aasin(P->ctx,xy.x * Q->rm * cos(N * Q->two_r_n) / cos(N)); + xp = 2. * sin(M); + yp = 2. * sin(N) * cos(M * Q->two_r_m) / cos(M); + cAz = cos(Az = aatan2(xp, yp) - Q->theta); + z = 2. * aasin(P->ctx, 0.5 * hypot(xp, yp)); + sz = sin(z); + cz = cos(z); + lp.phi = aasin(P->ctx, Q->sp0 * cz + Q->cp0 * sz * cAz); + lp.lam = aatan2(sz * sin(Az), + Q->cp0 * cz - Q->sp0 * sz * cAz); + + return lp; +} + + + + +PJ *PROJECTION(oea) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + if (((Q->n = pj_param(P->ctx, P->params, "dn").f) <= 0.) || + ((Q->m = pj_param(P->ctx, P->params, "dm").f) <= 0.)) { + return pj_default_destructor(P, PJD_ERR_INVALID_M_OR_N); + } else { + Q->theta = pj_param(P->ctx, P->params, "rtheta").f; + Q->sp0 = sin(P->phi0); + Q->cp0 = cos(P->phi0); + Q->rn = 1./ Q->n; + Q->rm = 1./ Q->m; + Q->two_r_n = 2. * Q->rn; + Q->two_r_m = 2. * Q->rm; + Q->hm = 0.5 * Q->m; + Q->hn = 0.5 * Q->n; + P->fwd = s_forward; + P->inv = s_inverse; + P->es = 0.; + } + + return P; +} + diff --git a/src/projections/omerc.cpp b/src/projections/omerc.cpp new file mode 100644 index 00000000..ead07128 --- /dev/null +++ b/src/projections/omerc.cpp @@ -0,0 +1,229 @@ +/* +** Copyright (c) 2003, 2006 Gerald I. Evenden +*/ +/* +** 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. +*/ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(omerc, "Oblique Mercator") + "\n\tCyl, Sph&Ell no_rot\n\t" + "alpha= [gamma=] [no_off] lonc= or\n\t lon_1= lat_1= lon_2= lat_2="; + +namespace { // anonymous namespace +struct pj_opaque { + double A, B, E, AB, ArB, BrA, rB, singam, cosgam, sinrot, cosrot; + double v_pole_n, v_pole_s, u_0; + int no_rot; +}; +} // anonymous namespace + +#define TOL 1.e-7 +#define EPS 1.e-10 + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double S, T, U, V, W, temp, u, v; + + if (fabs(fabs(lp.phi) - M_HALFPI) > EPS) { + W = Q->E / pow(pj_tsfn(lp.phi, sin(lp.phi), P->e), Q->B); + temp = 1. / W; + S = .5 * (W - temp); + T = .5 * (W + temp); + V = sin(Q->B * lp.lam); + U = (S * Q->singam - V * Q->cosgam) / T; + if (fabs(fabs(U) - 1.0) < EPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + v = 0.5 * Q->ArB * log((1. - U)/(1. + U)); + temp = cos(Q->B * lp.lam); + if(fabs(temp) < TOL) { + u = Q->A * lp.lam; + } else { + u = Q->ArB * atan2((S * Q->cosgam + V * Q->singam), temp); + } + } else { + v = lp.phi > 0 ? Q->v_pole_n : Q->v_pole_s; + u = Q->ArB * lp.phi; + } + if (Q->no_rot) { + xy.x = u; + xy.y = v; + } else { + u -= Q->u_0; + xy.x = v * Q->cosrot + u * Q->sinrot; + xy.y = u * Q->cosrot - v * Q->sinrot; + } + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double u, v, Qp, Sp, Tp, Vp, Up; + + if (Q->no_rot) { + v = xy.y; + u = xy.x; + } else { + v = xy.x * Q->cosrot - xy.y * Q->sinrot; + u = xy.y * Q->cosrot + xy.x * Q->sinrot + Q->u_0; + } + Qp = exp(- Q->BrA * v); + Sp = .5 * (Qp - 1. / Qp); + Tp = .5 * (Qp + 1. / Qp); + Vp = sin(Q->BrA * u); + Up = (Vp * Q->cosgam + Sp * Q->singam) / Tp; + if (fabs(fabs(Up) - 1.) < EPS) { + lp.lam = 0.; + lp.phi = Up < 0. ? -M_HALFPI : M_HALFPI; + } else { + lp.phi = Q->E / sqrt((1. + Up) / (1. - Up)); + if ((lp.phi = pj_phi2(P->ctx, pow(lp.phi, 1. / Q->B), P->e)) == HUGE_VAL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + lp.lam = - Q->rB * atan2((Sp * Q->cosgam - + Vp * Q->singam), cos(Q->BrA * u)); + } + return lp; +} + + +PJ *PROJECTION(omerc) { + double con, com, cosph0, D, F, H, L, sinph0, p, J, gamma=0, + gamma0, lamc=0, lam1=0, lam2=0, phi1=0, phi2=0, alpha_c=0; + int alp, gam, no_off = 0; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->no_rot = pj_param(P->ctx, P->params, "bno_rot").i; + if ((alp = pj_param(P->ctx, P->params, "talpha").i) != 0) + alpha_c = pj_param(P->ctx, P->params, "ralpha").f; + if ((gam = pj_param(P->ctx, P->params, "tgamma").i) != 0) + gamma = pj_param(P->ctx, P->params, "rgamma").f; + if (alp || gam) { + lamc = pj_param(P->ctx, P->params, "rlonc").f; + no_off = + /* For libproj4 compatibility */ + pj_param(P->ctx, P->params, "tno_off").i + /* for backward compatibility */ + || pj_param(P->ctx, P->params, "tno_uoff").i; + if( no_off ) + { + /* Mark the parameter as used, so that the pj_get_def() return them */ + pj_param(P->ctx, P->params, "sno_uoff"); + pj_param(P->ctx, P->params, "sno_off"); + } + } else { + lam1 = pj_param(P->ctx, P->params, "rlon_1").f; + phi1 = pj_param(P->ctx, P->params, "rlat_1").f; + lam2 = pj_param(P->ctx, P->params, "rlon_2").f; + phi2 = pj_param(P->ctx, P->params, "rlat_2").f; + if (fabs(phi1 - phi2) <= TOL || + (con = fabs(phi1)) <= TOL || + fabs(con - M_HALFPI) <= TOL || + fabs(fabs(P->phi0) - M_HALFPI) <= TOL || + fabs(fabs(phi2) - M_HALFPI) <= TOL) + return pj_default_destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); + } + com = sqrt(P->one_es); + if (fabs(P->phi0) > EPS) { + sinph0 = sin(P->phi0); + cosph0 = cos(P->phi0); + con = 1. - P->es * sinph0 * sinph0; + Q->B = cosph0 * cosph0; + Q->B = sqrt(1. + P->es * Q->B * Q->B / P->one_es); + Q->A = Q->B * P->k0 * com / con; + D = Q->B * com / (cosph0 * sqrt(con)); + if ((F = D * D - 1.) <= 0.) + F = 0.; + else { + F = sqrt(F); + if (P->phi0 < 0.) + F = -F; + } + Q->E = F += D; + Q->E *= pow(pj_tsfn(P->phi0, sinph0, P->e), Q->B); + } else { + Q->B = 1. / com; + Q->A = P->k0; + Q->E = D = F = 1.; + } + if (alp || gam) { + if (alp) { + gamma0 = aasin(P->ctx, sin(alpha_c) / D); + if (!gam) + gamma = alpha_c; + } else + alpha_c = aasin(P->ctx, D*sin(gamma0 = gamma)); + P->lam0 = lamc - aasin(P->ctx, .5 * (F - 1. / F) * + tan(gamma0)) / Q->B; + } else { + H = pow(pj_tsfn(phi1, sin(phi1), P->e), Q->B); + L = pow(pj_tsfn(phi2, sin(phi2), P->e), Q->B); + F = Q->E / H; + p = (L - H) / (L + H); + J = Q->E * Q->E; + J = (J - L * H) / (J + L * H); + if ((con = lam1 - lam2) < -M_PI) + lam2 -= M_TWOPI; + else if (con > M_PI) + lam2 += M_TWOPI; + P->lam0 = adjlon(.5 * (lam1 + lam2) - atan( + J * tan(.5 * Q->B * (lam1 - lam2)) / p) / Q->B); + gamma0 = atan(2. * sin(Q->B * adjlon(lam1 - P->lam0)) / + (F - 1. / F)); + gamma = alpha_c = aasin(P->ctx, D * sin(gamma0)); + } + Q->singam = sin(gamma0); + Q->cosgam = cos(gamma0); + Q->sinrot = sin(gamma); + Q->cosrot = cos(gamma); + Q->BrA = 1. / (Q->ArB = Q->A * (Q->rB = 1. / Q->B)); + Q->AB = Q->A * Q->B; + if (no_off) + Q->u_0 = 0; + else { + Q->u_0 = fabs(Q->ArB * atan(sqrt(D * D - 1.) / cos(alpha_c))); + if (P->phi0 < 0.) + Q->u_0 = - Q->u_0; + } + F = 0.5 * gamma0; + Q->v_pole_n = Q->ArB * log(tan(M_FORTPI - F)); + Q->v_pole_s = Q->ArB * log(tan(M_FORTPI + F)); + P->inv = e_inverse; + P->fwd = e_forward; + + return P; +} diff --git a/src/projections/ortho.cpp b/src/projections/ortho.cpp new file mode 100644 index 00000000..6ea55248 --- /dev/null +++ b/src/projections/ortho.cpp @@ -0,0 +1,143 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "proj_internal.h" +#include "proj_math.h" +#include "projects.h" + +PROJ_HEAD(ortho, "Orthographic") "\n\tAzi, Sph"; + +namespace { // anonymous namespace +enum Mode { + N_POLE = 0, + S_POLE = 1, + EQUIT = 2, + OBLIQ = 3 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double sinph0; + double cosph0; + enum Mode mode; +}; +} // anonymous namespace + +#define EPS10 1.e-10 + +static XY forward_error(PJ *P, LP lp, XY xy) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + proj_log_trace(P, "Coordinate (%.3f, %.3f) is on the unprojected hemisphere", + proj_todeg(lp.lam), proj_todeg(lp.phi)); + return xy; +} + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy; + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, cosphi, sinphi; + + xy.x = HUGE_VAL; xy.y = HUGE_VAL; + + cosphi = cos(lp.phi); + coslam = cos(lp.lam); + switch (Q->mode) { + case EQUIT: + if (cosphi * coslam < - EPS10) + return forward_error(P, lp, xy); + xy.y = sin(lp.phi); + break; + case OBLIQ: + if (Q->sinph0 * (sinphi = sin(lp.phi)) + Q->cosph0 * cosphi * coslam < - EPS10) + return forward_error(P, lp, xy); + xy.y = Q->cosph0 * sinphi - Q->sinph0 * cosphi * coslam; + break; + case N_POLE: + coslam = - coslam; + /*-fallthrough*/ + case S_POLE: + if (fabs(lp.phi - P->phi0) - EPS10 > M_HALFPI) + return forward_error(P, lp, xy); + xy.y = cosphi * coslam; + break; + } + xy.x = cosphi * sin(lp.lam); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp; + struct pj_opaque *Q = static_cast(P->opaque); + double rh, cosc, sinc; + + lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; + + if ((sinc = (rh = hypot(xy.x, xy.y))) > 1.) { + if ((sinc - 1.) > EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + proj_log_trace(P, "Point (%.3f, %.3f) is outside the projection boundary"); + return lp; + } + sinc = 1.; + } + cosc = sqrt(1. - sinc * sinc); /* in this range OK */ + if (fabs(rh) <= EPS10) { + lp.phi = P->phi0; + lp.lam = 0.0; + } else { + switch (Q->mode) { + case N_POLE: + xy.y = -xy.y; + lp.phi = acos(sinc); + break; + case S_POLE: + lp.phi = - acos(sinc); + break; + case EQUIT: + lp.phi = xy.y * sinc / rh; + xy.x *= sinc; + xy.y = cosc * rh; + goto sinchk; + case OBLIQ: + lp.phi = cosc * Q->sinph0 + xy.y * sinc * Q->cosph0 /rh; + xy.y = (cosc - Q->sinph0 * lp.phi) * rh; + xy.x *= sinc * Q->cosph0; + sinchk: + if (fabs(lp.phi) >= 1.) + lp.phi = lp.phi < 0. ? -M_HALFPI : M_HALFPI; + else + lp.phi = asin(lp.phi); + break; + } + lp.lam = (xy.y == 0. && (Q->mode == OBLIQ || Q->mode == EQUIT)) + ? (xy.x == 0. ? 0. : xy.x < 0. ? -M_HALFPI : M_HALFPI) + : atan2(xy.x, xy.y); + } + return lp; +} + + + +PJ *PROJECTION(ortho) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + if (fabs(fabs(P->phi0) - M_HALFPI) <= EPS10) + Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + else if (fabs(P->phi0) > EPS10) { + Q->mode = OBLIQ; + Q->sinph0 = sin(P->phi0); + Q->cosph0 = cos(P->phi0); + } else + Q->mode = EQUIT; + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + + return P; +} + diff --git a/src/projections/patterson.cpp b/src/projections/patterson.cpp new file mode 100644 index 00000000..0d19414e --- /dev/null +++ b/src/projections/patterson.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2014 Bojan Savric + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * The Patterson Cylindrical projection was designed by Tom Patterson, US National + * Park Service, in 2014, using Flex Projector. The polynomial equations for the + * projection were developed by Bojan Savric, Oregon State University, in + * collaboration with Tom Patterson and Bernhard Jenny, Oregon State University. + * + * Java reference algorithm implemented by Bojan Savric in Java Map Projection + * Library (a Java port of PROJ.4) in the file PattersonProjection.java. + * + * References: + * Java Map Projection Library + * https://github.com/OSUCartography/JMapProjLib + * + * Patterson Cylindrical Projection + * http://shadedrelief.com/patterson/ + * + * Patterson, T., Savric, B., and Jenny, B. (2015). Cartographic Perspectives + * (No.78). Describes the projection design and characteristics, and + * developing the equations. doi:10.14714/CP78.1270 + * https://doi.org/10.14714/CP78.1270 + * + * Port to PROJ.4 by Micah Cochran, 26 March 2016 + */ + +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(patterson, "Patterson Cylindrical") "\n\tCyl"; + +#define K1 1.0148 +#define K2 0.23185 +#define K3 -0.14499 +#define K4 0.02406 +#define C1 K1 +#define C2 (5.0 * K2) +#define C3 (7.0 * K3) +#define C4 (9.0 * K4) +#define EPS11 1.0e-11 +#define MAX_Y 1.790857183 +/* Not sure at all of the appropriate number for MAX_ITER... */ +#define MAX_ITER 100 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double phi2; + (void) P; + + phi2 = lp.phi * lp.phi; + xy.x = lp.lam; + xy.y = lp.phi * (K1 + phi2 * phi2 * (K2 + phi2 * (K3 + K4 * phi2))); + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double yc, tol, y2, f, fder; + int i; + (void) P; + + yc = xy.y; + + /* make sure y is inside valid range */ + if (xy.y > MAX_Y) { + xy.y = MAX_Y; + } else if (xy.y < -MAX_Y) { + xy.y = -MAX_Y; + } + + for (i = MAX_ITER; i ; --i) { /* Newton-Raphson */ + y2 = yc * yc; + f = (yc * (K1 + y2 * y2 * (K2 + y2 * (K3 + K4 * y2)))) - xy.y; + fder = C1 + y2 * y2 * (C2 + y2 * (C3 + C4 * y2)); + yc -= tol = f / fder; + if (fabs(tol) < EPS11) { + break; + } + } + if( i == 0 ) + pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + lp.phi = yc; + + /* longitude */ + lp.lam = xy.x; + + return lp; +} + + +PJ *PROJECTION(patterson) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/poly.cpp b/src/projections/poly.cpp new file mode 100644 index 00000000..a970fdb1 --- /dev/null +++ b/src/projections/poly.cpp @@ -0,0 +1,171 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(poly, "Polyconic (American)") + "\n\tConic, Sph&Ell"; + +namespace { // anonymous namespace +struct pj_opaque { + double ml0; \ + double *en; +}; +} // anonymous namespace + +#define TOL 1e-10 +#define CONV 1e-10 +#define N_ITER 10 +#define I_ITER 20 +#define ITOL 1.e-12 + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double ms, sp, cp; + + if (fabs(lp.phi) <= TOL) { + xy.x = lp.lam; + xy.y = -Q->ml0; + } else { + sp = sin(lp.phi); + ms = fabs(cp = cos(lp.phi)) > TOL ? pj_msfn(sp, cp, P->es) / sp : 0.; + xy.x = ms * sin(lp.lam *= sp); + xy.y = (pj_mlfn(lp.phi, sp, cp, Q->en) - Q->ml0) + ms * (1. - cos(lp.lam)); + } + + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cot, E; + + if (fabs(lp.phi) <= TOL) { + xy.x = lp.lam; + xy.y = Q->ml0; + } else { + cot = 1. / tan(lp.phi); + xy.x = sin(E = lp.lam * sin(lp.phi)) * cot; + xy.y = lp.phi - P->phi0 + cot * (1. - cos(E)); + } + + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + xy.y += Q->ml0; + if (fabs(xy.y) <= TOL) { + lp.lam = xy.x; + lp.phi = 0.; + } else { + double r, c, sp, cp, s2ph, ml, mlb, mlp, dPhi; + int i; + + r = xy.y * xy.y + xy.x * xy.x; + lp.phi = xy.y; + for (i = I_ITER; i ; --i) { + sp = sin(lp.phi); + s2ph = sp * ( cp = cos(lp.phi)); + if (fabs(cp) < ITOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + c = sp * (mlp = sqrt(1. - P->es * sp * sp)) / cp; + ml = pj_mlfn(lp.phi, sp, cp, Q->en); + mlb = ml * ml + r; + mlp = P->one_es / (mlp * mlp * mlp); + lp.phi += ( dPhi = + ( ml + ml + c * mlb - 2. * xy.y * (c * ml + 1.) ) / ( + P->es * s2ph * (mlb - 2. * xy.y * ml) / c + + 2.* (xy.y - ml) * (c * mlp - 1. / s2ph) - mlp - mlp )); + if (fabs(dPhi) <= ITOL) + break; + } + if (!i) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + c = sin(lp.phi); + lp.lam = asin(xy.x * tan(lp.phi) * sqrt(1. - P->es * c * c)) / sin(lp.phi); + } + + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double B, dphi, tp; + int i; + + if (fabs(xy.y = P->phi0 + xy.y) <= TOL) { + lp.lam = xy.x; + lp.phi = 0.; + } else { + lp.phi = xy.y; + B = xy.x * xy.x + xy.y * xy.y; + i = N_ITER; + do { + tp = tan(lp.phi); + lp.phi -= (dphi = (xy.y * (lp.phi * tp + 1.) - lp.phi - + .5 * ( lp.phi * lp.phi + B) * tp) / + ((lp.phi - xy.y) / tp - 1.)); + } while (fabs(dphi) > CONV && --i); + if (! i) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + lp.lam = asin(xy.x * tan(lp.phi)) / sin(lp.phi); + } + + return lp; +} + + +static PJ *destructor(PJ *P, int errlev) { + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + if (static_cast(P->opaque)->en) + pj_dealloc (static_cast(P->opaque)->en); + + return pj_default_destructor(P, errlev); +} + + +PJ *PROJECTION(poly) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + + P->opaque = Q; + P->destructor = destructor; + + if (P->es != 0.0) { + if (!(Q->en = pj_enfn(P->es))) + return pj_default_destructor (P, ENOMEM); + Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); + P->inv = e_inverse; + P->fwd = e_forward; + } else { + Q->ml0 = -P->phi0; + P->inv = s_inverse; + P->fwd = s_forward; + } + + return P; +} diff --git a/src/projections/proj_etmerc.cpp b/src/projections/proj_etmerc.cpp deleted file mode 100644 index 05f86f37..00000000 --- a/src/projections/proj_etmerc.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/* -** libproj -- library of cartographic projections -** -** Copyright (c) 2008 Gerald I. Evenden -*/ - -/* -** 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. -*/ - -/* The code in this file is largly based upon procedures: - * - * Written by: Knud Poder and Karsten Engsager - * - * Based on math from: R.Koenig and K.H. Weise, "Mathematische - * Grundlagen der hoeheren Geodaesie und Kartographie, - * Springer-Verlag, Berlin/Goettingen" Heidelberg, 1951. - * - * Modified and used here by permission of Reference Networks - * Division, Kort og Matrikelstyrelsen (KMS), Copenhagen, Denmark - * -*/ - -#define PJ_LIB__ - -#include - -#include "proj.h" -#include "projects.h" -#include "proj_math.h" - - -namespace { // anonymous namespace -struct pj_opaque { - double Qn; /* Merid. quad., scaled to the projection */ \ - double Zb; /* Radius vector in polar coord. systems */ \ - double cgb[6]; /* Constants for Gauss -> Geo lat */ \ - double cbg[6]; /* Constants for Geo lat -> Gauss */ \ - double utg[6]; /* Constants for transv. merc. -> geo */ \ - double gtu[6]; /* Constants for geo -> transv. merc. */ -}; -} // anonymous namespace - -PROJ_HEAD(etmerc, "Extended Transverse Mercator") - "\n\tCyl, Sph\n\tlat_ts=(0)\nlat_0=(0)"; -PROJ_HEAD(utm, "Universal Transverse Mercator (UTM)") - "\n\tCyl, Sph\n\tzone= south"; - -#define PROJ_ETMERC_ORDER 6 - -#ifdef _GNU_SOURCE - inline -#endif -static double gatg(double *p1, int len_p1, double B) { - double *p; - double h = 0, h1, h2 = 0, cos_2B; - - cos_2B = 2*cos(2*B); - p = p1 + len_p1; - h1 = *--p; - while (p - p1) { - h = -h2 + cos_2B*h1 + *--p; - h2 = h1; - h1 = h; - } - return (B + h*sin(2*B)); -} - -/* Complex Clenshaw summation */ -#ifdef _GNU_SOURCE - inline -#endif -static double clenS(double *a, int size, double arg_r, double arg_i, double *R, double *I) { - double *p, r, i, hr, hr1, hr2, hi, hi1, hi2; - double sin_arg_r, cos_arg_r, sinh_arg_i, cosh_arg_i; - - /* arguments */ - p = a + size; -#ifdef _GNU_SOURCE - sincos(arg_r, &sin_arg_r, &cos_arg_r); -#else - sin_arg_r = sin(arg_r); - cos_arg_r = cos(arg_r); -#endif - sinh_arg_i = sinh(arg_i); - cosh_arg_i = cosh(arg_i); - r = 2*cos_arg_r*cosh_arg_i; - i = -2*sin_arg_r*sinh_arg_i; - - /* summation loop */ - hi1 = hr1 = hi = 0; - hr = *--p; - for (; a - p;) { - hr2 = hr1; - hi2 = hi1; - hr1 = hr; - hi1 = hi; - hr = -hr2 + r*hr1 - i*hi1 + *--p; - hi = -hi2 + i*hr1 + r*hi1; - } - - r = sin_arg_r*cosh_arg_i; - i = cos_arg_r*sinh_arg_i; - *R = r*hr - i*hi; - *I = r*hi + i*hr; - return *R; -} - - -/* Real Clenshaw summation */ -static double clens(double *a, int size, double arg_r) { - double *p, r, hr, hr1, hr2, cos_arg_r; - - p = a + size; - cos_arg_r = cos(arg_r); - r = 2*cos_arg_r; - - /* summation loop */ - hr1 = 0; - hr = *--p; - for (; a - p;) { - hr2 = hr1; - hr1 = hr; - hr = -hr2 + r*hr1 + *--p; - } - return sin (arg_r)*hr; -} - - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double sin_Cn, cos_Cn, cos_Ce, sin_Ce, dCn, dCe; - double Cn = lp.phi, Ce = lp.lam; - - /* ell. LAT, LNG -> Gaussian LAT, LNG */ - Cn = gatg (Q->cbg, PROJ_ETMERC_ORDER, Cn); - /* Gaussian LAT, LNG -> compl. sph. LAT */ -#ifdef _GNU_SOURCE - sincos (Cn, &sin_Cn, &cos_Cn); - sincos (Ce, &sin_Ce, &cos_Ce); -#else - sin_Cn = sin (Cn); - cos_Cn = cos (Cn); - sin_Ce = sin (Ce); - cos_Ce = cos (Ce); -#endif - - Cn = atan2 (sin_Cn, cos_Ce*cos_Cn); - Ce = atan2 (sin_Ce*cos_Cn, hypot (sin_Cn, cos_Cn*cos_Ce)); - - /* compl. sph. N, E -> ell. norm. N, E */ - Ce = asinh ( tan (Ce) ); /* Replaces: Ce = log(tan(FORTPI + Ce*0.5)); */ - Cn += clenS (Q->gtu, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe); - Ce += dCe; - if (fabs (Ce) <= 2.623395162778) { - xy.y = Q->Qn * Cn + Q->Zb; /* Northing */ - xy.x = Q->Qn * Ce; /* Easting */ - } else - xy.x = xy.y = HUGE_VAL; - return xy; -} - - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double sin_Cn, cos_Cn, cos_Ce, sin_Ce, dCn, dCe; - double Cn = xy.y, Ce = xy.x; - - /* normalize N, E */ - Cn = (Cn - Q->Zb)/Q->Qn; - Ce = Ce/Q->Qn; - - if (fabs(Ce) <= 2.623395162778) { /* 150 degrees */ - /* norm. N, E -> compl. sph. LAT, LNG */ - Cn += clenS(Q->utg, PROJ_ETMERC_ORDER, 2*Cn, 2*Ce, &dCn, &dCe); - Ce += dCe; - Ce = atan (sinh (Ce)); /* Replaces: Ce = 2*(atan(exp(Ce)) - FORTPI); */ - /* compl. sph. LAT -> Gaussian LAT, LNG */ -#ifdef _GNU_SOURCE - sincos (Cn, &sin_Cn, &cos_Cn); - sincos (Ce, &sin_Ce, &cos_Ce); -#else - sin_Cn = sin (Cn); - cos_Cn = cos (Cn); - sin_Ce = sin (Ce); - cos_Ce = cos (Ce); -#endif - Ce = atan2 (sin_Ce, cos_Ce*cos_Cn); - Cn = atan2 (sin_Cn*cos_Ce, hypot (sin_Ce, cos_Ce*cos_Cn)); - /* Gaussian LAT, LNG -> ell. LAT, LNG */ - lp.phi = gatg (Q->cgb, PROJ_ETMERC_ORDER, Cn); - lp.lam = Ce; - } - else - lp.phi = lp.lam = HUGE_VAL; - return lp; -} - - -static PJ *setup(PJ *P) { /* general initialization */ - double f, n, np, Z; - struct pj_opaque *Q = static_cast(P->opaque); - - if (P->es <= 0) { - return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - } - - /* flattening */ - f = P->es / (1 + sqrt (1 - P->es)); /* Replaces: f = 1 - sqrt(1-P->es); */ - - /* third flattening */ - np = n = f/(2 - f); - - /* COEF. OF TRIG SERIES GEO <-> GAUSS */ - /* cgb := Gaussian -> Geodetic, KW p190 - 191 (61) - (62) */ - /* cbg := Geodetic -> Gaussian, KW p186 - 187 (51) - (52) */ - /* PROJ_ETMERC_ORDER = 6th degree : Engsager and Poder: ICC2007 */ - - Q->cgb[0] = n*( 2 + n*(-2/3.0 + n*(-2 + n*(116/45.0 + n*(26/45.0 + - n*(-2854/675.0 )))))); - Q->cbg[0] = n*(-2 + n*( 2/3.0 + n*( 4/3.0 + n*(-82/45.0 + n*(32/45.0 + - n*( 4642/4725.0)))))); - np *= n; - Q->cgb[1] = np*(7/3.0 + n*( -8/5.0 + n*(-227/45.0 + n*(2704/315.0 + - n*( 2323/945.0))))); - Q->cbg[1] = np*(5/3.0 + n*(-16/15.0 + n*( -13/9.0 + n*( 904/315.0 + - n*(-1522/945.0))))); - np *= n; - /* n^5 coeff corrected from 1262/105 -> -1262/105 */ - Q->cgb[2] = np*( 56/15.0 + n*(-136/35.0 + n*(-1262/105.0 + - n*( 73814/2835.0)))); - Q->cbg[2] = np*(-26/15.0 + n*( 34/21.0 + n*( 8/5.0 + - n*(-12686/2835.0)))); - np *= n; - /* n^5 coeff corrected from 322/35 -> 332/35 */ - Q->cgb[3] = np*(4279/630.0 + n*(-332/35.0 + n*(-399572/14175.0))); - Q->cbg[3] = np*(1237/630.0 + n*( -12/5.0 + n*( -24832/14175.0))); - np *= n; - Q->cgb[4] = np*(4174/315.0 + n*(-144838/6237.0 )); - Q->cbg[4] = np*(-734/315.0 + n*( 109598/31185.0)); - np *= n; - Q->cgb[5] = np*(601676/22275.0 ); - Q->cbg[5] = np*(444337/155925.0); - - /* Constants of the projections */ - /* Transverse Mercator (UTM, ITM, etc) */ - np = n*n; - /* Norm. mer. quad, K&W p.50 (96), p.19 (38b), p.5 (2) */ - Q->Qn = P->k0/(1 + n) * (1 + np*(1/4.0 + np*(1/64.0 + np/256.0))); - /* coef of trig series */ - /* utg := ell. N, E -> sph. N, E, KW p194 (65) */ - /* gtu := sph. N, E -> ell. N, E, KW p196 (69) */ - Q->utg[0] = n*(-0.5 + n*( 2/3.0 + n*(-37/96.0 + n*( 1/360.0 + - n*( 81/512.0 + n*(-96199/604800.0)))))); - Q->gtu[0] = n*( 0.5 + n*(-2/3.0 + n*( 5/16.0 + n*(41/180.0 + - n*(-127/288.0 + n*( 7891/37800.0 )))))); - Q->utg[1] = np*(-1/48.0 + n*(-1/15.0 + n*(437/1440.0 + n*(-46/105.0 + - n*( 1118711/3870720.0))))); - Q->gtu[1] = np*(13/48.0 + n*(-3/5.0 + n*(557/1440.0 + n*(281/630.0 + - n*(-1983433/1935360.0))))); - np *= n; - Q->utg[2] = np*(-17/480.0 + n*( 37/840.0 + n*( 209/4480.0 + - n*( -5569/90720.0 )))); - Q->gtu[2] = np*( 61/240.0 + n*(-103/140.0 + n*(15061/26880.0 + - n*(167603/181440.0)))); - np *= n; - Q->utg[3] = np*(-4397/161280.0 + n*( 11/504.0 + n*( 830251/7257600.0))); - Q->gtu[3] = np*(49561/161280.0 + n*(-179/168.0 + n*(6601661/7257600.0))); - np *= n; - Q->utg[4] = np*(-4583/161280.0 + n*( 108847/3991680.0)); - Q->gtu[4] = np*(34729/80640.0 + n*(-3418889/1995840.0)); - np *= n; - Q->utg[5] = np*(-20648693/638668800.0); - Q->gtu[5] = np*(212378941/319334400.0); - - /* Gaussian latitude value of the origin latitude */ - Z = gatg (Q->cbg, PROJ_ETMERC_ORDER, P->phi0); - - /* Origin northing minus true northing at the origin latitude */ - /* i.e. true northing = N - P->Zb */ - Q->Zb = - Q->Qn*(Z + clens(Q->gtu, PROJ_ETMERC_ORDER, 2*Z)); - P->inv = e_inverse; - P->fwd = e_forward; - return P; -} - - - -PJ *PROJECTION(etmerc) { - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - return setup (P); -} - - - -/* utm uses etmerc for the underlying projection */ - - -PJ *PROJECTION(utm) { - long zone; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = Q; - - if (P->es == 0.0) { - proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - return pj_default_destructor(P, ENOMEM); - } - if (P->lam0 < -1000.0 || P->lam0 > 1000.0) { - return pj_default_destructor(P, PJD_ERR_INVALID_UTM_ZONE); - } - - P->y0 = pj_param (P->ctx, P->params, "bsouth").i ? 10000000. : 0.; - P->x0 = 500000.; - if (pj_param (P->ctx, P->params, "tzone").i) /* zone input ? */ - { - zone = pj_param(P->ctx, P->params, "izone").i; - if (zone > 0 && zone <= 60) - --zone; - else { - return pj_default_destructor(P, PJD_ERR_INVALID_UTM_ZONE); - } - } - else /* nearest central meridian input */ - { - zone = lround((floor ((adjlon (P->lam0) + M_PI) * 30. / M_PI))); - if (zone < 0) - zone = 0; - else if (zone >= 60) - zone = 59; - } - P->lam0 = (zone + .5) * M_PI / 30. - M_PI; - P->k0 = 0.9996; - P->phi0 = 0.; - - return setup (P); -} diff --git a/src/projections/proj_rouss.cpp b/src/projections/proj_rouss.cpp deleted file mode 100644 index 3b4428bc..00000000 --- a/src/projections/proj_rouss.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* -** libproj -- library of cartographic projections -** -** Copyright (c) 2003, 2006 Gerald I. Evenden -*/ -/* -** 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. -*/ -#define PJ_LIB__ - -#include -#include - -#include "proj.h" -#include "projects.h" - -namespace { // anonymous namespace -struct pj_opaque { - double s0; - double A1, A2, A3, A4, A5, A6; - double B1, B2, B3, B4, B5, B6, B7, B8; - double C1, C2, C3, C4, C5, C6, C7, C8; - double D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11; - void *en; -}; -} // anonymous namespace -PROJ_HEAD(rouss, "Roussilhe Stereographic") "\n\tAzi, Ell"; - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double s, al, cp, sp, al2, s2; - - cp = cos(lp.phi); - sp = sin(lp.phi); - s = proj_mdist(lp.phi, sp, cp, Q->en) - Q->s0; - s2 = s * s; - al = lp.lam * cp / sqrt(1. - P->es * sp * sp); - al2 = al * al; - xy.x = P->k0 * al*(1.+s2*(Q->A1+s2*Q->A4)-al2*(Q->A2+s*Q->A3+s2*Q->A5 - +al2*Q->A6)); - xy.y = P->k0 * (al2*(Q->B1+al2*Q->B4)+ - s*(1.+al2*(Q->B3-al2*Q->B6)+s2*(Q->B2+s2*Q->B8)+ - s*al2*(Q->B5+s*Q->B7))); - - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - struct pj_opaque *Q = static_cast(P->opaque); - double s, al, x = xy.x / P->k0, y = xy.y / P->k0, x2, y2;; - - x2 = x * x; - y2 = y * y; - al = x*(1.-Q->C1*y2+x2*(Q->C2+Q->C3*y-Q->C4*x2+Q->C5*y2-Q->C7*x2*y) - +y2*(Q->C6*y2-Q->C8*x2*y)); - s = Q->s0 + y*(1.+y2*(-Q->D2+Q->D8*y2))+ - x2*(-Q->D1+y*(-Q->D3+y*(-Q->D5+y*(-Q->D7+y*Q->D11)))+ - x2*(Q->D4+y*(Q->D6+y*Q->D10)-x2*Q->D9)); - lp.phi=proj_inv_mdist(P->ctx, s, Q->en); - s = sin(lp.phi); - lp.lam=al * sqrt(1. - P->es * s * s)/cos(lp.phi); - - return lp; -} - - -static PJ *destructor (PJ *P, int errlev) { - if (nullptr==P) - return nullptr; - - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - - if (static_cast(P->opaque)->en) - pj_dealloc (static_cast(P->opaque)->en); - - return pj_default_destructor (P, ENOMEM); -} - - -PJ *PROJECTION(rouss) { - double N0, es2, t, t2, R_R0_2, R_R0_4; - - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = Q; - - if (!((Q->en = proj_mdist_ini(P->es)))) - return pj_default_destructor (P, ENOMEM); - - es2 = sin(P->phi0); - Q->s0 = proj_mdist(P->phi0, es2, cos(P->phi0), Q->en); - t = 1. - (es2 = P->es * es2 * es2); - N0 = 1./sqrt(t); - R_R0_2 = t * t / P->one_es; - R_R0_4 = R_R0_2 * R_R0_2; - t = tan(P->phi0); - t2 = t * t; - Q->C1 = Q->A1 = R_R0_2 / 4.; - Q->C2 = Q->A2 = R_R0_2 * (2 * t2 - 1. - 2. * es2) / 12.; - Q->A3 = R_R0_2 * t * (1. + 4. * t2)/ ( 12. * N0); - Q->A4 = R_R0_4 / 24.; - Q->A5 = R_R0_4 * ( -1. + t2 * (11. + 12. * t2))/24.; - Q->A6 = R_R0_4 * ( -2. + t2 * (11. - 2. * t2))/240.; - Q->B1 = t / (2. * N0); - Q->B2 = R_R0_2 / 12.; - Q->B3 = R_R0_2 * (1. + 2. * t2 - 2. * es2)/4.; - Q->B4 = R_R0_2 * t * (2. - t2)/(24. * N0); - Q->B5 = R_R0_2 * t * (5. + 4.* t2)/(8. * N0); - Q->B6 = R_R0_4 * (-2. + t2 * (-5. + 6. * t2))/48.; - Q->B7 = R_R0_4 * (5. + t2 * (19. + 12. * t2))/24.; - Q->B8 = R_R0_4 / 120.; - Q->C3 = R_R0_2 * t * (1. + t2)/(3. * N0); - Q->C4 = R_R0_4 * (-3. + t2 * (34. + 22. * t2))/240.; - Q->C5 = R_R0_4 * (4. + t2 * (13. + 12. * t2))/24.; - Q->C6 = R_R0_4 / 16.; - Q->C7 = R_R0_4 * t * (11. + t2 * (33. + t2 * 16.))/(48. * N0); - Q->C8 = R_R0_4 * t * (1. + t2 * 4.)/(36. * N0); - Q->D1 = t / (2. * N0); - Q->D2 = R_R0_2 / 12.; - Q->D3 = R_R0_2 * (2 * t2 + 1. - 2. * es2) / 4.; - Q->D4 = R_R0_2 * t * (1. + t2)/(8. * N0); - Q->D5 = R_R0_2 * t * (1. + t2 * 2.)/(4. * N0); - Q->D6 = R_R0_4 * (1. + t2 * (6. + t2 * 6.))/16.; - Q->D7 = R_R0_4 * t2 * (3. + t2 * 4.)/8.; - Q->D8 = R_R0_4 / 80.; - Q->D9 = R_R0_4 * t * (-21. + t2 * (178. - t2 * 26.))/720.; - Q->D10 = R_R0_4 * t * (29. + t2 * (86. + t2 * 48.))/(96. * N0); - Q->D11 = R_R0_4 * t * (37. + t2 * 44.)/(96. * N0); - - P->fwd = e_forward; - P->inv = e_inverse; - P->destructor = destructor; - - return P; -} diff --git a/src/projections/putp2.cpp b/src/projections/putp2.cpp new file mode 100644 index 00000000..d7a847c8 --- /dev/null +++ b/src/projections/putp2.cpp @@ -0,0 +1,61 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(putp2, "Putnins P2") "\n\tPCyl, Sph"; + +#define C_x 1.89490 +#define C_y 1.71848 +#define C_p 0.6141848493043784 +#define EPS 1e-10 +#define NITER 10 +#define PI_DIV_3 1.0471975511965977 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double p, c, s, V; + int i; + (void) P; + + p = C_p * sin(lp.phi); + s = lp.phi * lp.phi; + lp.phi *= 0.615709 + s * ( 0.00909953 + s * 0.0046292 ); + for (i = NITER; i ; --i) { + c = cos(lp.phi); + s = sin(lp.phi); + lp.phi -= V = (lp.phi + s * (c - 1.) - p) / + (1. + c * (c - 1.) - s * s); + if (fabs(V) < EPS) + break; + } + if (!i) + lp.phi = lp.phi < 0 ? - PI_DIV_3 : PI_DIV_3; + xy.x = C_x * lp.lam * (cos(lp.phi) - 0.5); + xy.y = C_y * sin(lp.phi); + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double c; + + lp.phi = aasin(P->ctx,xy.y / C_y); + lp.lam = xy.x / (C_x * ((c = cos(lp.phi)) - 0.5)); + lp.phi = aasin(P->ctx,(lp.phi + sin(lp.phi) * (c - 1.)) / C_p); + + return lp; +} + + +PJ *PROJECTION(putp2) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/putp3.cpp b/src/projections/putp3.cpp new file mode 100644 index 00000000..98bb2ff0 --- /dev/null +++ b/src/projections/putp3.cpp @@ -0,0 +1,67 @@ +#define PJ_LIB__ +#include +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + double A; +}; +} // anonymous namespace + +PROJ_HEAD(putp3, "Putnins P3") "\n\tPCyl, Sph"; +PROJ_HEAD(putp3p, "Putnins P3'") "\n\tPCyl, Sph"; + +#define C 0.79788456 +#define RPISQ 0.1013211836 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + + xy.x = C * lp.lam * (1. - static_cast(P->opaque)->A * lp.phi * lp.phi); + xy.y = C * lp.phi; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + + lp.phi = xy.y / C; + lp.lam = xy.x / (C * (1. - static_cast(P->opaque)->A * lp.phi * lp.phi)); + + return lp; +} + + +PJ *PROJECTION(putp3) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->A = 4. * RPISQ; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} + +PJ *PROJECTION(putp3p) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->A = 2. * RPISQ; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} + diff --git a/src/projections/putp4p.cpp b/src/projections/putp4p.cpp new file mode 100644 index 00000000..608fc76e --- /dev/null +++ b/src/projections/putp4p.cpp @@ -0,0 +1,76 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + double C_x, C_y; +}; +} // anonymous namespace + +PROJ_HEAD(putp4p, "Putnins P4'") "\n\tPCyl, Sph"; +PROJ_HEAD(weren, "Werenskiold I") "\n\tPCyl, Sph"; + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + lp.phi = aasin(P->ctx,0.883883476 * sin(lp.phi)); + xy.x = Q->C_x * lp.lam * cos(lp.phi); + xy.x /= cos(lp.phi *= 0.333333333333333); + xy.y = Q->C_y * sin(lp.phi); + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + lp.phi = aasin(P->ctx,xy.y / Q->C_y); + lp.lam = xy.x * cos(lp.phi) / Q->C_x; + lp.phi *= 3.; + lp.lam /= cos(lp.phi); + lp.phi = aasin(P->ctx,1.13137085 * sin(lp.phi)); + + return lp; +} + + +PJ *PROJECTION(putp4p) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->C_x = 0.874038744; + Q->C_y = 3.883251825; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} + + +PJ *PROJECTION(weren) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->C_x = 1.; + Q->C_y = 4.442882938; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/putp5.cpp b/src/projections/putp5.cpp new file mode 100644 index 00000000..79e2ad15 --- /dev/null +++ b/src/projections/putp5.cpp @@ -0,0 +1,75 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + double A, B; +}; +} // anonymous namespace + +PROJ_HEAD(putp5, "Putnins P5") "\n\tPCyl, Sph"; +PROJ_HEAD(putp5p, "Putnins P5'") "\n\tPCyl, Sph"; + +#define C 1.01346 +#define D 1.2158542 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + xy.x = C * lp.lam * (Q->A - Q->B * sqrt(1. + D * lp.phi * lp.phi)); + xy.y = C * lp.phi; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + + lp.phi = xy.y / C; + lp.lam = xy.x / (C * (Q->A - Q->B * sqrt(1. + D * lp.phi * lp.phi))); + + return lp; +} + + + +PJ *PROJECTION(putp5) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->A = 2.; + Q->B = 1.; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} + + +PJ *PROJECTION(putp5p) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->A = 1.5; + Q->B = 0.5; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/putp6.cpp b/src/projections/putp6.cpp new file mode 100644 index 00000000..1186b18b --- /dev/null +++ b/src/projections/putp6.cpp @@ -0,0 +1,97 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + double C_x, C_y, A, B, D; +}; +} // anonymous namespace + +PROJ_HEAD(putp6, "Putnins P6") "\n\tPCyl, Sph"; +PROJ_HEAD(putp6p, "Putnins P6'") "\n\tPCyl, Sph"; + +#define EPS 1e-10 +#define NITER 10 +#define CON_POLE 1.732050807568877 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double p, r, V; + int i; + + p = Q->B * sin(lp.phi); + lp.phi *= 1.10265779; + for (i = NITER; i ; --i) { + r = sqrt(1. + lp.phi * lp.phi); + lp.phi -= V = ( (Q->A - r) * lp.phi - log(lp.phi + r) - p ) / + (Q->A - 2. * r); + if (fabs(V) < EPS) + break; + } + if (!i) + lp.phi = p < 0. ? -CON_POLE : CON_POLE; + xy.x = Q->C_x * lp.lam * (Q->D - sqrt(1. + lp.phi * lp.phi)); + xy.y = Q->C_y * lp.phi; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double r; + + lp.phi = xy.y / Q->C_y; + r = sqrt(1. + lp.phi * lp.phi); + lp.lam = xy.x / (Q->C_x * (Q->D - r)); + lp.phi = aasin( P->ctx, ( (Q->A - r) * lp.phi - log(lp.phi + r) ) / Q->B); + + return lp; +} + + +PJ *PROJECTION(putp6) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + Q->C_x = 1.01346; + Q->C_y = 0.91910; + Q->A = 4.; + Q->B = 2.1471437182129378784; + Q->D = 2.; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} + + +PJ *PROJECTION(putp6p) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + Q->C_x = 0.44329; + Q->C_y = 0.80404; + Q->A = 6.; + Q->B = 5.61125; + Q->D = 3.; + + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/qsc.cpp b/src/projections/qsc.cpp new file mode 100644 index 00000000..b50a7c95 --- /dev/null +++ b/src/projections/qsc.cpp @@ -0,0 +1,408 @@ +/* + * This implements the Quadrilateralized Spherical Cube (QSC) projection. + * + * Copyright (c) 2011, 2012 Martin Lambers + * + * The QSC projection was introduced in: + * [OL76] + * E.M. O'Neill and R.E. Laubscher, "Extended Studies of a Quadrilateralized + * Spherical Cube Earth Data Base", Naval Environmental Prediction Research + * Facility Tech. Report NEPRF 3-76 (CSC), May 1976. + * + * The preceding shift from an ellipsoid to a sphere, which allows to apply + * this projection to ellipsoids as used in the Ellipsoidal Cube Map model, + * is described in + * [LK12] + * M. Lambers and A. Kolb, "Ellipsoidal Cube Maps for Accurate Rendering of + * Planetary-Scale Terrain Data", Proc. Pacific Graphics (Short Papers), Sep. + * 2012 + * + * You have to choose one of the following projection centers, + * corresponding to the centers of the six cube faces: + * phi0 = 0.0, lam0 = 0.0 ("front" face) + * phi0 = 0.0, lam0 = 90.0 ("right" face) + * phi0 = 0.0, lam0 = 180.0 ("back" face) + * phi0 = 0.0, lam0 = -90.0 ("left" face) + * phi0 = 90.0 ("top" face) + * phi0 = -90.0 ("bottom" face) + * Other projection centers will not work! + * + * In the projection code below, each cube face is handled differently. + * See the computation of the face parameter in the PROJECTION(qsc) function + * and the handling of different face values (FACE_*) in the forward and + * inverse projections. + * + * Furthermore, the projection is originally only defined for theta angles + * between (-1/4 * PI) and (+1/4 * PI) on the current cube face. This area + * of definition is named AREA_0 in the projection code below. The other + * three areas of a cube face are handled by rotation of AREA_0. + */ + +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +/* The six cube faces. */ +namespace { // anonymous namespace +enum Face { + FACE_FRONT = 0, + FACE_RIGHT = 1, + FACE_BACK = 2, + FACE_LEFT = 3, + FACE_TOP = 4, + FACE_BOTTOM = 5 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + enum Face face; + double a_squared; + double b; + double one_minus_f; + double one_minus_f_squared; +}; +} // anonymous namespace +PROJ_HEAD(qsc, "Quadrilateralized Spherical Cube") "\n\tAzi, Sph"; + +#define EPS10 1.e-10 + +/* The four areas on a cube face. AREA_0 is the area of definition, + * the other three areas are counted counterclockwise. */ +namespace { // anonymous namespace +enum Area { + AREA_0 = 0, + AREA_1 = 1, + AREA_2 = 2, + AREA_3 = 3 +}; +} // anonymous namespace + +/* Helper function for forward projection: compute the theta angle + * and determine the area number. */ +static double qsc_fwd_equat_face_theta(double phi, double y, double x, enum Area *area) { + double theta; + if (phi < EPS10) { + *area = AREA_0; + theta = 0.0; + } else { + theta = atan2(y, x); + if (fabs(theta) <= M_FORTPI) { + *area = AREA_0; + } else if (theta > M_FORTPI && theta <= M_HALFPI + M_FORTPI) { + *area = AREA_1; + theta -= M_HALFPI; + } else if (theta > M_HALFPI + M_FORTPI || theta <= -(M_HALFPI + M_FORTPI)) { + *area = AREA_2; + theta = (theta >= 0.0 ? theta - M_PI : theta + M_PI); + } else { + *area = AREA_3; + theta += M_HALFPI; + } + } + return theta; +} + +/* Helper function: shift the longitude. */ +static double qsc_shift_lon_origin(double lon, double offset) { + double slon = lon + offset; + if (slon < -M_PI) { + slon += M_TWOPI; + } else if (slon > +M_PI) { + slon -= M_TWOPI; + } + return slon; +} + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double lat, lon; + double theta, phi; + double t, mu; /* nu; */ + enum Area area; + + /* Convert the geodetic latitude to a geocentric latitude. + * This corresponds to the shift from the ellipsoid to the sphere + * described in [LK12]. */ + if (P->es != 0.0) { + lat = atan(Q->one_minus_f_squared * tan(lp.phi)); + } else { + lat = lp.phi; + } + + /* Convert the input lat, lon into theta, phi as used by QSC. + * This depends on the cube face and the area on it. + * For the top and bottom face, we can compute theta and phi + * directly from phi, lam. For the other faces, we must use + * unit sphere cartesian coordinates as an intermediate step. */ + lon = lp.lam; + if (Q->face == FACE_TOP) { + phi = M_HALFPI - lat; + if (lon >= M_FORTPI && lon <= M_HALFPI + M_FORTPI) { + area = AREA_0; + theta = lon - M_HALFPI; + } else if (lon > M_HALFPI + M_FORTPI || lon <= -(M_HALFPI + M_FORTPI)) { + area = AREA_1; + theta = (lon > 0.0 ? lon - M_PI : lon + M_PI); + } else if (lon > -(M_HALFPI + M_FORTPI) && lon <= -M_FORTPI) { + area = AREA_2; + theta = lon + M_HALFPI; + } else { + area = AREA_3; + theta = lon; + } + } else if (Q->face == FACE_BOTTOM) { + phi = M_HALFPI + lat; + if (lon >= M_FORTPI && lon <= M_HALFPI + M_FORTPI) { + area = AREA_0; + theta = -lon + M_HALFPI; + } else if (lon < M_FORTPI && lon >= -M_FORTPI) { + area = AREA_1; + theta = -lon; + } else if (lon < -M_FORTPI && lon >= -(M_HALFPI + M_FORTPI)) { + area = AREA_2; + theta = -lon - M_HALFPI; + } else { + area = AREA_3; + theta = (lon > 0.0 ? -lon + M_PI : -lon - M_PI); + } + } else { + double q, r, s; + double sinlat, coslat; + double sinlon, coslon; + + if (Q->face == FACE_RIGHT) { + lon = qsc_shift_lon_origin(lon, +M_HALFPI); + } else if (Q->face == FACE_BACK) { + lon = qsc_shift_lon_origin(lon, +M_PI); + } else if (Q->face == FACE_LEFT) { + lon = qsc_shift_lon_origin(lon, -M_HALFPI); + } + sinlat = sin(lat); + coslat = cos(lat); + sinlon = sin(lon); + coslon = cos(lon); + q = coslat * coslon; + r = coslat * sinlon; + s = sinlat; + + if (Q->face == FACE_FRONT) { + phi = acos(q); + theta = qsc_fwd_equat_face_theta(phi, s, r, &area); + } else if (Q->face == FACE_RIGHT) { + phi = acos(r); + theta = qsc_fwd_equat_face_theta(phi, s, -q, &area); + } else if (Q->face == FACE_BACK) { + phi = acos(-q); + theta = qsc_fwd_equat_face_theta(phi, s, -r, &area); + } else if (Q->face == FACE_LEFT) { + phi = acos(-r); + theta = qsc_fwd_equat_face_theta(phi, s, q, &area); + } else { + /* Impossible */ + phi = theta = 0.0; + area = AREA_0; + } + } + + /* Compute mu and nu for the area of definition. + * For mu, see Eq. (3-21) in [OL76], but note the typos: + * compare with Eq. (3-14). For nu, see Eq. (3-38). */ + mu = atan((12.0 / M_PI) * (theta + acos(sin(theta) * cos(M_FORTPI)) - M_HALFPI)); + t = sqrt((1.0 - cos(phi)) / (cos(mu) * cos(mu)) / (1.0 - cos(atan(1.0 / cos(theta))))); + /* nu = atan(t); We don't really need nu, just t, see below. */ + + /* Apply the result to the real area. */ + if (area == AREA_1) { + mu += M_HALFPI; + } else if (area == AREA_2) { + mu += M_PI; + } else if (area == AREA_3) { + mu += M_PI_HALFPI; + } + + /* Now compute x, y from mu and nu */ + /* t = tan(nu); */ + xy.x = t * cos(mu); + xy.y = t * sin(mu); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double mu, nu, cosmu, tannu; + double tantheta, theta, cosphi, phi; + double t; + int area; + + /* Convert the input x, y to the mu and nu angles as used by QSC. + * This depends on the area of the cube face. */ + nu = atan(sqrt(xy.x * xy.x + xy.y * xy.y)); + mu = atan2(xy.y, xy.x); + if (xy.x >= 0.0 && xy.x >= fabs(xy.y)) { + area = AREA_0; + } else if (xy.y >= 0.0 && xy.y >= fabs(xy.x)) { + area = AREA_1; + mu -= M_HALFPI; + } else if (xy.x < 0.0 && -xy.x >= fabs(xy.y)) { + area = AREA_2; + mu = (mu < 0.0 ? mu + M_PI : mu - M_PI); + } else { + area = AREA_3; + mu += M_HALFPI; + } + + /* Compute phi and theta for the area of definition. + * The inverse projection is not described in the original paper, but some + * good hints can be found here (as of 2011-12-14): + * http://fits.gsfc.nasa.gov/fitsbits/saf.93/saf.9302 + * (search for "Message-Id: <9302181759.AA25477 at fits.cv.nrao.edu>") */ + t = (M_PI / 12.0) * tan(mu); + tantheta = sin(t) / (cos(t) - (1.0 / sqrt(2.0))); + theta = atan(tantheta); + cosmu = cos(mu); + tannu = tan(nu); + cosphi = 1.0 - cosmu * cosmu * tannu * tannu * (1.0 - cos(atan(1.0 / cos(theta)))); + if (cosphi < -1.0) { + cosphi = -1.0; + } else if (cosphi > +1.0) { + cosphi = +1.0; + } + + /* Apply the result to the real area on the cube face. + * For the top and bottom face, we can compute phi and lam directly. + * For the other faces, we must use unit sphere cartesian coordinates + * as an intermediate step. */ + if (Q->face == FACE_TOP) { + phi = acos(cosphi); + lp.phi = M_HALFPI - phi; + if (area == AREA_0) { + lp.lam = theta + M_HALFPI; + } else if (area == AREA_1) { + lp.lam = (theta < 0.0 ? theta + M_PI : theta - M_PI); + } else if (area == AREA_2) { + lp.lam = theta - M_HALFPI; + } else /* area == AREA_3 */ { + lp.lam = theta; + } + } else if (Q->face == FACE_BOTTOM) { + phi = acos(cosphi); + lp.phi = phi - M_HALFPI; + if (area == AREA_0) { + lp.lam = -theta + M_HALFPI; + } else if (area == AREA_1) { + lp.lam = -theta; + } else if (area == AREA_2) { + lp.lam = -theta - M_HALFPI; + } else /* area == AREA_3 */ { + lp.lam = (theta < 0.0 ? -theta - M_PI : -theta + M_PI); + } + } else { + /* Compute phi and lam via cartesian unit sphere coordinates. */ + double q, r, s; + q = cosphi; + t = q * q; + if (t >= 1.0) { + s = 0.0; + } else { + s = sqrt(1.0 - t) * sin(theta); + } + t += s * s; + if (t >= 1.0) { + r = 0.0; + } else { + r = sqrt(1.0 - t); + } + /* Rotate q,r,s into the correct area. */ + if (area == AREA_1) { + t = r; + r = -s; + s = t; + } else if (area == AREA_2) { + r = -r; + s = -s; + } else if (area == AREA_3) { + t = r; + r = s; + s = -t; + } + /* Rotate q,r,s into the correct cube face. */ + if (Q->face == FACE_RIGHT) { + t = q; + q = -r; + r = t; + } else if (Q->face == FACE_BACK) { + q = -q; + r = -r; + } else if (Q->face == FACE_LEFT) { + t = q; + q = r; + r = -t; + } + /* Now compute phi and lam from the unit sphere coordinates. */ + lp.phi = acos(-s) - M_HALFPI; + lp.lam = atan2(r, q); + if (Q->face == FACE_RIGHT) { + lp.lam = qsc_shift_lon_origin(lp.lam, -M_HALFPI); + } else if (Q->face == FACE_BACK) { + lp.lam = qsc_shift_lon_origin(lp.lam, -M_PI); + } else if (Q->face == FACE_LEFT) { + lp.lam = qsc_shift_lon_origin(lp.lam, +M_HALFPI); + } + } + + /* Apply the shift from the sphere to the ellipsoid as described + * in [LK12]. */ + if (P->es != 0.0) { + int invert_sign; + double tanphi, xa; + invert_sign = (lp.phi < 0.0 ? 1 : 0); + tanphi = tan(lp.phi); + xa = Q->b / sqrt(tanphi * tanphi + Q->one_minus_f_squared); + lp.phi = atan(sqrt(P->a * P->a - xa * xa) / (Q->one_minus_f * xa)); + if (invert_sign) { + lp.phi = -lp.phi; + } + } + return lp; +} + + +PJ *PROJECTION(qsc) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + P->inv = e_inverse; + P->fwd = e_forward; + /* Determine the cube face from the center of projection. */ + if (P->phi0 >= M_HALFPI - M_FORTPI / 2.0) { + Q->face = FACE_TOP; + } else if (P->phi0 <= -(M_HALFPI - M_FORTPI / 2.0)) { + Q->face = FACE_BOTTOM; + } else if (fabs(P->lam0) <= M_FORTPI) { + Q->face = FACE_FRONT; + } else if (fabs(P->lam0) <= M_HALFPI + M_FORTPI) { + Q->face = (P->lam0 > 0.0 ? FACE_RIGHT : FACE_LEFT); + } else { + Q->face = FACE_BACK; + } + /* Fill in useful values for the ellipsoid <-> sphere shift + * described in [LK12]. */ + if (P->es != 0.0) { + Q->a_squared = P->a * P->a; + Q->b = P->a * sqrt(1.0 - P->es); + Q->one_minus_f = 1.0 - (P->a - Q->b) / P->a; + Q->one_minus_f_squared = Q->one_minus_f * Q->one_minus_f; + } + + return P; +} diff --git a/src/projections/robin.cpp b/src/projections/robin.cpp new file mode 100644 index 00000000..987977ae --- /dev/null +++ b/src/projections/robin.cpp @@ -0,0 +1,161 @@ +#define PJ_LIB__ +#include "proj_math.h" +#include "proj_internal.h" +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(robin, "Robinson") "\n\tPCyl, Sph"; + +#define V(C,z) (C.c0 + z * (C.c1 + z * (C.c2 + z * C.c3))) +#define DV(C,z) (C.c1 + z * (C.c2 + C.c2 + z * 3. * C.c3)) + +/* +note: following terms based upon 5 deg. intervals in degrees. + +Some background on these coefficients is available at: + +http://article.gmane.org/gmane.comp.gis.proj-4.devel/6039 +http://trac.osgeo.org/proj/ticket/113 +*/ + +namespace { // anonymous namespace +struct COEFS { + float c0, c1, c2, c3; +}; +} // anonymous namespace + +static const struct COEFS X[] = { + {1.0f, 2.2199e-17f, -7.15515e-05f, 3.1103e-06f}, + {0.9986f, -0.000482243f, -2.4897e-05f, -1.3309e-06f}, + {0.9954f, -0.00083103f, -4.48605e-05f, -9.86701e-07f}, + {0.99f, -0.00135364f, -5.9661e-05f, 3.6777e-06f}, + {0.9822f, -0.00167442f, -4.49547e-06f, -5.72411e-06f}, + {0.973f, -0.00214868f, -9.03571e-05f, 1.8736e-08f}, + {0.96f, -0.00305085f, -9.00761e-05f, 1.64917e-06f}, + {0.9427f, -0.00382792f, -6.53386e-05f, -2.6154e-06f}, + {0.9216f, -0.00467746f, -0.00010457f, 4.81243e-06f}, + {0.8962f, -0.00536223f, -3.23831e-05f, -5.43432e-06f}, + {0.8679f, -0.00609363f, -0.000113898f, 3.32484e-06f}, + {0.835f, -0.00698325f, -6.40253e-05f, 9.34959e-07f}, + {0.7986f, -0.00755338f, -5.00009e-05f, 9.35324e-07f}, + {0.7597f, -0.00798324f, -3.5971e-05f, -2.27626e-06f}, + {0.7186f, -0.00851367f, -7.01149e-05f, -8.6303e-06f}, + {0.6732f, -0.00986209f, -0.000199569f, 1.91974e-05f}, + {0.6213f, -0.010418f, 8.83923e-05f, 6.24051e-06f}, + {0.5722f, -0.00906601f, 0.000182f, 6.24051e-06f}, + {0.5322f, -0.00677797f, 0.000275608f, 6.24051e-06f} +}; + +static const struct COEFS Y[] = { + {-5.20417e-18f, 0.0124f, 1.21431e-18f, -8.45284e-11f}, + {0.062f, 0.0124f, -1.26793e-09f, 4.22642e-10f}, + {0.124f, 0.0124f, 5.07171e-09f, -1.60604e-09f}, + {0.186f, 0.0123999f, -1.90189e-08f, 6.00152e-09f}, + {0.248f, 0.0124002f, 7.10039e-08f, -2.24e-08f}, + {0.31f, 0.0123992f, -2.64997e-07f, 8.35986e-08f}, + {0.372f, 0.0124029f, 9.88983e-07f, -3.11994e-07f}, + {0.434f, 0.0123893f, -3.69093e-06f, -4.35621e-07f}, + {0.4958f, 0.0123198f, -1.02252e-05f, -3.45523e-07f}, + {0.5571f, 0.0121916f, -1.54081e-05f, -5.82288e-07f}, + {0.6176f, 0.0119938f, -2.41424e-05f, -5.25327e-07f}, + {0.6769f, 0.011713f, -3.20223e-05f, -5.16405e-07f}, + {0.7346f, 0.0113541f, -3.97684e-05f, -6.09052e-07f}, + {0.7903f, 0.0109107f, -4.89042e-05f, -1.04739e-06f}, + {0.8435f, 0.0103431f, -6.4615e-05f, -1.40374e-09f}, + {0.8936f, 0.00969686f, -6.4636e-05f, -8.547e-06f}, + {0.9394f, 0.00840947f, -0.000192841f, -4.2106e-06f}, + {0.9761f, 0.00616527f, -0.000256f, -4.2106e-06f}, + {1.0f, 0.00328947f, -0.000319159f, -4.2106e-06f} +}; + +#define FXC 0.8487 +#define FYC 1.3523 +#define C1 11.45915590261646417544 +#define RC1 0.08726646259971647884 +#define NODES 18 +#define ONEEPS 1.000001 +#define EPS 1e-8 +/* Not sure at all of the appropriate number for MAX_ITER... */ +#define MAX_ITER 100 + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + long i; + double dphi; + (void) P; + + dphi = fabs(lp.phi); + i = isnan(lp.phi) ? -1 : lround(floor(dphi * C1)); + if( i < 0 ){ + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + if (i >= NODES) i = NODES - 1; + dphi = RAD_TO_DEG * (dphi - RC1 * i); + xy.x = V(X[i], dphi) * FXC * lp.lam; + xy.y = V(Y[i], dphi) * FYC; + if (lp.phi < 0.) xy.y = -xy.y; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + long i; + double t, t1; + struct COEFS T; + int iters; + + lp.lam = xy.x / FXC; + lp.phi = fabs(xy.y / FYC); + if (lp.phi >= 1.) { /* simple pathologic cases */ + if (lp.phi > ONEEPS) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + else { + lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; + lp.lam /= X[NODES].c0; + } + } else { /* general problem */ + /* in Y space, reduce to table interval */ + i = isnan(lp.phi) ? -1 : lround(floor(lp.phi * NODES)); + if( i < 0 || i >= NODES ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + for (;;) { + if (Y[i].c0 > lp.phi) --i; + else if (Y[i+1].c0 <= lp.phi) ++i; + else break; + } + T = Y[i]; + /* first guess, linear interp */ + t = 5. * (lp.phi - T.c0)/(Y[i+1].c0 - T.c0); + /* make into root */ + T.c0 = (float)(T.c0 - lp.phi); + for (iters = MAX_ITER; iters ; --iters) { /* Newton-Raphson */ + t -= t1 = V(T,t) / DV(T,t); + if (fabs(t1) < EPS) + break; + } + if( iters == 0 ) + pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + lp.phi = (5 * i + t) * DEG_TO_RAD; + if (xy.y < 0.) lp.phi = -lp.phi; + lp.lam /= V(X[i], t); + } + return lp; +} + + +PJ *PROJECTION(robin) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} + + diff --git a/src/projections/rouss.cpp b/src/projections/rouss.cpp new file mode 100644 index 00000000..3b4428bc --- /dev/null +++ b/src/projections/rouss.cpp @@ -0,0 +1,158 @@ +/* +** libproj -- library of cartographic projections +** +** Copyright (c) 2003, 2006 Gerald I. Evenden +*/ +/* +** 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. +*/ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + double s0; + double A1, A2, A3, A4, A5, A6; + double B1, B2, B3, B4, B5, B6, B7, B8; + double C1, C2, C3, C4, C5, C6, C7, C8; + double D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11; + void *en; +}; +} // anonymous namespace +PROJ_HEAD(rouss, "Roussilhe Stereographic") "\n\tAzi, Ell"; + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double s, al, cp, sp, al2, s2; + + cp = cos(lp.phi); + sp = sin(lp.phi); + s = proj_mdist(lp.phi, sp, cp, Q->en) - Q->s0; + s2 = s * s; + al = lp.lam * cp / sqrt(1. - P->es * sp * sp); + al2 = al * al; + xy.x = P->k0 * al*(1.+s2*(Q->A1+s2*Q->A4)-al2*(Q->A2+s*Q->A3+s2*Q->A5 + +al2*Q->A6)); + xy.y = P->k0 * (al2*(Q->B1+al2*Q->B4)+ + s*(1.+al2*(Q->B3-al2*Q->B6)+s2*(Q->B2+s2*Q->B8)+ + s*al2*(Q->B5+s*Q->B7))); + + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double s, al, x = xy.x / P->k0, y = xy.y / P->k0, x2, y2;; + + x2 = x * x; + y2 = y * y; + al = x*(1.-Q->C1*y2+x2*(Q->C2+Q->C3*y-Q->C4*x2+Q->C5*y2-Q->C7*x2*y) + +y2*(Q->C6*y2-Q->C8*x2*y)); + s = Q->s0 + y*(1.+y2*(-Q->D2+Q->D8*y2))+ + x2*(-Q->D1+y*(-Q->D3+y*(-Q->D5+y*(-Q->D7+y*Q->D11)))+ + x2*(Q->D4+y*(Q->D6+y*Q->D10)-x2*Q->D9)); + lp.phi=proj_inv_mdist(P->ctx, s, Q->en); + s = sin(lp.phi); + lp.lam=al * sqrt(1. - P->es * s * s)/cos(lp.phi); + + return lp; +} + + +static PJ *destructor (PJ *P, int errlev) { + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + if (static_cast(P->opaque)->en) + pj_dealloc (static_cast(P->opaque)->en); + + return pj_default_destructor (P, ENOMEM); +} + + +PJ *PROJECTION(rouss) { + double N0, es2, t, t2, R_R0_2, R_R0_4; + + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + if (!((Q->en = proj_mdist_ini(P->es)))) + return pj_default_destructor (P, ENOMEM); + + es2 = sin(P->phi0); + Q->s0 = proj_mdist(P->phi0, es2, cos(P->phi0), Q->en); + t = 1. - (es2 = P->es * es2 * es2); + N0 = 1./sqrt(t); + R_R0_2 = t * t / P->one_es; + R_R0_4 = R_R0_2 * R_R0_2; + t = tan(P->phi0); + t2 = t * t; + Q->C1 = Q->A1 = R_R0_2 / 4.; + Q->C2 = Q->A2 = R_R0_2 * (2 * t2 - 1. - 2. * es2) / 12.; + Q->A3 = R_R0_2 * t * (1. + 4. * t2)/ ( 12. * N0); + Q->A4 = R_R0_4 / 24.; + Q->A5 = R_R0_4 * ( -1. + t2 * (11. + 12. * t2))/24.; + Q->A6 = R_R0_4 * ( -2. + t2 * (11. - 2. * t2))/240.; + Q->B1 = t / (2. * N0); + Q->B2 = R_R0_2 / 12.; + Q->B3 = R_R0_2 * (1. + 2. * t2 - 2. * es2)/4.; + Q->B4 = R_R0_2 * t * (2. - t2)/(24. * N0); + Q->B5 = R_R0_2 * t * (5. + 4.* t2)/(8. * N0); + Q->B6 = R_R0_4 * (-2. + t2 * (-5. + 6. * t2))/48.; + Q->B7 = R_R0_4 * (5. + t2 * (19. + 12. * t2))/24.; + Q->B8 = R_R0_4 / 120.; + Q->C3 = R_R0_2 * t * (1. + t2)/(3. * N0); + Q->C4 = R_R0_4 * (-3. + t2 * (34. + 22. * t2))/240.; + Q->C5 = R_R0_4 * (4. + t2 * (13. + 12. * t2))/24.; + Q->C6 = R_R0_4 / 16.; + Q->C7 = R_R0_4 * t * (11. + t2 * (33. + t2 * 16.))/(48. * N0); + Q->C8 = R_R0_4 * t * (1. + t2 * 4.)/(36. * N0); + Q->D1 = t / (2. * N0); + Q->D2 = R_R0_2 / 12.; + Q->D3 = R_R0_2 * (2 * t2 + 1. - 2. * es2) / 4.; + Q->D4 = R_R0_2 * t * (1. + t2)/(8. * N0); + Q->D5 = R_R0_2 * t * (1. + t2 * 2.)/(4. * N0); + Q->D6 = R_R0_4 * (1. + t2 * (6. + t2 * 6.))/16.; + Q->D7 = R_R0_4 * t2 * (3. + t2 * 4.)/8.; + Q->D8 = R_R0_4 / 80.; + Q->D9 = R_R0_4 * t * (-21. + t2 * (178. - t2 * 26.))/720.; + Q->D10 = R_R0_4 * t * (29. + t2 * (86. + t2 * 48.))/(96. * N0); + Q->D11 = R_R0_4 * t * (37. + t2 * 44.)/(96. * N0); + + P->fwd = e_forward; + P->inv = e_inverse; + P->destructor = destructor; + + return P; +} diff --git a/src/projections/rpoly.cpp b/src/projections/rpoly.cpp new file mode 100644 index 00000000..a34f6171 --- /dev/null +++ b/src/projections/rpoly.cpp @@ -0,0 +1,58 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + double phi1; + double fxa; + double fxb; + int mode; +}; +} // anonymous namespace + +PROJ_HEAD(rpoly, "Rectangular Polyconic") + "\n\tConic, Sph, no inv\n\tlat_ts="; + +#define EPS 1e-9 + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double fa; + + if (Q->mode) + fa = tan(lp.lam * Q->fxb) * Q->fxa; + else + fa = 0.5 * lp.lam; + if (fabs(lp.phi) < EPS) { + xy.x = fa + fa; + xy.y = - P->phi0; + } else { + xy.y = 1. / tan(lp.phi); + xy.x = sin(fa = 2. * atan(fa * sin(lp.phi))) * xy.y; + xy.y = lp.phi - P->phi0 + (1. - cos(fa)) * xy.y; + } + return xy; +} + + + +PJ *PROJECTION(rpoly) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + if ((Q->mode = (Q->phi1 = fabs(pj_param(P->ctx, P->params, "rlat_ts").f)) > EPS)) { + Q->fxb = 0.5 * sin(Q->phi1); + Q->fxa = 0.5 / Q->fxb; + } + P->es = 0.; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/sch.cpp b/src/projections/sch.cpp new file mode 100644 index 00000000..5a2f944b --- /dev/null +++ b/src/projections/sch.cpp @@ -0,0 +1,232 @@ +/****************************************************************************** + * Project: SCH Coordinate system + * Purpose: Implementation of SCH Coordinate system + * References : + * 1. Hensley. Scott. SCH Coordinates and various transformations. June 15, 2000. + * 2. Buckley, Sean Monroe. Radar interferometry measurement of land subsidence. 2000.. + * PhD Thesis. UT Austin. (Appendix) + * 3. Hensley, Scott, Elaine Chapin, and T. Michel. "Improved processing of AIRSAR + * data based on the GeoSAR processor." Airsar earth science and applications + * workshop, March. 2002. (http://airsar.jpl.nasa.gov/documents/workshop2002/papers/T3.pdf) + * + * Author: Piyush Agram (piyush.agram@jpl.nasa.gov) + * Copyright (c) 2015 California Institute of Technology. + * Government sponsorship acknowledged. + * + * NOTE: The SCH coordinate system is a sensor aligned coordinate system + * developed at JPL for radar mapping missions. Details pertaining to the + * coordinate system have been release in the public domain (see references above). + * This code is an independent implementation of the SCH coordinate system + * that conforms to the PROJ.4 conventions and uses the details presented in these + * publicly released documents. All credit for the development of the coordinate + * system and its use should be directed towards the original developers at JPL. + ****************************************************************************** + * 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. + ****************************************************************************/ + +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" +#include "geocent.h" + +namespace { // anonymous namespace +struct pj_opaque { + double plat; /*Peg Latitude */ + double plon; /*Peg Longitude*/ + double phdg; /*Peg heading */ + double h0; /*Average altitude */ + double transMat[9]; + double xyzoff[3]; + double rcurv; + GeocentricInfo sph; + GeocentricInfo elp_0; +}; +} // anonymous namespace + +PROJ_HEAD(sch, "Spherical Cross-track Height") "\n\tMisc\n\tplat_0= plon_0= phdg_0= [h_0=]"; + +static LPZ inverse3d(XYZ xyz, PJ *P) { + LPZ lpz = {0.0, 0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double temp[3]; + double pxyz[3]; + + /* Local lat,lon using radius */ + pxyz[0] = xyz.y * P->a / Q->rcurv; + pxyz[1] = xyz.x * P->a / Q->rcurv; + pxyz[2] = xyz.z; + + if( pj_Convert_Geodetic_To_Geocentric( &(Q->sph), pxyz[0], pxyz[1], pxyz[2], temp, temp+1, temp+2) != 0) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lpz; + } + + /* Apply rotation */ + pxyz[0] = Q->transMat[0] * temp[0] + Q->transMat[1] * temp[1] + Q->transMat[2] * temp[2]; + pxyz[1] = Q->transMat[3] * temp[0] + Q->transMat[4] * temp[1] + Q->transMat[5] * temp[2]; + pxyz[2] = Q->transMat[6] * temp[0] + Q->transMat[7] * temp[1] + Q->transMat[8] * temp[2]; + + /* Apply offset */ + pxyz[0] += Q->xyzoff[0]; + pxyz[1] += Q->xyzoff[1]; + pxyz[2] += Q->xyzoff[2]; + + /* Convert geocentric coordinates to lat lon */ + pj_Convert_Geocentric_To_Geodetic( &(Q->elp_0), pxyz[0], pxyz[1], pxyz[2], + temp, temp+1, temp+2); + + + lpz.lam = temp[1] ; + lpz.phi = temp[0] ; + lpz.z = temp[2]; + + return lpz; +} + +static XYZ forward3d(LPZ lpz, PJ *P) { + XYZ xyz = {0.0, 0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double temp[3]; + double pxyz[3]; + + + /* Convert lat lon to geocentric coordinates */ + if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), lpz.phi, lpz.lam, lpz.z, temp, temp+1, temp+2 ) != 0 ) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xyz; + } + + + /* Adjust for offset */ + temp[0] -= Q->xyzoff[0]; + temp[1] -= Q->xyzoff[1]; + temp[2] -= Q->xyzoff[2]; + + + /* Apply rotation */ + pxyz[0] = Q->transMat[0] * temp[0] + Q->transMat[3] * temp[1] + Q->transMat[6] * temp[2]; + pxyz[1] = Q->transMat[1] * temp[0] + Q->transMat[4] * temp[1] + Q->transMat[7] * temp[2]; + pxyz[2] = Q->transMat[2] * temp[0] + Q->transMat[5] * temp[1] + Q->transMat[8] * temp[2]; + + /* Convert to local lat,lon */ + pj_Convert_Geocentric_To_Geodetic( &(Q->sph), pxyz[0], pxyz[1], pxyz[2], + temp, temp+1, temp+2); + + + /* Scale by radius */ + xyz.x = temp[1] * Q->rcurv / P->a; + xyz.y = temp[0] * Q->rcurv / P->a; + xyz.z = temp[2]; + + return xyz; +} + + +static PJ *setup(PJ *P) { /* general initialization */ + struct pj_opaque *Q = static_cast(P->opaque); + double reast, rnorth; + double chdg, shdg; + double clt, slt; + double clo, slo; + double temp; + double pxyz[3]; + + temp = P->a * sqrt(1.0 - P->es); + + /* Setup original geocentric system */ + if ( pj_Set_Geocentric_Parameters(&(Q->elp_0), P->a, temp) != 0) + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); + + clt = cos(Q->plat); + slt = sin(Q->plat); + clo = cos(Q->plon); + slo = sin(Q->plon); + + /* Estimate the radius of curvature for given peg */ + temp = sqrt(1.0 - (P->es) * slt * slt); + reast = (P->a)/temp; + rnorth = (P->a) * (1.0 - (P->es))/pow(temp,3); + + chdg = cos(Q->phdg); + shdg = sin(Q->phdg); + + Q->rcurv = Q->h0 + (reast*rnorth)/(reast * chdg * chdg + rnorth * shdg * shdg); + + /* Set up local sphere at the given peg point */ + if ( pj_Set_Geocentric_Parameters(&(Q->sph), Q->rcurv, Q->rcurv) != 0) + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); + + /* Set up the transformation matrices */ + Q->transMat[0] = clt * clo; + Q->transMat[1] = -shdg*slo - slt*clo * chdg; + Q->transMat[2] = slo*chdg - slt*clo*shdg; + Q->transMat[3] = clt*slo; + Q->transMat[4] = clo*shdg - slt*slo*chdg; + Q->transMat[5] = -clo*chdg - slt*slo*shdg; + Q->transMat[6] = slt; + Q->transMat[7] = clt*chdg; + Q->transMat[8] = clt*shdg; + + + if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), Q->plat, Q->plon, Q->h0, + pxyz, pxyz+1, pxyz+2 ) != 0 ) + return pj_default_destructor(P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); + + + Q->xyzoff[0] = pxyz[0] - (Q->rcurv) * clt * clo; + Q->xyzoff[1] = pxyz[1] - (Q->rcurv) * clt * slo; + Q->xyzoff[2] = pxyz[2] - (Q->rcurv) * slt; + + P->fwd3d = forward3d; + P->inv3d = inverse3d; + return P; +} + + +PJ *PROJECTION(sch) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + Q->h0 = 0.0; + + /* Check if peg latitude was defined */ + if (pj_param(P->ctx, P->params, "tplat_0").i) + Q->plat = pj_param(P->ctx, P->params, "rplat_0").f; + else { + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); + } + + /* Check if peg longitude was defined */ + if (pj_param(P->ctx, P->params, "tplon_0").i) + Q->plon = pj_param(P->ctx, P->params, "rplon_0").f; + else { + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); + } + + /* Check if peg latitude is defined */ + if (pj_param(P->ctx, P->params, "tphdg_0").i) + Q->phdg = pj_param(P->ctx, P->params, "rphdg_0").f; + else { + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); + } + + + /* Check if average height was defined - If so read it in */ + if (pj_param(P->ctx, P->params, "th_0").i) + Q->h0 = pj_param(P->ctx, P->params, "dh_0").f; + + + return setup(P); +} diff --git a/src/projections/sconics.cpp b/src/projections/sconics.cpp new file mode 100644 index 00000000..1d19a13d --- /dev/null +++ b/src/projections/sconics.cpp @@ -0,0 +1,220 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + + +namespace { // anonymous namespace +enum Type { + EULER = 0, + MURD1 = 1, + MURD2 = 2, + MURD3 = 3, + PCONIC = 4, + TISSOT = 5, + VITK1 = 6 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double n; + double rho_c; + double rho_0; + double sig; + double c1, c2; + enum Type type; +}; +} // anonymous namespace + + +#define EPS10 1.e-10 +#define EPS 1e-10 +#define LINE2 "\n\tConic, Sph\n\tlat_1= and lat_2=" + +PROJ_HEAD(euler, "Euler") LINE2; +PROJ_HEAD(murd1, "Murdoch I") LINE2; +PROJ_HEAD(murd2, "Murdoch II") LINE2; +PROJ_HEAD(murd3, "Murdoch III") LINE2; +PROJ_HEAD(pconic, "Perspective Conic") LINE2; +PROJ_HEAD(tissot, "Tissot") LINE2; +PROJ_HEAD(vitk1, "Vitkovsky I") LINE2; + + + +/* get common factors for simple conics */ +static int phi12(PJ *P, double *del) { + double p1, p2; + int err = 0; + + if (!pj_param(P->ctx, P->params, "tlat_1").i || + !pj_param(P->ctx, P->params, "tlat_2").i) { + err = -41; + } else { + p1 = pj_param(P->ctx, P->params, "rlat_1").f; + p2 = pj_param(P->ctx, P->params, "rlat_2").f; + *del = 0.5 * (p2 - p1); + static_cast(P->opaque)->sig = 0.5 * (p2 + p1); + err = (fabs(*del) < EPS || fabs(static_cast(P->opaque)->sig) < EPS) ? PJD_ERR_ABS_LAT1_EQ_ABS_LAT2 : 0; + } + return err; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double rho; + + switch (Q->type) { + case MURD2: + rho = Q->rho_c + tan (Q->sig - lp.phi); + break; + case PCONIC: + rho = Q->c2 * (Q->c1 - tan (lp.phi - Q->sig)); + break; + default: + rho = Q->rho_c - lp.phi; + break; + } + + xy.x = rho * sin ( lp.lam *= Q->n ); + xy.y = Q->rho_0 - rho * cos (lp.lam); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, (and ellipsoidal?) inverse */ + LP lp = {0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double rho; + + rho = hypot (xy.x, xy.y = Q->rho_0 - xy.y); + if (Q->n < 0.) { + rho = - rho; + xy.x = - xy.x; + xy.y = - xy.y; + } + + lp.lam = atan2 (xy.x, xy.y) / Q->n; + + switch (Q->type) { + case PCONIC: + lp.phi = atan (Q->c1 - rho / Q->c2) + Q->sig; + break; + case MURD2: + lp.phi = Q->sig - atan(rho - Q->rho_c); + break; + default: + lp.phi = Q->rho_c - rho; + } + return lp; +} + + +static PJ *setup(PJ *P, enum Type type) { + double del, cs; + int err; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + Q->type = type; + + err = phi12 (P, &del); + if(err) + return pj_default_destructor (P, err); + + switch (Q->type) { + + case TISSOT: + Q->n = sin (Q->sig); + cs = cos (del); + Q->rho_c = Q->n / cs + cs / Q->n; + Q->rho_0 = sqrt ((Q->rho_c - 2 * sin (P->phi0)) / Q->n); + break; + + case MURD1: + Q->rho_c = sin(del)/(del * tan(Q->sig)) + Q->sig; + Q->rho_0 = Q->rho_c - P->phi0; + Q->n = sin(Q->sig); + break; + + case MURD2: + Q->rho_c = (cs = sqrt (cos (del))) / tan (Q->sig); + Q->rho_0 = Q->rho_c + tan (Q->sig - P->phi0); + Q->n = sin (Q->sig) * cs; + break; + + case MURD3: + Q->rho_c = del / (tan(Q->sig) * tan(del)) + Q->sig; + Q->rho_0 = Q->rho_c - P->phi0; + Q->n = sin (Q->sig) * sin (del) * tan (del) / (del * del); + break; + + case EULER: + Q->n = sin (Q->sig) * sin (del) / del; + del *= 0.5; + Q->rho_c = del / (tan (del) * tan (Q->sig)) + Q->sig; + Q->rho_0 = Q->rho_c - P->phi0; + break; + + case PCONIC: + Q->n = sin (Q->sig); + Q->c2 = cos (del); + Q->c1 = 1./tan (Q->sig); + if (fabs (del = P->phi0 - Q->sig) - EPS10 >= M_HALFPI) + return pj_default_destructor(P, PJD_ERR_LAT_0_HALF_PI_FROM_MEAN); + + Q->rho_0 = Q->c2 * (Q->c1 - tan (del)); + break; + + case VITK1: + Q->n = (cs = tan (del)) * sin (Q->sig) / del; + Q->rho_c = del / (cs * tan (Q->sig)) + Q->sig; + Q->rho_0 = Q->rho_c - P->phi0; + break; + } + + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0; + return (P); +} + + +PJ *PROJECTION(euler) { + return setup(P, EULER); +} + + +PJ *PROJECTION(tissot) { + return setup(P, TISSOT); +} + + +PJ *PROJECTION(murd1) { + return setup(P, MURD1); +} + + +PJ *PROJECTION(murd2) { + return setup(P, MURD2); +} + + +PJ *PROJECTION(murd3) { + return setup(P, MURD3); +} + + +PJ *PROJECTION(pconic) { + return setup(P, PCONIC); +} + + +PJ *PROJECTION(vitk1) { + return setup(P, VITK1); +} + diff --git a/src/projections/somerc.cpp b/src/projections/somerc.cpp new file mode 100644 index 00000000..15d2e765 --- /dev/null +++ b/src/projections/somerc.cpp @@ -0,0 +1,94 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(somerc, "Swiss. Obl. Mercator") "\n\tCyl, Ell\n\tFor CH1903"; + +namespace { // anonymous namespace +struct pj_opaque { + double K, c, hlf_e, kR, cosp0, sinp0; +}; +} // anonymous namespace + +#define EPS 1.e-10 +#define NITER 6 + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0, 0.0}; + double phip, lamp, phipp, lampp, sp, cp; + struct pj_opaque *Q = static_cast(P->opaque); + + sp = P->e * sin (lp.phi); + phip = 2.* atan ( exp ( Q->c * ( + log (tan (M_FORTPI + 0.5 * lp.phi)) - Q->hlf_e * log ((1. + sp)/(1. - sp))) + + Q->K)) - M_HALFPI; + lamp = Q->c * lp.lam; + cp = cos(phip); + phipp = aasin (P->ctx, Q->cosp0 * sin (phip) - Q->sinp0 * cp * cos (lamp)); + lampp = aasin (P->ctx, cp * sin (lamp) / cos (phipp)); + xy.x = Q->kR * lampp; + xy.y = Q->kR * log (tan (M_FORTPI + 0.5 * phipp)); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double phip, lamp, phipp, lampp, cp, esp, con, delp; + int i; + + phipp = 2. * (atan (exp (xy.y / Q->kR)) - M_FORTPI); + lampp = xy.x / Q->kR; + cp = cos (phipp); + phip = aasin (P->ctx, Q->cosp0 * sin (phipp) + Q->sinp0 * cp * cos (lampp)); + lamp = aasin (P->ctx, cp * sin (lampp) / cos (phip)); + con = (Q->K - log (tan (M_FORTPI + 0.5 * phip)))/Q->c; + for (i = NITER; i ; --i) { + esp = P->e * sin(phip); + delp = (con + log(tan(M_FORTPI + 0.5 * phip)) - Q->hlf_e * + log((1. + esp)/(1. - esp)) ) * + (1. - esp * esp) * cos(phip) * P->rone_es; + phip -= delp; + if (fabs(delp) < EPS) + break; + } + if (i) { + lp.phi = phip; + lp.lam = lamp / Q->c; + } else { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + return (lp); +} + + +PJ *PROJECTION(somerc) { + double cp, phip0, sp; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + + Q->hlf_e = 0.5 * P->e; + cp = cos (P->phi0); + cp *= cp; + Q->c = sqrt (1 + P->es * cp * cp * P->rone_es); + sp = sin (P->phi0); + Q->cosp0 = cos( phip0 = aasin (P->ctx, Q->sinp0 = sp / Q->c) ); + sp *= P->e; + Q->K = log (tan (M_FORTPI + 0.5 * phip0)) - Q->c * ( + log (tan (M_FORTPI + 0.5 * P->phi0)) - Q->hlf_e * + log ((1. + sp) / (1. - sp))); + Q->kR = P->k0 * sqrt(P->one_es) / (1. - sp * sp); + P->inv = e_inverse; + P->fwd = e_forward; + return P; +} diff --git a/src/projections/stere.cpp b/src/projections/stere.cpp new file mode 100644 index 00000000..1502b2a6 --- /dev/null +++ b/src/projections/stere.cpp @@ -0,0 +1,320 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "projects.h" +#include "proj_math.h" + +PROJ_HEAD(stere, "Stereographic") "\n\tAzi, Sph&Ell\n\tlat_ts="; +PROJ_HEAD(ups, "Universal Polar Stereographic") "\n\tAzi, Sph&Ell\n\tsouth"; + + +namespace { // anonymous namespace +enum Mode { + S_POLE = 0, + N_POLE = 1, + OBLIQ = 2, + EQUIT = 3 +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque { + double phits; + double sinX1; + double cosX1; + double akm1; + enum Mode mode; +}; +} // anonymous namespace + +#define sinph0 static_cast(P->opaque)->sinX1 +#define cosph0 static_cast(P->opaque)->cosX1 +#define EPS10 1.e-10 +#define TOL 1.e-8 +#define NITER 8 +#define CONV 1.e-10 + +static double ssfn_ (double phit, double sinphi, double eccen) { + sinphi *= eccen; + return (tan (.5 * (M_HALFPI + phit)) * + pow ((1. - sinphi) / (1. + sinphi), .5 * eccen)); +} + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double coslam, sinlam, sinX = 0.0, cosX = 0.0, X, A = 0.0, sinphi; + + coslam = cos (lp.lam); + sinlam = sin (lp.lam); + sinphi = sin (lp.phi); + if (Q->mode == OBLIQ || Q->mode == EQUIT) { + sinX = sin (X = 2. * atan(ssfn_(lp.phi, sinphi, P->e)) - M_HALFPI); + cosX = cos (X); + } + + switch (Q->mode) { + case OBLIQ: + A = Q->akm1 / (Q->cosX1 * (1. + Q->sinX1 * sinX + + Q->cosX1 * cosX * coslam)); + xy.y = A * (Q->cosX1 * sinX - Q->sinX1 * cosX * coslam); + goto xmul; /* but why not just xy.x = A * cosX; break; ? */ + + case EQUIT: + /* avoid zero division */ + if (1. + cosX * coslam == 0.0) { + xy.y = HUGE_VAL; + } else { + A = Q->akm1 / (1. + cosX * coslam); + xy.y = A * sinX; + } +xmul: + xy.x = A * cosX; + break; + + case S_POLE: + lp.phi = -lp.phi; + coslam = - coslam; + sinphi = -sinphi; + /*-fallthrough*/ + case N_POLE: + xy.x = Q->akm1 * pj_tsfn (lp.phi, sinphi, P->e); + xy.y = - xy.x * coslam; + break; + } + + xy.x = xy.x * sinlam; + return xy; +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double sinphi, cosphi, coslam, sinlam; + + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + coslam = cos(lp.lam); + sinlam = sin(lp.lam); + + switch (Q->mode) { + case EQUIT: + xy.y = 1. + cosphi * coslam; + goto oblcon; + case OBLIQ: + xy.y = 1. + sinph0 * sinphi + cosph0 * cosphi * coslam; +oblcon: + if (xy.y <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.x = (xy.y = Q->akm1 / xy.y) * cosphi * sinlam; + xy.y *= (Q->mode == EQUIT) ? sinphi : + cosph0 * sinphi - sinph0 * cosphi * coslam; + break; + case N_POLE: + coslam = - coslam; + lp.phi = - lp.phi; + /*-fallthrough*/ + case S_POLE: + if (fabs (lp.phi - M_HALFPI) < TOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.x = sinlam * ( xy.y = Q->akm1 * tan (M_FORTPI + .5 * lp.phi) ); + xy.y *= coslam; + break; + } + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cosphi, sinphi, tp=0.0, phi_l=0.0, rho, halfe=0.0, halfpi=0.0; + int i; + + rho = hypot (xy.x, xy.y); + + switch (Q->mode) { + case OBLIQ: + case EQUIT: + cosphi = cos ( tp = 2. * atan2 (rho * Q->cosX1 , Q->akm1) ); + sinphi = sin (tp); + if ( rho == 0.0 ) + phi_l = asin (cosphi * Q->sinX1); + else + phi_l = asin (cosphi * Q->sinX1 + (xy.y * sinphi * Q->cosX1 / rho)); + + tp = tan (.5 * (M_HALFPI + phi_l)); + xy.x *= sinphi; + xy.y = rho * Q->cosX1 * cosphi - xy.y * Q->sinX1* sinphi; + halfpi = M_HALFPI; + halfe = .5 * P->e; + break; + case N_POLE: + xy.y = -xy.y; + /*-fallthrough*/ + case S_POLE: + phi_l = M_HALFPI - 2. * atan (tp = - rho / Q->akm1); + halfpi = -M_HALFPI; + halfe = -.5 * P->e; + break; + } + + for (i = NITER; i--; phi_l = lp.phi) { + sinphi = P->e * sin(phi_l); + lp.phi = 2. * atan (tp * pow ((1.+sinphi)/(1.-sinphi), halfe)) - halfpi; + if (fabs (phi_l - lp.phi) < CONV) { + if (Q->mode == S_POLE) + lp.phi = -lp.phi; + lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2 (xy.x, xy.y); + return lp; + } + } + + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double c, rh, sinc, cosc; + + sinc = sin (c = 2. * atan ((rh = hypot (xy.x, xy.y)) / Q->akm1)); + cosc = cos (c); + lp.lam = 0.; + + switch (Q->mode) { + case EQUIT: + if (fabs (rh) <= EPS10) + lp.phi = 0.; + else + lp.phi = asin (xy.y * sinc / rh); + if (cosc != 0. || xy.x != 0.) + lp.lam = atan2 (xy.x * sinc, cosc * rh); + break; + case OBLIQ: + if (fabs (rh) <= EPS10) + lp.phi = P->phi0; + else + lp.phi = asin (cosc * sinph0 + xy.y * sinc * cosph0 / rh); + if ((c = cosc - sinph0 * sin (lp.phi)) != 0. || xy.x != 0.) + lp.lam = atan2 (xy.x * sinc * cosph0, c * rh); + break; + case N_POLE: + xy.y = -xy.y; + /*-fallthrough*/ + case S_POLE: + if (fabs (rh) <= EPS10) + lp.phi = P->phi0; + else + lp.phi = asin (Q->mode == S_POLE ? - cosc : cosc); + lp.lam = (xy.x == 0. && xy.y == 0.) ? 0. : atan2 (xy.x, xy.y); + break; + } + return lp; +} + + +static PJ *setup(PJ *P) { /* general initialization */ + double t; + struct pj_opaque *Q = static_cast(P->opaque); + + if (fabs ((t = fabs (P->phi0)) - M_HALFPI) < EPS10) + Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + else + Q->mode = t > EPS10 ? OBLIQ : EQUIT; + Q->phits = fabs (Q->phits); + + if (P->es != 0.0) { + double X; + + switch (Q->mode) { + case N_POLE: + case S_POLE: + if (fabs (Q->phits - M_HALFPI) < EPS10) + Q->akm1 = 2. * P->k0 / + sqrt (pow (1+P->e,1+P->e) * pow (1-P->e,1-P->e)); + else { + Q->akm1 = cos (Q->phits) / + pj_tsfn (Q->phits, t = sin (Q->phits), P->e); + t *= P->e; + Q->akm1 /= sqrt(1. - t * t); + } + break; + case EQUIT: + case OBLIQ: + t = sin (P->phi0); + X = 2. * atan (ssfn_(P->phi0, t, P->e)) - M_HALFPI; + t *= P->e; + Q->akm1 = 2. * P->k0 * cos (P->phi0) / sqrt(1. - t * t); + Q->sinX1 = sin (X); + Q->cosX1 = cos (X); + break; + } + P->inv = e_inverse; + P->fwd = e_forward; + } else { + switch (Q->mode) { + case OBLIQ: + sinph0 = sin (P->phi0); + cosph0 = cos (P->phi0); + /*-fallthrough*/ + case EQUIT: + Q->akm1 = 2. * P->k0; + break; + case S_POLE: + case N_POLE: + Q->akm1 = fabs (Q->phits - M_HALFPI) >= EPS10 ? + cos (Q->phits) / tan (M_FORTPI - .5 * Q->phits) : + 2. * P->k0 ; + break; + } + + P->inv = s_inverse; + P->fwd = s_forward; + } + return P; +} + + +PJ *PROJECTION(stere) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->phits = pj_param (P->ctx, P->params, "tlat_ts").i ? + pj_param (P->ctx, P->params, "rlat_ts").f : M_HALFPI; + + return setup(P); +} + + +PJ *PROJECTION(ups) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + /* International Ellipsoid */ + P->phi0 = pj_param(P->ctx, P->params, "bsouth").i ? - M_HALFPI: M_HALFPI; + if (P->es == 0.0) { + proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); + return pj_default_destructor (P, ENOMEM); + } + P->k0 = .994; + P->x0 = 2000000.; + P->y0 = 2000000.; + Q->phits = M_HALFPI; + P->lam0 = 0.; + + return setup(P); +} + diff --git a/src/projections/sterea.cpp b/src/projections/sterea.cpp new file mode 100644 index 00000000..bb498068 --- /dev/null +++ b/src/projections/sterea.cpp @@ -0,0 +1,117 @@ +/* +** libproj -- library of cartographic projections +** +** Copyright (c) 2003 Gerald I. Evenden +*/ +/* +** 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. +*/ +#define PJ_LIB__ +#include +#include "projects.h" +#include "proj_math.h" + + +namespace { // anonymous namespace +struct pj_opaque { + double phic0; + double cosc0, sinc0; + double R2; + void *en; +}; +} // anonymous namespace + + +PROJ_HEAD(sterea, "Oblique Stereographic Alternative") "\n\tAzimuthal, Sph&Ell"; + + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cosc, sinc, cosl, k; + + lp = pj_gauss(P->ctx, lp, Q->en); + sinc = sin(lp.phi); + cosc = cos(lp.phi); + cosl = cos(lp.lam); + k = P->k0 * Q->R2 / (1. + Q->sinc0 * sinc + Q->cosc0 * cosc * cosl); + xy.x = k * cosc * sin(lp.lam); + xy.y = k * (Q->cosc0 * sinc - Q->sinc0 * cosc * cosl); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double rho, c, sinc, cosc; + + xy.x /= P->k0; + xy.y /= P->k0; + if ( (rho = hypot (xy.x, xy.y)) != 0.0 ) { + c = 2. * atan2 (rho, Q->R2); + sinc = sin (c); + cosc = cos (c); + lp.phi = asin (cosc * Q->sinc0 + xy.y * sinc * Q->cosc0 / rho); + lp.lam = atan2 (xy.x * sinc, rho * Q->cosc0 * cosc - xy.y * Q->sinc0 * sinc); + } else { + lp.phi = Q->phic0; + lp.lam = 0.; + } + return pj_inv_gauss(P->ctx, lp, Q->en); +} + + +static PJ *destructor (PJ *P, int errlev) { + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor (P, errlev); +} + + +PJ *PROJECTION(sterea) { + double R; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->en = pj_gauss_ini(P->e, P->phi0, &(Q->phic0), &R); + if (nullptr==Q->en) + return pj_default_destructor (P, ENOMEM); + + Q->sinc0 = sin (Q->phic0); + Q->cosc0 = cos (Q->phic0); + Q->R2 = 2. * R; + + P->inv = e_inverse; + P->fwd = e_forward; + P->destructor = destructor; + + return P; +} + diff --git a/src/projections/sts.cpp b/src/projections/sts.cpp new file mode 100644 index 00000000..9f889611 --- /dev/null +++ b/src/projections/sts.cpp @@ -0,0 +1,109 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(kav5, "Kavraisky V") "\n\tPCyl, Sph"; +PROJ_HEAD(qua_aut, "Quartic Authalic") "\n\tPCyl, Sph"; +PROJ_HEAD(fouc, "Foucaut") "\n\tPCyl, Sph"; +PROJ_HEAD(mbt_s, "McBryde-Thomas Flat-Polar Sine (No. 1)") "\n\tPCyl, Sph"; + + +namespace { // anonymous namespace +struct pj_opaque { + double C_x, C_y, C_p; + int tan_mode; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double c; + + xy.x = Q->C_x * lp.lam * cos(lp.phi); + xy.y = Q->C_y; + lp.phi *= Q->C_p; + c = cos(lp.phi); + if (Q->tan_mode) { + xy.x *= c * c; + xy.y *= tan (lp.phi); + } else { + xy.x /= c; + xy.y *= sin (lp.phi); + } + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double c; + + xy.y /= Q->C_y; + c = cos (lp.phi = Q->tan_mode ? atan (xy.y) : aasin (P->ctx, xy.y)); + lp.phi /= Q->C_p; + lp.lam = xy.x / (Q->C_x * cos(lp.phi)); + if (Q->tan_mode) + lp.lam /= c * c; + else + lp.lam *= c; + return lp; +} + + +static PJ *setup(PJ *P, double p, double q, int mode) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + static_cast(P->opaque)->C_x = q / p; + static_cast(P->opaque)->C_y = p; + static_cast(P->opaque)->C_p = 1/ q; + static_cast(P->opaque)->tan_mode = mode; + return P; +} + + + +PJ *PROJECTION(fouc) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + return setup(P, 2., 2., 1); +} + + + +PJ *PROJECTION(kav5) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + return setup(P, 1.50488, 1.35439, 0); +} + + + +PJ *PROJECTION(qua_aut) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + return setup(P, 2., 2., 0); +} + + + +PJ *PROJECTION(mbt_s) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + return setup(P, 1.48875, 1.36509, 0); +} diff --git a/src/projections/tcc.cpp b/src/projections/tcc.cpp new file mode 100644 index 00000000..64fdc182 --- /dev/null +++ b/src/projections/tcc.cpp @@ -0,0 +1,34 @@ +#define PJ_LIB__ + +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(tcc, "Transverse Central Cylindrical") "\n\tCyl, Sph, no inv"; + +#define EPS10 1.e-10 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + double b, bt; + + b = cos (lp.phi) * sin (lp.lam); + if ((bt = 1. - b * b) < EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + xy.x = b / sqrt(bt); + xy.y = atan2 (tan (lp.phi) , cos (lp.lam)); + return xy; +} + + +PJ *PROJECTION(tcc) { + P->es = 0.; + P->fwd = s_forward; + P->inv = nullptr; + + return P; +} diff --git a/src/projections/tcea.cpp b/src/projections/tcea.cpp new file mode 100644 index 00000000..d30f3df0 --- /dev/null +++ b/src/projections/tcea.cpp @@ -0,0 +1,36 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(tcea, "Transverse Cylindrical Equal Area") "\n\tCyl, Sph"; + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + xy.x = cos (lp.phi) * sin (lp.lam) / P->k0; + xy.y = P->k0 * (atan2 (tan (lp.phi), cos (lp.lam)) - P->phi0); + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0, 0.0}; + double t; + + xy.y = xy.y / P->k0 + P->phi0; + xy.x *= P->k0; + t = sqrt (1. - xy.x * xy.x); + lp.phi = asin (t * sin (xy.y)); + lp.lam = atan2 (xy.x, t * cos (xy.y)); + return lp; +} + + +PJ *PROJECTION(tcea) { + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + return P; +} diff --git a/src/projections/times.cpp b/src/projections/times.cpp new file mode 100644 index 00000000..e8b4499f --- /dev/null +++ b/src/projections/times.cpp @@ -0,0 +1,79 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the Times projection. + * Author: Kristian Evers + * + ****************************************************************************** + * Copyright (c) 2016, Kristian Evers + * + * 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. + ***************************************************************************** + * Based on describtion of the Times Projection in + * + * Flattening the Earth, Snyder, J.P., 1993, p.213-214. + *****************************************************************************/ + +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(times, "Times") "\n\tCyl, Sph"; + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + double T, S, S2; + XY xy = {0.0,0.0}; + (void) P; + + T = tan(lp.phi/2.0); + S = sin(M_FORTPI * T); + S2 = S*S; + + xy.x = lp.lam * (0.74482 - 0.34588*S2); + xy.y = 1.70711 * T; + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + double T, S, S2; + LP lp = {0.0,0.0}; + (void) P; + + T = xy.y / 1.70711; + S = sin(M_FORTPI * T); + S2 = S*S; + + lp.lam = xy.x / (0.74482 - 0.34588 * S2); + lp.phi = 2 * atan(T); + + return lp; +} + + +PJ *PROJECTION(times) { + P->es = 0.0; + + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/tmerc.cpp b/src/projections/tmerc.cpp new file mode 100644 index 00000000..5a2dacbd --- /dev/null +++ b/src/projections/tmerc.cpp @@ -0,0 +1,210 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(tmerc, "Transverse Mercator") "\n\tCyl, Sph&Ell"; + + +namespace { // anonymous namespace +struct pj_opaque { + double esp; + double ml0; + double *en; +}; +} // anonymous namespace + +#define EPS10 1.e-10 +#define FC1 1. +#define FC2 .5 +#define FC3 .16666666666666666666 +#define FC4 .08333333333333333333 +#define FC5 .05 +#define FC6 .03333333333333333333 +#define FC7 .02380952380952380952 +#define FC8 .01785714285714285714 + + +static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ + XY xy = {0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double al, als, n, cosphi, sinphi, t; + + /* + * Fail if our longitude is more than 90 degrees from the + * central meridian since the results are essentially garbage. + * Is error -20 really an appropriate return value? + * + * http://trac.osgeo.org/proj/ticket/5 + */ + if( lp.lam < -M_HALFPI || lp.lam > M_HALFPI ) { + xy.x = HUGE_VAL; + xy.y = HUGE_VAL; + pj_ctx_set_errno( P->ctx, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT ); + return xy; + } + + sinphi = sin (lp.phi); + cosphi = cos (lp.phi); + t = fabs (cosphi) > 1e-10 ? sinphi/cosphi : 0.; + t *= t; + al = cosphi * lp.lam; + als = al * al; + al /= sqrt (1. - P->es * sinphi * sinphi); + n = Q->esp * cosphi * cosphi; + xy.x = P->k0 * al * (FC1 + + FC3 * als * (1. - t + n + + FC5 * als * (5. + t * (t - 18.) + n * (14. - 58. * t) + + FC7 * als * (61. + t * ( t * (179. - t) - 479. ) ) + ))); + xy.y = P->k0 * (pj_mlfn(lp.phi, sinphi, cosphi, Q->en) - Q->ml0 + + sinphi * al * lp.lam * FC2 * ( 1. + + FC4 * als * (5. - t + n * (9. + 4. * n) + + FC6 * als * (61. + t * (t - 58.) + n * (270. - 330 * t) + + FC8 * als * (1385. + t * ( t * (543. - t) - 3111.) ) + )))); + return (xy); +} + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double b, cosphi; + + /* + * Fail if our longitude is more than 90 degrees from the + * central meridian since the results are essentially garbage. + * Is error -20 really an appropriate return value? + * + * http://trac.osgeo.org/proj/ticket/5 + */ + if( lp.lam < -M_HALFPI || lp.lam > M_HALFPI ) { + xy.x = HUGE_VAL; + xy.y = HUGE_VAL; + pj_ctx_set_errno( P->ctx, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT ); + return xy; + } + + cosphi = cos(lp.phi); + b = cosphi * sin (lp.lam); + if (fabs (fabs (b) - 1.) <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + + xy.x = static_cast(P->opaque)->ml0 * log ((1. + b) / (1. - b)); + xy.y = cosphi * cos (lp.lam) / sqrt (1. - b * b); + + b = fabs ( xy.y ); + if (b >= 1.) { + if ((b - 1.) > EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + else xy.y = 0.; + } else + xy.y = acos (xy.y); + + if (lp.phi < 0.) + xy.y = -xy.y; + xy.y = static_cast(P->opaque)->esp * (xy.y - P->phi0); + return xy; +} + + +static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double n, con, cosphi, d, ds, sinphi, t; + + lp.phi = pj_inv_mlfn(P->ctx, Q->ml0 + xy.y / P->k0, P->es, Q->en); + if (fabs(lp.phi) >= M_HALFPI) { + lp.phi = xy.y < 0. ? -M_HALFPI : M_HALFPI; + lp.lam = 0.; + } else { + sinphi = sin(lp.phi); + cosphi = cos(lp.phi); + t = fabs (cosphi) > 1e-10 ? sinphi/cosphi : 0.; + n = Q->esp * cosphi * cosphi; + d = xy.x * sqrt (con = 1. - P->es * sinphi * sinphi) / P->k0; + con *= t; + t *= t; + ds = d * d; + lp.phi -= (con * ds / (1.-P->es)) * FC2 * (1. - + ds * FC4 * (5. + t * (3. - 9. * n) + n * (1. - 4 * n) - + ds * FC6 * (61. + t * (90. - 252. * n + + 45. * t) + 46. * n + - ds * FC8 * (1385. + t * (3633. + t * (4095. + 1575. * t)) ) + ))); + lp.lam = d*(FC1 - + ds*FC3*( 1. + 2.*t + n - + ds*FC5*(5. + t*(28. + 24.*t + 8.*n) + 6.*n + - ds * FC7 * (61. + t * (662. + t * (1320. + 720. * t)) ) + ))) / cosphi; + } + return lp; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0, 0.0}; + double h, g; + + h = exp(xy.x / static_cast(P->opaque)->esp); + g = .5 * (h - 1. / h); + h = cos (P->phi0 + xy.y / static_cast(P->opaque)->esp); + lp.phi = asin(sqrt((1. - h * h) / (1. + g * g))); + + /* Make sure that phi is on the correct hemisphere when false northing is used */ + if (xy.y < 0. && -lp.phi+P->phi0 < 0.0) lp.phi = -lp.phi; + + lp.lam = (g != 0.0 || h != 0.0) ? atan2 (g, h) : 0.; + return lp; +} + + +static PJ *destructor(PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + + if (nullptr==P->opaque) + return pj_default_destructor(P, errlev); + + pj_dealloc (static_cast(P->opaque)->en); + return pj_default_destructor(P, errlev); +} + + +static PJ *setup(PJ *P) { /* general initialization */ + struct pj_opaque *Q = static_cast(P->opaque); + if (P->es != 0.0) { + if (!(Q->en = pj_enfn(P->es))) + return pj_default_destructor(P, ENOMEM); + + Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); + Q->esp = P->es / (1. - P->es); + P->inv = e_inverse; + P->fwd = e_forward; + } else { + Q->esp = P->k0; + Q->ml0 = .5 * Q->esp; + P->inv = s_inverse; + P->fwd = s_forward; + } + return P; +} + + +PJ *PROJECTION(tmerc) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + + P->opaque = Q; + P->destructor = destructor; + + return setup(P); +} diff --git a/src/projections/tobmerc.cpp b/src/projections/tobmerc.cpp new file mode 100644 index 00000000..9c939f0b --- /dev/null +++ b/src/projections/tobmerc.cpp @@ -0,0 +1,51 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj_internal.h" +#include "proj.h" +#include "proj_math.h" +#include "projects.h" + +PROJ_HEAD(tobmerc, "Tobler-Mercator") "\n\tCyl, Sph"; + +#define EPS10 1.e-10 +static double logtanpfpim1(double x) { /* log(tan(x/2 + M_FORTPI)) */ + if (fabs(x) <= DBL_EPSILON) { + /* tan(M_FORTPI + .5 * x) can be approximated by 1.0 + x */ + return log1p(x); + } + return log(tan(M_FORTPI + .5 * x)); +} + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + double cosphi; + + if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + + cosphi = cos(lp.phi); + xy.x = P->k0 * lp.lam * cosphi * cosphi; + xy.y = P->k0 * logtanpfpim1(lp.phi); + return xy; +} + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0, 0.0}; + double cosphi; + + lp.phi = atan(sinh(xy.y / P->k0)); + cosphi = cos(lp.phi); + lp.lam = xy.x / P->k0 / (cosphi * cosphi); + return lp; +} + +PJ *PROJECTION(tobmerc) { + P->inv = s_inverse; + P->fwd = s_forward; + return P; +} diff --git a/src/projections/tpeqd.cpp b/src/projections/tpeqd.cpp new file mode 100644 index 00000000..2720327a --- /dev/null +++ b/src/projections/tpeqd.cpp @@ -0,0 +1,109 @@ +#define PJ_LIB__ +#include +#include "proj.h" +#include "proj_math.h" +#include "projects.h" + + +PROJ_HEAD(tpeqd, "Two Point Equidistant") + "\n\tMisc Sph\n\tlat_1= lon_1= lat_2= lon_2="; + +namespace { // anonymous namespace +struct pj_opaque { + double cp1, sp1, cp2, sp2, ccs, cs, sc, r2z0, z02, dlam2; + double hz0, thz0, rhshz0, ca, sa, lp, lamc; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double t, z1, z2, dl1, dl2, sp, cp; + + sp = sin(lp.phi); + cp = cos(lp.phi); + z1 = aacos(P->ctx, Q->sp1 * sp + Q->cp1 * cp * cos (dl1 = lp.lam + Q->dlam2)); + z2 = aacos(P->ctx, Q->sp2 * sp + Q->cp2 * cp * cos (dl2 = lp.lam - Q->dlam2)); + z1 *= z1; + z2 *= z2; + + xy.x = Q->r2z0 * (t = z1 - z2); + t = Q->z02 - t; + xy.y = Q->r2z0 * asqrt (4. * Q->z02 * z2 - t * t); + if ((Q->ccs * sp - cp * (Q->cs * sin(dl1) - Q->sc * sin(dl2))) < 0.) + xy.y = -xy.y; + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double cz1, cz2, s, d, cp, sp; + + cz1 = cos (hypot(xy.y, xy.x + Q->hz0)); + cz2 = cos (hypot(xy.y, xy.x - Q->hz0)); + s = cz1 + cz2; + d = cz1 - cz2; + lp.lam = - atan2(d, (s * Q->thz0)); + lp.phi = aacos(P->ctx, hypot (Q->thz0 * s, d) * Q->rhshz0); + if ( xy.y < 0. ) + lp.phi = - lp.phi; + /* lam--phi now in system relative to P1--P2 base equator */ + sp = sin (lp.phi); + cp = cos (lp.phi); + lp.phi = aasin (P->ctx, Q->sa * sp + Q->ca * cp * (s = cos(lp.lam -= Q->lp))); + lp.lam = atan2 (cp * sin(lp.lam), Q->sa * cp * s - Q->ca * sp) + Q->lamc; + return lp; +} + + +PJ *PROJECTION(tpeqd) { + double lam_1, lam_2, phi_1, phi_2, A12, pp; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + + /* get control point locations */ + phi_1 = pj_param(P->ctx, P->params, "rlat_1").f; + lam_1 = pj_param(P->ctx, P->params, "rlon_1").f; + phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; + lam_2 = pj_param(P->ctx, P->params, "rlon_2").f; + + if (phi_1 == phi_2 && lam_1 == lam_2) + return pj_default_destructor(P, PJD_ERR_CONTROL_POINT_NO_DIST); + + P->lam0 = adjlon (0.5 * (lam_1 + lam_2)); + Q->dlam2 = adjlon (lam_2 - lam_1); + + Q->cp1 = cos (phi_1); + Q->cp2 = cos (phi_2); + Q->sp1 = sin (phi_1); + Q->sp2 = sin (phi_2); + Q->cs = Q->cp1 * Q->sp2; + Q->sc = Q->sp1 * Q->cp2; + Q->ccs = Q->cp1 * Q->cp2 * sin(Q->dlam2); + Q->z02 = aacos(P->ctx, Q->sp1 * Q->sp2 + Q->cp1 * Q->cp2 * cos (Q->dlam2)); + Q->hz0 = .5 * Q->z02; + A12 = atan2(Q->cp2 * sin (Q->dlam2), + Q->cp1 * Q->sp2 - Q->sp1 * Q->cp2 * cos (Q->dlam2)); + Q->ca = cos(pp = aasin(P->ctx, Q->cp1 * sin(A12))); + Q->sa = sin(pp); + Q->lp = adjlon ( atan2 (Q->cp1 * cos(A12), Q->sp1) - Q->hz0); + Q->dlam2 *= .5; + Q->lamc = M_HALFPI - atan2(sin(A12) * Q->sp1, cos(A12)) - Q->dlam2; + Q->thz0 = tan (Q->hz0); + Q->rhshz0 = .5 / sin (Q->hz0); + Q->r2z0 = 0.5 / Q->z02; + Q->z02 *= Q->z02; + + P->inv = s_inverse; + P->fwd = s_forward; + P->es = 0.; + + return P; +} + diff --git a/src/projections/urm5.cpp b/src/projections/urm5.cpp new file mode 100644 index 00000000..0e3c7e3c --- /dev/null +++ b/src/projections/urm5.cpp @@ -0,0 +1,56 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(urm5, "Urmaev V") "\n\tPCyl, Sph, no inv\n\tn= q= alpha="; + +namespace { // anonymous namespace +struct pj_opaque { + double m, rmn, q3, n; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double t; + + t = lp.phi = aasin (P->ctx, Q->n * sin (lp.phi)); + xy.x = Q->m * lp.lam * cos (lp.phi); + t *= t; + xy.y = lp.phi * (1. + t * Q->q3) * Q->rmn; + return xy; +} + + +PJ *PROJECTION(urm5) { + double alpha, t; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + if (pj_param(P->ctx, P->params, "tn").i) { + Q->n = pj_param(P->ctx, P->params, "dn").f; + if (Q->n <= 0. || Q->n > 1.) + return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); + } else { + return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); + } + Q->q3 = pj_param(P->ctx, P->params, "dq").f / 3.; + alpha = pj_param(P->ctx, P->params, "ralpha").f; + t = Q->n * sin (alpha); + Q->m = cos (alpha) / sqrt (1. - t * t); + Q->rmn = 1. / (Q->m * Q->n); + + P->es = 0.; + P->inv = nullptr; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/urmfps.cpp b/src/projections/urmfps.cpp new file mode 100644 index 00000000..7103222a --- /dev/null +++ b/src/projections/urmfps.cpp @@ -0,0 +1,76 @@ +#define PJ_LIB__ + +#include +#include + +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(urmfps, "Urmaev Flat-Polar Sinusoidal") "\n\tPCyl, Sph\n\tn="; +PROJ_HEAD(wag1, "Wagner I (Kavraisky VI)") "\n\tPCyl, Sph"; + +namespace { // anonymous namespace +struct pj_opaque { + double n, C_y; +}; +} // anonymous namespace + +#define C_x 0.8773826753 +#define Cy 1.139753528477 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + lp.phi = aasin (P->ctx,static_cast(P->opaque)->n * sin (lp.phi)); + xy.x = C_x * lp.lam * cos (lp.phi); + xy.y = static_cast(P->opaque)->C_y * lp.phi; + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0, 0.0}; + xy.y /= static_cast(P->opaque)->C_y; + lp.phi = aasin(P->ctx, sin (xy.y) / static_cast(P->opaque)->n); + lp.lam = xy.x / (C_x * cos (xy.y)); + return lp; +} + + +static PJ *setup(PJ *P) { + static_cast(P->opaque)->C_y = Cy / static_cast(P->opaque)->n; + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + return P; +} + + +PJ *PROJECTION(urmfps) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + + P->opaque = Q; + + if (pj_param(P->ctx, P->params, "tn").i) { + static_cast(P->opaque)->n = pj_param(P->ctx, P->params, "dn").f; + if (static_cast(P->opaque)->n <= 0. || static_cast(P->opaque)->n > 1.) + return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); + } else { + return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); + } + + return setup(P); +} + + +PJ *PROJECTION(wag1) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + static_cast(P->opaque)->n = 0.8660254037844386467637231707; + return setup(P); +} diff --git a/src/projections/vandg.cpp b/src/projections/vandg.cpp new file mode 100644 index 00000000..d148e210 --- /dev/null +++ b/src/projections/vandg.cpp @@ -0,0 +1,106 @@ +#define PJ_LIB__ +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(vandg, "van der Grinten (I)") "\n\tMisc Sph"; + +# define TOL 1.e-10 +# define THIRD .33333333333333333333 +# define C2_27 .07407407407407407407 +# define PI4_3 4.18879020478639098458 +# define PISQ 9.86960440108935861869 +# define TPISQ 19.73920880217871723738 +# define HPISQ 4.93480220054467930934 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double al, al2, g, g2, p2; + + p2 = fabs(lp.phi / M_HALFPI); + if ((p2 - TOL) > 1.) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + if (p2 > 1.) + p2 = 1.; + if (fabs(lp.phi) <= TOL) { + xy.x = lp.lam; + xy.y = 0.; + } else if (fabs(lp.lam) <= TOL || fabs(p2 - 1.) < TOL) { + xy.x = 0.; + xy.y = M_PI * tan(.5 * asin(p2)); + if (lp.phi < 0.) xy.y = -xy.y; + } else { + al = .5 * fabs(M_PI / lp.lam - lp.lam / M_PI); + al2 = al * al; + g = sqrt(1. - p2 * p2); + g = g / (p2 + g - 1.); + g2 = g * g; + p2 = g * (2. / p2 - 1.); + p2 = p2 * p2; + xy.x = g - p2; g = p2 + al2; + xy.x = M_PI * (al * xy.x + sqrt(al2 * xy.x * xy.x - g * (g2 - p2))) / g; + if (lp.lam < 0.) xy.x = -xy.x; + xy.y = fabs(xy.x / M_PI); + xy.y = 1. - xy.y * (xy.y + 2. * al); + if (xy.y < -TOL) { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return xy; + } + if (xy.y < 0.) + xy.y = 0.; + else + xy.y = sqrt(xy.y) * (lp.phi < 0. ? -M_PI : M_PI); + } + + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + double t, c0, c1, c2, c3, al, r2, r, m, d, ay, x2, y2; + + x2 = xy.x * xy.x; + if ((ay = fabs(xy.y)) < TOL) { + lp.phi = 0.; + t = x2 * x2 + TPISQ * (x2 + HPISQ); + lp.lam = fabs(xy.x) <= TOL ? 0. : + .5 * (x2 - PISQ + sqrt(t)) / xy.x; + return (lp); + } + y2 = xy.y * xy.y; + r = x2 + y2; r2 = r * r; + c1 = - M_PI * ay * (r + PISQ); + c3 = r2 + M_TWOPI * (ay * r + M_PI * (y2 + M_PI * (ay + M_HALFPI))); + c2 = c1 + PISQ * (r - 3. * y2); + c0 = M_PI * ay; + c2 /= c3; + al = c1 / c3 - THIRD * c2 * c2; + m = 2. * sqrt(-THIRD * al); + d = C2_27 * c2 * c2 * c2 + (c0 * c0 - THIRD * c2 * c1) / c3; + if (((t = fabs(d = 3. * d / (al * m))) - TOL) <= 1.) { + d = t > 1. ? (d > 0. ? 0. : M_PI) : acos(d); + lp.phi = M_PI * (m * cos(d * THIRD + PI4_3) - THIRD * c2); + if (xy.y < 0.) lp.phi = -lp.phi; + t = r2 + TPISQ * (x2 - y2 + HPISQ); + lp.lam = fabs(xy.x) <= TOL ? 0. : + .5 * (r - PISQ + (t <= 0. ? 0. : sqrt(t))) / xy.x; + } else { + proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); + return lp; + } + + return lp; +} + + +PJ *PROJECTION(vandg) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} + diff --git a/src/projections/vandg2.cpp b/src/projections/vandg2.cpp new file mode 100644 index 00000000..61d50044 --- /dev/null +++ b/src/projections/vandg2.cpp @@ -0,0 +1,76 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +namespace { // anonymous namespace +struct pj_opaque { + int vdg3; +}; +} // anonymous namespace + +PROJ_HEAD(vandg2, "van der Grinten II") "\n\tMisc Sph, no inv"; +PROJ_HEAD(vandg3, "van der Grinten III") "\n\tMisc Sph, no inv"; + +#define TOL 1e-10 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + struct pj_opaque *Q = static_cast(P->opaque); + double x1, at, bt, ct; + + bt = fabs(M_TWO_D_PI * lp.phi); + if ((ct = 1. - bt * bt) < 0.) + ct = 0.; + else + ct = sqrt(ct); + if (fabs(lp.lam) < TOL) { + xy.x = 0.; + xy.y = M_PI * (lp.phi < 0. ? -bt : bt) / (1. + ct); + } else { + at = 0.5 * fabs(M_PI / lp.lam - lp.lam / M_PI); + if (Q->vdg3) { + x1 = bt / (1. + ct); + xy.x = M_PI * (sqrt(at * at + 1. - x1 * x1) - at); + xy.y = M_PI * x1; + } else { + x1 = (ct * sqrt(1. + at * at) - at * ct * ct) / + (1. + at * at * bt * bt); + xy.x = M_PI * x1; + xy.y = M_PI * sqrt(1. - x1 * (x1 + 2. * at) + TOL); + } + if ( lp.lam < 0.) xy.x = -xy.x; + if ( lp.phi < 0.) xy.y = -xy.y; + } + + return xy; +} + + +PJ *PROJECTION(vandg2) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->vdg3 = 0; + P->fwd = s_forward; + + return P; +} + +PJ *PROJECTION(vandg3) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + + Q->vdg3 = 1; + P->es = 0.; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/vandg4.cpp b/src/projections/vandg4.cpp new file mode 100644 index 00000000..d9a53c87 --- /dev/null +++ b/src/projections/vandg4.cpp @@ -0,0 +1,55 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(vandg4, "van der Grinten IV") "\n\tMisc Sph, no inv"; + +#define TOL 1e-10 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + double x1, t, bt, ct, ft, bt2, ct2, dt, dt2; + (void) P; + + if (fabs(lp.phi) < TOL) { + xy.x = lp.lam; + xy.y = 0.; + } else if (fabs(lp.lam) < TOL || fabs(fabs(lp.phi) - M_HALFPI) < TOL) { + xy.x = 0.; + xy.y = lp.phi; + } else { + bt = fabs(M_TWO_D_PI * lp.phi); + bt2 = bt * bt; + ct = 0.5 * (bt * (8. - bt * (2. + bt2)) - 5.) + / (bt2 * (bt - 1.)); + ct2 = ct * ct; + dt = M_TWO_D_PI * lp.lam; + dt = dt + 1. / dt; + dt = sqrt(dt * dt - 4.); + if ((fabs(lp.lam) - M_HALFPI) < 0.) dt = -dt; + dt2 = dt * dt; + x1 = bt + ct; x1 *= x1; + t = bt + 3.*ct; + ft = x1 * (bt2 + ct2 * dt2 - 1.) + (1.-bt2) * ( + bt2 * (t * t + 4. * ct2) + + ct2 * (12. * bt * ct + 4. * ct2) ); + x1 = (dt*(x1 + ct2 - 1.) + 2.*sqrt(ft)) / + (4.* x1 + dt2); + xy.x = M_HALFPI * x1; + xy.y = M_HALFPI * sqrt(1. + dt * fabs(x1) - x1 * x1); + if (lp.lam < 0.) xy.x = -xy.x; + if (lp.phi < 0.) xy.y = -xy.y; + } + return xy; +} + + +PJ *PROJECTION(vandg4) { + P->es = 0.; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/wag2.cpp b/src/projections/wag2.cpp new file mode 100644 index 00000000..1bee737a --- /dev/null +++ b/src/projections/wag2.cpp @@ -0,0 +1,38 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(wag2, "Wagner II") "\n\tPCyl, Sph"; + +#define C_x 0.92483 +#define C_y 1.38725 +#define C_p1 0.88022 +#define C_p2 0.88550 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + lp.phi = aasin (P->ctx,C_p1 * sin (C_p2 * lp.phi)); + xy.x = C_x * lp.lam * cos (lp.phi); + xy.y = C_y * lp.phi; + return (xy); +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + lp.phi = xy.y / C_y; + lp.lam = xy.x / (C_x * cos(lp.phi)); + lp.phi = aasin (P->ctx,sin(lp.phi) / C_p1) / C_p2; + return (lp); +} + + +PJ *PROJECTION(wag2) { + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + return P; +} diff --git a/src/projections/wag3.cpp b/src/projections/wag3.cpp new file mode 100644 index 00000000..bb1b4d49 --- /dev/null +++ b/src/projections/wag3.cpp @@ -0,0 +1,50 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(wag3, "Wagner III") "\n\tPCyl, Sph\n\tlat_ts="; + +#define TWOTHIRD 0.6666666666666666666667 + +namespace { // anonymous namespace +struct pj_opaque { + double C_x; +}; +} // anonymous namespace + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + xy.x = static_cast(P->opaque)->C_x * lp.lam * cos(TWOTHIRD * lp.phi); + xy.y = lp.phi; + return xy; +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + lp.phi = xy.y; + lp.lam = xy.x / (static_cast(P->opaque)->C_x * cos(TWOTHIRD * lp.phi)); + return lp; +} + + +PJ *PROJECTION(wag3) { + double ts; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + + P->opaque = Q; + + ts = pj_param (P->ctx, P->params, "rlat_ts").f; + static_cast(P->opaque)->C_x = cos (ts) / cos (2.*ts/3.); + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/wag7.cpp b/src/projections/wag7.cpp new file mode 100644 index 00000000..c8807f12 --- /dev/null +++ b/src/projections/wag7.cpp @@ -0,0 +1,30 @@ +#define PJ_LIB__ + +#include + +#include "projects.h" + +PROJ_HEAD(wag7, "Wagner VII") "\n\tMisc Sph, no inv"; + + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + double theta, ct, D; + + (void) P; /* Shut up compiler warnnings about unused P */ + + theta = asin (xy.y = 0.90630778703664996 * sin(lp.phi)); + xy.x = 2.66723 * (ct = cos (theta)) * sin (lp.lam /= 3.); + xy.y *= 1.24104 * (D = 1/(sqrt (0.5 * (1 + ct * cos (lp.lam))))); + xy.x *= D; + return (xy); +} + + +PJ *PROJECTION(wag7) { + P->fwd = s_forward; + P->inv = nullptr; + P->es = 0.; + return P; +} diff --git a/src/projections/wink1.cpp b/src/projections/wink1.cpp new file mode 100644 index 00000000..de2f55ee --- /dev/null +++ b/src/projections/wink1.cpp @@ -0,0 +1,46 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(wink1, "Winkel I") "\n\tPCyl, Sph\n\tlat_ts="; + +namespace { // anonymous namespace +struct pj_opaque { + double cosphi1; +}; +} // anonymous namespace + + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0,0.0}; + xy.x = .5 * lp.lam * (static_cast(P->opaque)->cosphi1 + cos(lp.phi)); + xy.y = lp.phi; + return (xy); +} + + +static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ + LP lp = {0.0,0.0}; + lp.phi = xy.y; + lp.lam = 2. * xy.x / (static_cast(P->opaque)->cosphi1 + cos(lp.phi)); + return (lp); +} + + +PJ *PROJECTION(wink1) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + static_cast(P->opaque)->cosphi1 = cos (pj_param(P->ctx, P->params, "rlat_ts").f); + P->es = 0.; + P->inv = s_inverse; + P->fwd = s_forward; + + return P; +} diff --git a/src/projections/wink2.cpp b/src/projections/wink2.cpp new file mode 100644 index 00000000..74a47283 --- /dev/null +++ b/src/projections/wink2.cpp @@ -0,0 +1,56 @@ +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +PROJ_HEAD(wink2, "Winkel II") "\n\tPCyl, Sph, no inv\n\tlat_1="; + +namespace { // anonymous namespace +struct pj_opaque { + double cosphi1; +}; +} // anonymous namespace + +#define MAX_ITER 10 +#define LOOP_TOL 1e-7 + + +static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ + XY xy = {0.0, 0.0}; + double k, V; + int i; + + xy.y = lp.phi * M_TWO_D_PI; + k = M_PI * sin (lp.phi); + lp.phi *= 1.8; + for (i = MAX_ITER; i ; --i) { + lp.phi -= V = (lp.phi + sin (lp.phi) - k) / + (1. + cos (lp.phi)); + if (fabs (V) < LOOP_TOL) + break; + } + if (!i) + lp.phi = (lp.phi < 0.) ? -M_HALFPI : M_HALFPI; + else + lp.phi *= 0.5; + xy.x = 0.5 * lp.lam * (cos (lp.phi) + static_cast(P->opaque)->cosphi1); + xy.y = M_FORTPI * (sin (lp.phi) + xy.y); + return xy; +} + + +PJ *PROJECTION(wink2) { + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; + + static_cast(P->opaque)->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f); + P->es = 0.; + P->inv = nullptr; + P->fwd = s_forward; + + return P; +} -- cgit v1.2.3