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 --- scripts/cppcheck.sh | 2 +- src/4D_api.cpp | 1285 +++++++++++++ src/Makefile.am | 296 +-- src/PJ_pipeline.cpp | 503 ----- src/apply_gridshift.cpp | 356 ++++ src/apply_vgridshift.cpp | 331 ++++ src/auth.cpp | 36 + src/conversions/PJ_axisswap.cpp | 302 --- src/conversions/PJ_cart.cpp | 219 --- src/conversions/PJ_geoc.cpp | 59 - src/conversions/PJ_unitconvert.cpp | 552 ------ src/conversions/axisswap.cpp | 302 +++ src/conversions/cart.cpp | 219 +++ src/conversions/geoc.cpp | 59 + src/conversions/geocent.cpp | 62 + src/conversions/pj_geocent.cpp | 62 - src/conversions/unitconvert.cpp | 552 ++++++ src/ctx.cpp | 233 +++ src/datum_set.cpp | 169 ++ src/datums.cpp | 99 + src/deriv.cpp | 70 + src/ell_set.cpp | 727 ++++++++ src/ellps.cpp | 62 + src/errno.cpp | 17 + src/factors.cpp | 107 ++ src/fileapi.cpp | 213 +++ src/fwd.cpp | 261 +++ src/gauss.cpp | 103 ++ src/gc_reader.cpp | 247 +++ src/gridcatalog.cpp | 295 +++ src/gridinfo.cpp | 991 ++++++++++ src/gridlist.cpp | 219 +++ src/init.cpp | 888 +++++++++ src/initcache.cpp | 184 ++ src/internal.cpp | 445 +++++ src/inv.cpp | 238 +++ src/iso19111/io.cpp | 4 +- src/lib_proj.cmake | 282 +-- src/list.cpp | 32 + src/log.cpp | 98 + src/malloc.cpp | 240 +++ src/math.cpp | 108 ++ src/mlfn.cpp | 64 + src/msfn.cpp | 7 + src/mutex.cpp | 270 +++ src/open_lib.cpp | 247 +++ src/param.cpp | 189 ++ src/phi2.cpp | 46 + src/pipeline.cpp | 503 +++++ src/pj_apply_gridshift.cpp | 356 ---- src/pj_apply_vgridshift.cpp | 331 ---- src/pj_auth.cpp | 36 - src/pj_ctx.cpp | 233 --- src/pj_datum_set.cpp | 169 -- src/pj_datums.cpp | 99 - src/pj_deriv.cpp | 70 - src/pj_ell_set.cpp | 727 -------- src/pj_ellps.cpp | 62 - src/pj_errno.cpp | 17 - src/pj_factors.cpp | 107 -- src/pj_fileapi.cpp | 213 --- src/pj_fwd.cpp | 261 --- src/pj_gauss.cpp | 103 -- src/pj_gc_reader.cpp | 247 --- src/pj_gridcatalog.cpp | 295 --- src/pj_gridinfo.cpp | 991 ---------- src/pj_gridlist.cpp | 219 --- src/pj_init.cpp | 888 --------- src/pj_initcache.cpp | 184 -- src/pj_internal.cpp | 445 ----- src/pj_inv.cpp | 238 --- src/pj_list.cpp | 32 - src/pj_log.cpp | 98 - src/pj_malloc.cpp | 240 --- src/pj_math.cpp | 108 -- src/pj_mlfn.cpp | 64 - src/pj_msfn.cpp | 7 - src/pj_mutex.cpp | 270 --- src/pj_open_lib.cpp | 247 --- src/pj_param.cpp | 189 -- src/pj_phi2.cpp | 46 - src/pj_pr_list.cpp | 104 -- src/pj_qsfn.cpp | 22 - src/pj_release.cpp | 18 - src/pj_strerrno.cpp | 109 -- src/pj_strtod.cpp | 195 -- src/pj_transform.cpp | 1047 ----------- src/pj_tsfn.cpp | 16 - src/pj_units.cpp | 58 - src/pj_utils.cpp | 181 -- src/pj_wkt1_generated_parser.c | 1664 ----------------- src/pj_wkt1_generated_parser.h | 89 - src/pj_wkt1_grammar.y | 301 --- src/pj_wkt1_parser.cpp | 193 -- src/pj_wkt1_parser.h | 54 - src/pj_wkt2_generated_parser.c | 3140 -------------------------------- src/pj_wkt2_generated_parser.h | 208 --- src/pj_wkt2_grammar.y | 1499 --------------- src/pj_wkt2_parser.cpp | 221 --- src/pj_wkt2_parser.h | 54 - src/pj_wkt_parser.cpp | 60 - src/pj_wkt_parser.hpp | 50 - src/pj_zpoly1.cpp | 46 - src/pr_list.cpp | 104 ++ src/proj_4D_api.cpp | 1285 ------------- 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 + src/qsfn.cpp | 22 + src/release.cpp | 18 + src/strerrno.cpp | 109 ++ src/strtod.cpp | 195 ++ src/transform.cpp | 1047 +++++++++++ src/transformations/PJ_affine.cpp | 250 --- src/transformations/PJ_deformation.cpp | 325 ---- src/transformations/PJ_helmert.cpp | 755 -------- src/transformations/PJ_hgridshift.cpp | 133 -- src/transformations/PJ_horner.cpp | 513 ------ src/transformations/PJ_molodensky.cpp | 329 ---- src/transformations/PJ_vgridshift.cpp | 144 -- src/transformations/affine.cpp | 250 +++ src/transformations/deformation.cpp | 325 ++++ src/transformations/helmert.cpp | 755 ++++++++ src/transformations/hgridshift.cpp | 133 ++ src/transformations/horner.cpp | 513 ++++++ src/transformations/molodensky.cpp | 329 ++++ src/transformations/vgridshift.cpp | 144 ++ src/tsfn.cpp | 16 + src/units.cpp | 58 + src/utils.cpp | 181 ++ src/wkt1_generated_parser.c | 1664 +++++++++++++++++ src/wkt1_generated_parser.h | 89 + src/wkt1_grammar.y | 301 +++ src/wkt1_parser.cpp | 193 ++ src/wkt1_parser.h | 54 + src/wkt2_generated_parser.c | 3140 ++++++++++++++++++++++++++++++++ src/wkt2_generated_parser.h | 208 +++ src/wkt2_grammar.y | 1499 +++++++++++++++ src/wkt2_parser.cpp | 221 +++ src/wkt2_parser.h | 54 + src/wkt_parser.cpp | 60 + src/wkt_parser.hpp | 50 + src/zpoly1.cpp | 46 + 356 files changed, 36926 insertions(+), 36926 deletions(-) create mode 100644 src/4D_api.cpp delete mode 100644 src/PJ_pipeline.cpp create mode 100644 src/apply_gridshift.cpp create mode 100644 src/apply_vgridshift.cpp create mode 100644 src/auth.cpp delete mode 100644 src/conversions/PJ_axisswap.cpp delete mode 100644 src/conversions/PJ_cart.cpp delete mode 100644 src/conversions/PJ_geoc.cpp delete mode 100644 src/conversions/PJ_unitconvert.cpp create mode 100644 src/conversions/axisswap.cpp create mode 100644 src/conversions/cart.cpp create mode 100644 src/conversions/geoc.cpp create mode 100644 src/conversions/geocent.cpp delete mode 100644 src/conversions/pj_geocent.cpp create mode 100644 src/conversions/unitconvert.cpp create mode 100644 src/ctx.cpp create mode 100644 src/datum_set.cpp create mode 100644 src/datums.cpp create mode 100644 src/deriv.cpp create mode 100644 src/ell_set.cpp create mode 100644 src/ellps.cpp create mode 100644 src/errno.cpp create mode 100644 src/factors.cpp create mode 100644 src/fileapi.cpp create mode 100644 src/fwd.cpp create mode 100644 src/gauss.cpp create mode 100644 src/gc_reader.cpp create mode 100644 src/gridcatalog.cpp create mode 100644 src/gridinfo.cpp create mode 100644 src/gridlist.cpp create mode 100644 src/init.cpp create mode 100644 src/initcache.cpp create mode 100644 src/internal.cpp create mode 100644 src/inv.cpp create mode 100644 src/list.cpp create mode 100644 src/log.cpp create mode 100644 src/malloc.cpp create mode 100644 src/math.cpp create mode 100644 src/mlfn.cpp create mode 100644 src/msfn.cpp create mode 100644 src/mutex.cpp create mode 100644 src/open_lib.cpp create mode 100644 src/param.cpp create mode 100644 src/phi2.cpp create mode 100644 src/pipeline.cpp delete mode 100644 src/pj_apply_gridshift.cpp delete mode 100644 src/pj_apply_vgridshift.cpp delete mode 100644 src/pj_auth.cpp delete mode 100644 src/pj_ctx.cpp delete mode 100644 src/pj_datum_set.cpp delete mode 100644 src/pj_datums.cpp delete mode 100644 src/pj_deriv.cpp delete mode 100644 src/pj_ell_set.cpp delete mode 100644 src/pj_ellps.cpp delete mode 100644 src/pj_errno.cpp delete mode 100644 src/pj_factors.cpp delete mode 100644 src/pj_fileapi.cpp delete mode 100644 src/pj_fwd.cpp delete mode 100644 src/pj_gauss.cpp delete mode 100644 src/pj_gc_reader.cpp delete mode 100644 src/pj_gridcatalog.cpp delete mode 100644 src/pj_gridinfo.cpp delete mode 100644 src/pj_gridlist.cpp delete mode 100644 src/pj_init.cpp delete mode 100644 src/pj_initcache.cpp delete mode 100644 src/pj_internal.cpp delete mode 100644 src/pj_inv.cpp delete mode 100644 src/pj_list.cpp delete mode 100644 src/pj_log.cpp delete mode 100644 src/pj_malloc.cpp delete mode 100644 src/pj_math.cpp delete mode 100644 src/pj_mlfn.cpp delete mode 100644 src/pj_msfn.cpp delete mode 100644 src/pj_mutex.cpp delete mode 100644 src/pj_open_lib.cpp delete mode 100644 src/pj_param.cpp delete mode 100644 src/pj_phi2.cpp delete mode 100644 src/pj_pr_list.cpp delete mode 100644 src/pj_qsfn.cpp delete mode 100644 src/pj_release.cpp delete mode 100644 src/pj_strerrno.cpp delete mode 100644 src/pj_strtod.cpp delete mode 100644 src/pj_transform.cpp delete mode 100644 src/pj_tsfn.cpp delete mode 100644 src/pj_units.cpp delete mode 100644 src/pj_utils.cpp delete mode 100644 src/pj_wkt1_generated_parser.c delete mode 100644 src/pj_wkt1_generated_parser.h delete mode 100644 src/pj_wkt1_grammar.y delete mode 100644 src/pj_wkt1_parser.cpp delete mode 100644 src/pj_wkt1_parser.h delete mode 100644 src/pj_wkt2_generated_parser.c delete mode 100644 src/pj_wkt2_generated_parser.h delete mode 100644 src/pj_wkt2_grammar.y delete mode 100644 src/pj_wkt2_parser.cpp delete mode 100644 src/pj_wkt2_parser.h delete mode 100644 src/pj_wkt_parser.cpp delete mode 100644 src/pj_wkt_parser.hpp delete mode 100644 src/pj_zpoly1.cpp create mode 100644 src/pr_list.cpp delete mode 100644 src/proj_4D_api.cpp 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 create mode 100644 src/qsfn.cpp create mode 100644 src/release.cpp create mode 100644 src/strerrno.cpp create mode 100644 src/strtod.cpp create mode 100644 src/transform.cpp delete mode 100644 src/transformations/PJ_affine.cpp delete mode 100644 src/transformations/PJ_deformation.cpp delete mode 100644 src/transformations/PJ_helmert.cpp delete mode 100644 src/transformations/PJ_hgridshift.cpp delete mode 100644 src/transformations/PJ_horner.cpp delete mode 100644 src/transformations/PJ_molodensky.cpp delete mode 100644 src/transformations/PJ_vgridshift.cpp create mode 100644 src/transformations/affine.cpp create mode 100644 src/transformations/deformation.cpp create mode 100644 src/transformations/helmert.cpp create mode 100644 src/transformations/hgridshift.cpp create mode 100644 src/transformations/horner.cpp create mode 100644 src/transformations/molodensky.cpp create mode 100644 src/transformations/vgridshift.cpp create mode 100644 src/tsfn.cpp create mode 100644 src/units.cpp create mode 100644 src/utils.cpp create mode 100644 src/wkt1_generated_parser.c create mode 100644 src/wkt1_generated_parser.h create mode 100644 src/wkt1_grammar.y create mode 100644 src/wkt1_parser.cpp create mode 100644 src/wkt1_parser.h create mode 100644 src/wkt2_generated_parser.c create mode 100644 src/wkt2_generated_parser.h create mode 100644 src/wkt2_grammar.y create mode 100644 src/wkt2_parser.cpp create mode 100644 src/wkt2_parser.h create mode 100644 src/wkt_parser.cpp create mode 100644 src/wkt_parser.hpp create mode 100644 src/zpoly1.cpp diff --git a/scripts/cppcheck.sh b/scripts/cppcheck.sh index b0f8598a..f21c74e7 100755 --- a/scripts/cppcheck.sh +++ b/scripts/cppcheck.sh @@ -34,7 +34,7 @@ done ret_code=0 -grep -v "unmatchedSuppression" ${LOG_FILE} | grep -v "nn.hpp" | grep -v "pj_wkt1_generated_parser" | grep -v "pj_wkt2_generated_parser" > ${LOG_FILE}.tmp +grep -v "unmatchedSuppression" ${LOG_FILE} | grep -v "nn.hpp" | grep -v "wkt1_generated_parser" | grep -v "wkt2_generated_parser" > ${LOG_FILE}.tmp mv ${LOG_FILE}.tmp ${LOG_FILE} if grep "null pointer" ${LOG_FILE} ; then diff --git a/src/4D_api.cpp b/src/4D_api.cpp new file mode 100644 index 00000000..88210348 --- /dev/null +++ b/src/4D_api.cpp @@ -0,0 +1,1285 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implement a (currently minimalistic) proj API based primarily + * on the PJ_COORD 4D geodetic spatiotemporal data type. + * + * Author: Thomas Knudsen, thokn@sdfe.dk, 2016-06-09/2016-11-06 + * + ****************************************************************************** + * Copyright (c) 2016, 2017 Thomas Knudsen/SDFE + * + * 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. + *****************************************************************************/ + +#include +#include +#include +#include +#include +#ifndef _MSC_VER +#include +#endif + +#include "proj.h" +#include "proj_internal.h" +#include "proj_math.h" +#include "projects.h" +#include "geodesic.h" + + +/* Initialize PJ_COORD struct */ +PJ_COORD proj_coord (double x, double y, double z, double t) { + PJ_COORD res; + res.v[0] = x; + res.v[1] = y; + res.v[2] = z; + res.v[3] = t; + return res; +} + +static PJ_DIRECTION opposite_direction(PJ_DIRECTION dir) { + return static_cast(-dir); +} + +/*****************************************************************************/ +int proj_angular_input (PJ *P, enum PJ_DIRECTION dir) { +/****************************************************************************** + Returns 1 if the operator P expects angular input coordinates when + operating in direction dir, 0 otherwise. + dir: {PJ_FWD, PJ_INV} +******************************************************************************/ + if (PJ_FWD==dir) + return pj_left (P)==PJ_IO_UNITS_ANGULAR; + return pj_right (P)==PJ_IO_UNITS_ANGULAR; +} + +/*****************************************************************************/ +int proj_angular_output (PJ *P, enum PJ_DIRECTION dir) { +/****************************************************************************** + Returns 1 if the operator P provides angular output coordinates when + operating in direction dir, 0 otherwise. + dir: {PJ_FWD, PJ_INV} +******************************************************************************/ + return proj_angular_input (P, opposite_direction(dir)); +} + + +/* Geodesic distance (in meter) + fwd and rev azimuth between two points on the ellipsoid */ +PJ_COORD proj_geod (const PJ *P, PJ_COORD a, PJ_COORD b) { + PJ_COORD c; + /* Note: the geodesic code takes arguments in degrees */ + geod_inverse (P->geod, + PJ_TODEG(a.lpz.phi), PJ_TODEG(a.lpz.lam), + PJ_TODEG(b.lpz.phi), PJ_TODEG(b.lpz.lam), + c.v, c.v+1, c.v+2 + ); + + return c; +} + + +/* Geodesic distance (in meter) between two points with angular 2D coordinates */ +double proj_lp_dist (const PJ *P, PJ_COORD a, PJ_COORD b) { + double s12, azi1, azi2; + /* Note: the geodesic code takes arguments in degrees */ + geod_inverse (P->geod, + PJ_TODEG(a.lpz.phi), PJ_TODEG(a.lpz.lam), + PJ_TODEG(b.lpz.phi), PJ_TODEG(b.lpz.lam), + &s12, &azi1, &azi2 + ); + return s12; +} + +/* The geodesic distance AND the vertical offset */ +double proj_lpz_dist (const PJ *P, PJ_COORD a, PJ_COORD b) { + if (HUGE_VAL==a.lpz.lam || HUGE_VAL==b.lpz.lam) + return HUGE_VAL; + return hypot (proj_lp_dist (P, a, b), a.lpz.z - b.lpz.z); +} + +/* Euclidean distance between two points with linear 2D coordinates */ +double proj_xy_dist (PJ_COORD a, PJ_COORD b) { + return hypot (a.xy.x - b.xy.x, a.xy.y - b.xy.y); +} + +/* Euclidean distance between two points with linear 3D coordinates */ +double proj_xyz_dist (PJ_COORD a, PJ_COORD b) { + return hypot (proj_xy_dist (a, b), a.xyz.z - b.xyz.z); +} + + + +/* Measure numerical deviation after n roundtrips fwd-inv (or inv-fwd) */ +double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_COORD *coord) { + int i; + PJ_COORD t, org; + + if (nullptr==P) + return HUGE_VAL; + + if (n < 1) { + proj_errno_set (P, EINVAL); + return HUGE_VAL; + } + + /* in the first half-step, we generate the output value */ + org = *coord; + *coord = proj_trans (P, direction, org); + t = *coord; + + /* now we take n-1 full steps in inverse direction: We are */ + /* out of phase due to the half step already taken */ + for (i = 0; i < n - 1; i++) + t = proj_trans (P, direction, proj_trans (P, opposite_direction(direction), t) ); + + /* finally, we take the last half-step */ + t = proj_trans (P, opposite_direction(direction), t); + + /* checking for angular *input* since we do a roundtrip, and end where we begin */ + if (proj_angular_input (P, direction)) + return proj_lpz_dist (P, org, t); + + return proj_xyz_dist (org, t); +} + + + +/**************************************************************************************/ +PJ_COORD proj_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coord) { +/*************************************************************************************** +Apply the transformation P to the coordinate coord, preferring the 4D interfaces if +available. + +See also pj_approx_2D_trans and pj_approx_3D_trans in pj_internal.c, which work +similarly, but prefers the 2D resp. 3D interfaces if available. +***************************************************************************************/ + if (nullptr==P) + return coord; + if (P->inverted) + direction = opposite_direction(direction); + + switch (direction) { + case PJ_FWD: + return pj_fwd4d (coord, P); + case PJ_INV: + return pj_inv4d (coord, P); + case PJ_IDENT: + return coord; + default: + break; + } + + proj_errno_set (P, EINVAL); + return proj_coord_error (); +} + + + +/*****************************************************************************/ +int proj_trans_array (PJ *P, PJ_DIRECTION direction, size_t n, PJ_COORD *coord) { +/****************************************************************************** + Batch transform an array of PJ_COORD. + + Returns 0 if all coordinates are transformed without error, otherwise + returns error number. +******************************************************************************/ + size_t i; + + for (i = 0; i < n; i++) { + coord[i] = proj_trans (P, direction, coord[i]); + if (proj_errno(P)) + return proj_errno (P); + } + + return 0; +} + + + +/*************************************************************************************/ +size_t proj_trans_generic ( + PJ *P, + PJ_DIRECTION direction, + double *x, size_t sx, size_t nx, + double *y, size_t sy, size_t ny, + double *z, size_t sz, size_t nz, + double *t, size_t st, size_t nt +) { +/************************************************************************************** + + Transform a series of coordinates, where the individual coordinate dimension + may be represented by an array that is either + + 1. fully populated + 2. a null pointer and/or a length of zero, which will be treated as a + fully populated array of zeroes + 3. of length one, i.e. a constant, which will be treated as a fully + populated array of that constant value + + The strides, sx, sy, sz, st, represent the step length, in bytes, between + consecutive elements of the corresponding array. This makes it possible for + proj_transform to handle transformation of a large class of application + specific data structures, without necessarily understanding the data structure + format, as in: + + typedef struct {double x, y; int quality_level; char surveyor_name[134];} XYQS; + XYQS survey[345]; + double height = 23.45; + PJ *P = {...}; + size_t stride = sizeof (XYQS); + ... + proj_transform ( + P, PJ_INV, sizeof(XYQS), + &(survey[0].x), stride, 345, (* We have 345 eastings *) + &(survey[0].y), stride, 345, (* ...and 345 northings. *) + &height, 1, (* The height is the constant 23.45 m *) + 0, 0 (* and the time is the constant 0.00 s *) + ); + + This is similar to the inner workings of the pj_transform function, but the + stride functionality has been generalized to work for any size of basic unit, + not just a fixed number of doubles. + + In most cases, the stride will be identical for x, y,z, and t, since they will + typically be either individual arrays (stride = sizeof(double)), or strided + views into an array of application specific data structures (stride = sizeof (...)). + + But in order to support cases where x, y, z, and t come from heterogeneous + sources, individual strides, sx, sy, sz, st, are used. + + Caveat: Since proj_transform does its work *in place*, this means that even the + supposedly constants (i.e. length 1 arrays) will return from the call in altered + state. Hence, remember to reinitialize between repeated calls. + + Return value: Number of transformations completed. + +**************************************************************************************/ + PJ_COORD coord = {{0,0,0,0}}; + size_t i, nmin; + double null_broadcast = 0; + + if (nullptr==P) + return 0; + + if (P->inverted) + direction = opposite_direction(direction); + + /* ignore lengths of null arrays */ + if (nullptr==x) nx = 0; + if (nullptr==y) ny = 0; + if (nullptr==z) nz = 0; + if (nullptr==t) nt = 0; + + /* and make the nullities point to some real world memory for broadcasting nulls */ + if (0==nx) x = &null_broadcast; + if (0==ny) y = &null_broadcast; + if (0==nz) z = &null_broadcast; + if (0==nt) t = &null_broadcast; + + /* nothing to do? */ + if (0==nx+ny+nz+nt) + return 0; + + /* arrays of length 1 are constants, which we broadcast along the longer arrays */ + /* so we need to find the length of the shortest non-unity array to figure out */ + /* how many coordinate pairs we must transform */ + nmin = (nx > 1)? nx: (ny > 1)? ny: (nz > 1)? nz: (nt > 1)? nt: 1; + if ((nx > 1) && (nx < nmin)) nmin = nx; + if ((ny > 1) && (ny < nmin)) nmin = ny; + if ((nz > 1) && (nz < nmin)) nmin = nz; + if ((nt > 1) && (nt < nmin)) nmin = nt; + + /* Check validity of direction flag */ + switch (direction) { + case PJ_FWD: + case PJ_INV: + break; + case PJ_IDENT: + return nmin; + default: + proj_errno_set (P, EINVAL); + return 0; + } + + /* Arrays of length==0 are broadcast as the constant 0 */ + /* Arrays of length==1 are broadcast as their single value */ + /* Arrays of length >1 are iterated over (for the first nmin values) */ + /* The slightly convolved incremental indexing is used due */ + /* to the stride, which may be any size supported by the platform */ + for (i = 0; i < nmin; i++) { + coord.xyzt.x = *x; + coord.xyzt.y = *y; + coord.xyzt.z = *z; + coord.xyzt.t = *t; + + if (PJ_FWD==direction) + coord = pj_fwd4d (coord, P); + else + coord = pj_inv4d (coord, P); + + /* in all full length cases, we overwrite the input with the output, */ + /* and step on to the next element. */ + /* The casts are somewhat funky, but they compile down to no-ops and */ + /* they tell compilers and static analyzers that we know what we do */ + if (nx > 1) { + *x = coord.xyzt.x; + x = (double *) ((void *) ( ((char *) x) + sx)); + } + if (ny > 1) { + *y = coord.xyzt.y; + y = (double *) ((void *) ( ((char *) y) + sy)); + } + if (nz > 1) { + *z = coord.xyzt.z; + z = (double *) ((void *) ( ((char *) z) + sz)); + } + if (nt > 1) { + *t = coord.xyzt.t; + t = (double *) ((void *) ( ((char *) t) + st)); + } + } + + /* Last time around, we update the length 1 cases with their transformed alter egos */ + if (nx==1) + *x = coord.xyzt.x; + if (ny==1) + *y = coord.xyzt.y; + if (nz==1) + *z = coord.xyzt.z; + if (nt==1) + *t = coord.xyzt.t; + + return i; +} + + +/*************************************************************************************/ +PJ_COORD pj_geocentric_latitude (const PJ *P, PJ_DIRECTION direction, PJ_COORD coord) { +/************************************************************************************** + Convert geographical latitude to geocentric (or the other way round if + direction = PJ_INV) + + The conversion involves a call to the tangent function, which goes through the + roof at the poles, so very close (the last centimeter) to the poles no + conversion takes place and the input latitude is copied directly to the output. + + Fortunately, the geocentric latitude converges to the geographical at the + poles, so the difference is negligible. + + For the spherical case, the geographical latitude equals the geocentric, and + consequently, the input is copied directly to the output. +**************************************************************************************/ + const double limit = M_HALFPI - 1e-9; + PJ_COORD res = coord; + if ((coord.lp.phi > limit) || (coord.lp.phi < -limit) || (P->es==0)) + return res; + if (direction==PJ_FWD) + res.lp.phi = atan (P->one_es * tan (coord.lp.phi) ); + else + res.lp.phi = atan (P->rone_es * tan (coord.lp.phi) ); + + return res; +} + +double proj_torad (double angle_in_degrees) { return PJ_TORAD (angle_in_degrees);} +double proj_todeg (double angle_in_radians) { return PJ_TODEG (angle_in_radians);} + +double proj_dmstor(const char *is, char **rs) { + return dmstor(is, rs); +} + +char* proj_rtodms(char *s, double r, int pos, int neg) { + return rtodms(s, r, pos, neg); +} + +/*************************************************************************************/ +static PJ* skip_prep_fin(PJ *P) { +/************************************************************************************** +Skip prepare and finalize function for the various "helper operations" added to P when +in cs2cs compatibility mode. +**************************************************************************************/ + P->skip_fwd_prepare = 1; + P->skip_fwd_finalize = 1; + P->skip_inv_prepare = 1; + P->skip_inv_finalize = 1; + return P; +} + +/*************************************************************************************/ +static int cs2cs_emulation_setup (PJ *P) { +/************************************************************************************** +If any cs2cs style modifiers are given (axis=..., towgs84=..., ) create the 4D API +equivalent operations, so the preparation and finalization steps in the pj_inv/pj_fwd +invocators can emulate the behaviour of pj_transform and the cs2cs app. + +Returns 1 on success, 0 on failure +**************************************************************************************/ + PJ *Q; + paralist *p; + int do_cart = 0; + if (nullptr==P) + return 0; + + /* Don't recurse when calling proj_create (which calls us back) */ + if (pj_param_exists (P->params, "break_cs2cs_recursion")) + return 1; + + /* Swap axes? */ + p = pj_param_exists (P->params, "axis"); + + /* Don't axisswap if data are already in "enu" order */ + if (p && (0!=strcmp ("enu", p->param))) { + char *def = static_cast(malloc (100+strlen(P->axis))); + if (nullptr==def) + return 0; + sprintf (def, "break_cs2cs_recursion proj=axisswap axis=%s", P->axis); + Q = proj_create (P->ctx, def); + free (def); + if (nullptr==Q) + return 0; + P->axisswap = skip_prep_fin(Q); + } + + /* Geoid grid(s) given? */ + p = pj_param_exists (P->params, "geoidgrids"); + if (p && strlen (p->param) > strlen ("geoidgrids=")) { + char *gridnames = p->param + strlen ("geoidgrids="); + char *def = static_cast(malloc (100+strlen(gridnames))); + if (nullptr==def) + return 0; + sprintf (def, "break_cs2cs_recursion proj=vgridshift grids=%s", gridnames); + Q = proj_create (P->ctx, def); + free (def); + if (nullptr==Q) + return 0; + P->vgridshift = skip_prep_fin(Q); + } + + /* Datum shift grid(s) given? */ + p = pj_param_exists (P->params, "nadgrids"); + if (p && strlen (p->param) > strlen ("nadgrids=")) { + char *gridnames = p->param + strlen ("nadgrids="); + char *def = static_cast(malloc (100+strlen(gridnames))); + if (nullptr==def) + return 0; + sprintf (def, "break_cs2cs_recursion proj=hgridshift grids=%s", gridnames); + Q = proj_create (P->ctx, def); + free (def); + if (nullptr==Q) + return 0; + P->hgridshift = skip_prep_fin(Q); + } + + /* We ignore helmert if we have grid shift */ + p = P->hgridshift ? nullptr : pj_param_exists (P->params, "towgs84"); + while (p) { + char *def; + char *s = p->param; + double *d = P->datum_params; + size_t n = strlen (s); + + /* We ignore null helmert shifts (common in auto-translated resource files, e.g. epsg) */ + if (0==d[0] && 0==d[1] && 0==d[2] && 0==d[3] && 0==d[4] && 0==d[5] && 0==d[6]) { + /* If the current ellipsoid is not WGS84, then make sure the */ + /* change in ellipsoid is still done. */ + if (!(fabs(P->a_orig - 6378137.0) < 1e-8 && fabs(P->es_orig - 0.0066943799901413) < 1e-15)) { + do_cart = 1; + } + break; + } + + if (n <= 8) /* 8==strlen ("towgs84=") */ + return 0; + + def = static_cast(malloc (100+n)); + if (nullptr==def) + return 0; + sprintf (def, "break_cs2cs_recursion proj=helmert exact %s convention=position_vector", s); + Q = proj_create (P->ctx, def); + free(def); + if (nullptr==Q) + return 0; + pj_inherit_ellipsoid_def (P, Q); + P->helmert = skip_prep_fin (Q); + + break; + } + + /* We also need cartesian/geographical transformations if we are working in */ + /* geocentric/cartesian space or we need to do a Helmert transform. */ + if (P->is_geocent || P->helmert || do_cart) { + char def[150]; + sprintf (def, "break_cs2cs_recursion proj=cart a=%40.20g es=%40.20g", P->a_orig, P->es_orig); + { + /* In case the current locale does not use dot but comma as decimal */ + /* separator, replace it with dot, so that proj_atof() behaves */ + /* correctly. */ + /* TODO later: use C++ ostringstream with imbue(std::locale::classic()) */ + /* to be locale unaware */ + char* next_pos; + for (next_pos = def; (next_pos = strchr (next_pos, ',')) != nullptr; next_pos++) { + *next_pos = '.'; + } + } + Q = proj_create (P->ctx, def); + if (nullptr==Q) + return 0; + P->cart = skip_prep_fin (Q); + + if (!P->is_geocent) { + sprintf (def, "break_cs2cs_recursion proj=cart ellps=WGS84"); + Q = proj_create (P->ctx, def); + if (nullptr==Q) + return 0; + P->cart_wgs84 = skip_prep_fin (Q); + } + } + + return 1; +} + + + +/*************************************************************************************/ +PJ *proj_create (PJ_CONTEXT *ctx, const char *definition) { +/************************************************************************************** + Create a new PJ object in the context ctx, using the given definition. If ctx==0, + the default context is used, if definition==0, or invalid, a null-pointer is + returned. The definition may use '+' as argument start indicator, as in + "+proj=utm +zone=32", or leave it out, as in "proj=utm zone=32". + + It may even use free formatting "proj = utm; zone =32 ellps= GRS80". + Note that the semicolon separator is allowed, but not required. +**************************************************************************************/ + PJ *P; + char *args, **argv; + size_t argc, n; + int ret; + int allow_init_epsg; + + if (nullptr==ctx) + ctx = pj_get_default_ctx (); + + /* Make a copy that we can manipulate */ + n = strlen (definition); + args = (char *) malloc (n + 1); + if (nullptr==args) { + proj_context_errno_set(ctx, ENOMEM); + return nullptr; + } + strcpy (args, definition); + + argc = pj_trim_argc (args); + if (argc==0) { + pj_dealloc (args); + proj_context_errno_set(ctx, PJD_ERR_NO_ARGS); + return nullptr; + } + + argv = pj_trim_argv (argc, args); + + /* ...and let pj_init_ctx do the hard work */ + /* New interface: forbid init=epsg:XXXX syntax by default */ + allow_init_epsg = proj_context_get_use_proj4_init_rules(ctx, FALSE); + P = pj_init_ctx_with_allow_init_epsg (ctx, (int) argc, argv, allow_init_epsg); + + pj_dealloc (argv); + pj_dealloc (args); + + /* Support cs2cs-style modifiers */ + ret = cs2cs_emulation_setup (P); + if (0==ret) + return proj_destroy (P); + + return P; +} + + + +/*************************************************************************************/ +PJ *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv) { +/************************************************************************************** +Create a new PJ object in the context ctx, using the given definition argument +array argv. If ctx==0, the default context is used, if definition==0, or invalid, +a null-pointer is returned. The definition arguments may use '+' as argument start +indicator, as in {"+proj=utm", "+zone=32"}, or leave it out, as in {"proj=utm", +"zone=32"}. +**************************************************************************************/ + PJ *P; + const char *c; + + if (nullptr==ctx) + ctx = pj_get_default_ctx (); + if (nullptr==argv) { + proj_context_errno_set(ctx, PJD_ERR_NO_ARGS); + return nullptr; + } + + /* We assume that free format is used, and build a full proj_create compatible string */ + c = pj_make_args (argc, argv); + if (nullptr==c) { + proj_context_errno_set(ctx, ENOMEM); + return nullptr; + } + + P = proj_create (ctx, c); + + pj_dealloc ((char *) c); + return P; +} + +/** Create an area of use */ +PJ_AREA * proj_area_create(void) { + return static_cast(pj_calloc(1, sizeof(PJ_AREA))); +} + +/** Assign a bounding box to an area of use. */ +void proj_area_set_bbox(PJ_AREA *area, + double west_lon_degree, + double south_lat_degree, + double east_lon_degree, + double north_lat_degree) { + area->bbox_set = TRUE; + area->west_lon_degree = west_lon_degree; + area->south_lat_degree = south_lat_degree; + area->east_lon_degree = east_lon_degree; + area->north_lat_degree = north_lat_degree; +} + +/** Free an area of use */ +void proj_area_destroy(PJ_AREA* area) { + pj_dealloc(area); +} + +/************************************************************************/ +/* proj_context_use_proj4_init_rules() */ +/************************************************************************/ + +void proj_context_use_proj4_init_rules(PJ_CONTEXT *ctx, int enable) { + if( ctx == nullptr ) { + ctx = pj_get_default_ctx(); + } + ctx->use_proj4_init_rules = enable; +} + +/************************************************************************/ +/* EQUAL() */ +/************************************************************************/ + +static int EQUAL(const char* a, const char* b) { +#ifdef _MSC_VER + return _stricmp(a, b) == 0; +#else + return strcasecmp(a, b) == 0; +#endif +} + +/************************************************************************/ +/* proj_context_get_use_proj4_init_rules() */ +/************************************************************************/ + +int proj_context_get_use_proj4_init_rules(PJ_CONTEXT *ctx, int from_legacy_code_path) { + const char* val = getenv("PROJ_USE_PROJ4_INIT_RULES"); + + if( ctx == nullptr ) { + ctx = pj_get_default_ctx(); + } + + if( val ) { + if( EQUAL(val, "yes") || EQUAL(val, "on") || EQUAL(val, "true") ) { + return TRUE; + } + if( EQUAL(val, "no") || EQUAL(val, "off") || EQUAL(val, "false") ) { + return FALSE; + } + pj_log(ctx, PJ_LOG_ERROR, "Invalid value for PROJ_USE_PROJ4_INIT_RULES"); + } + + if( ctx->use_proj4_init_rules >= 0 ) { + return ctx->use_proj4_init_rules; + } + return from_legacy_code_path; +} + + +/*****************************************************************************/ +PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char *target_crs, PJ_AREA *area) { +/****************************************************************************** + Create a transformation pipeline between two known coordinate reference + systems. + + source_crs and target_crs can be : + - a "AUTHORITY:CODE", like EPSG:25832. When using that syntax for a source + CRS, the created pipeline will expect that the values passed to proj_trans() + respect the axis order and axis unit of the official definition ( + so for example, for EPSG:4326, with latitude first and longitude next, + in degrees). Similarly, when using that syntax for a target CRS, output + values will be emitted according to the official definition of this CRS. + - a PROJ string, like "+proj=longlat +datum=WGS84". + When using that syntax, the axis order and unit for geographic CRS will + be longitude, latitude, and the unit degrees. + - more generally any string accepted by proj_obj_create_from_user_input() + + An "area of use" can be specified in area. When it is supplied, the more + accurate transformation between two given systems can be chosen. + + Example call: + + PJ *P = proj_create_crs_to_crs(0, "EPSG:25832", "EPSG:25833", NULL); + +******************************************************************************/ + PJ *P; + PJ_OBJ* src; + PJ_OBJ* dst; + PJ_OPERATION_FACTORY_CONTEXT* operation_ctx; + PJ_OBJ_LIST* op_list; + PJ_OBJ* op; + const char* proj_string; + const char* const optionsProj4Mode[] = { "USE_PROJ4_INIT_RULES=YES", nullptr }; + const char* const* optionsImportCRS = + proj_context_get_use_proj4_init_rules(ctx, FALSE) ? optionsProj4Mode : nullptr; + + src = proj_obj_create_from_user_input(ctx, source_crs, optionsImportCRS); + if( !src ) { + return nullptr; + } + + dst = proj_obj_create_from_user_input(ctx, target_crs, optionsImportCRS); + if( !dst ) { + proj_obj_destroy(src); + return nullptr; + } + + operation_ctx = proj_create_operation_factory_context(ctx, nullptr); + if( !operation_ctx ) { + proj_obj_destroy(src); + proj_obj_destroy(dst); + return nullptr; + } + + if( area && area->bbox_set ) { + proj_operation_factory_context_set_area_of_interest( + ctx, + operation_ctx, + area->west_lon_degree, + area->south_lat_degree, + area->east_lon_degree, + area->north_lat_degree); + } + + proj_operation_factory_context_set_grid_availability_use( + ctx, operation_ctx, PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID); + + op_list = proj_obj_create_operations(ctx, src, dst, operation_ctx); + + proj_operation_factory_context_destroy(operation_ctx); + proj_obj_destroy(src); + proj_obj_destroy(dst); + + if( !op_list ) { + return nullptr; + } + + if( proj_obj_list_get_count(op_list) == 0 ) { + proj_obj_list_destroy(op_list); + return nullptr; + } + + op = proj_obj_list_get(ctx, op_list, 0); + proj_obj_list_destroy(op_list); + if( !op ) { + return nullptr; + } + + proj_string = proj_obj_as_proj_string(ctx, op, PJ_PROJ_5, nullptr); + if( !proj_string) { + proj_obj_destroy(op); + return nullptr; + } + + if( proj_string[0] == '\0' ) { + /* Null transform ? */ + P = proj_create(ctx, "proj=affine"); + } else { + P = proj_create(ctx, proj_string); + } + + proj_obj_destroy(op); + + return P; +} + +PJ *proj_destroy (PJ *P) { + pj_free (P); + return nullptr; +} + +/*****************************************************************************/ +int proj_errno (const PJ *P) { +/****************************************************************************** + Read an error level from the context of a PJ. +******************************************************************************/ + return pj_ctx_get_errno (pj_get_ctx ((PJ *) P)); +} + +/*****************************************************************************/ +int proj_context_errno (PJ_CONTEXT *ctx) { +/****************************************************************************** + Read an error directly from a context, without going through a PJ + belonging to that context. +******************************************************************************/ + if (nullptr==ctx) + ctx = pj_get_default_ctx(); + return pj_ctx_get_errno (ctx); +} + +/*****************************************************************************/ +int proj_errno_set (const PJ *P, int err) { +/****************************************************************************** + Set context-errno, bubble it up to the thread local errno, return err +******************************************************************************/ + /* Use proj_errno_reset to explicitly clear the error status */ + if (0==err) + return 0; + + /* For P==0 err goes to the default context */ + proj_context_errno_set (pj_get_ctx ((PJ *) P), err); + errno = err; + return err; +} + +/*****************************************************************************/ +int proj_errno_restore (const PJ *P, int err) { +/****************************************************************************** + Use proj_errno_restore when the current function succeeds, but the + error flag was set on entry, and stored/reset using proj_errno_reset + in order to monitor for new errors. + + See usage example under proj_errno_reset () +******************************************************************************/ + if (0==err) + return 0; + proj_errno_set (P, err); + return 0; +} + +/*****************************************************************************/ +int proj_errno_reset (const PJ *P) { +/****************************************************************************** + Clears errno in the context and thread local levels + through the low level pj_ctx interface. + + Returns the previous value of the errno, for convenient reset/restore + operations: + + int foo (PJ *P) { + // errno may be set on entry, but we need to reset it to be able to + // check for errors from "do_something_with_P(P)" + int last_errno = proj_errno_reset (P); + + // local failure + if (0==P) + return proj_errno_set (P, 42); + + // call to function that may fail + do_something_with_P (P); + + // failure in do_something_with_P? - keep latest error status + if (proj_errno(P)) + return proj_errno (P); + + // success - restore previous error status, return 0 + return proj_errno_restore (P, last_errno); + } +******************************************************************************/ + int last_errno; + last_errno = proj_errno (P); + + pj_ctx_set_errno (pj_get_ctx ((PJ *) P), 0); + errno = 0; + pj_errno = 0; + return last_errno; +} + + +/* Create a new context */ +PJ_CONTEXT *proj_context_create (void) { + return pj_ctx_alloc (); +} + + +PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx) { + if (nullptr==ctx) + return nullptr; + + /* Trying to free the default context is a no-op (since it is statically allocated) */ + if (pj_get_default_ctx ()==ctx) + return nullptr; + + pj_ctx_free (ctx); + return nullptr; +} + + + + + + +/*****************************************************************************/ +static char *path_append (char *buf, const char *app, size_t *buf_size) { +/****************************************************************************** + Helper for proj_info() below. Append app to buf, separated by a + semicolon. Also handle allocation of longer buffer if needed. + + Returns buffer and adjusts *buf_size through provided pointer arg. +******************************************************************************/ + char *p; + size_t len, applen = 0, buflen = 0; +#ifdef _WIN32 + const char *delim = ";"; +#else + const char *delim = ":"; +#endif + + /* Nothing to do? */ + if (nullptr == app) + return buf; + applen = strlen (app); + if (0 == applen) + return buf; + + /* Start checking whether buf is long enough */ + if (nullptr != buf) + buflen = strlen (buf); + len = buflen+applen+strlen (delim) + 1; + + /* "pj_realloc", so to speak */ + if (*buf_size < len) { + p = static_cast(pj_calloc (2 * len, sizeof (char))); + if (nullptr==p) { + pj_dealloc (buf); + return nullptr; + } + *buf_size = 2 * len; + if (buf != nullptr) + strcpy (p, buf); + pj_dealloc (buf); + buf = p; + } + + /* Only append a semicolon if something's already there */ + if (0 != buflen) + strcat (buf, ";"); + strcat (buf, app); + return buf; +} + +static const char *empty = {""}; +static char version[64] = {""}; +static PJ_INFO info = {0, 0, 0, nullptr, nullptr, nullptr, nullptr, 0}; +static volatile int info_initialized = 0; + +/*****************************************************************************/ +PJ_INFO proj_info (void) { +/****************************************************************************** + Basic info about the current instance of the PROJ.4 library. + + Returns PJ_INFO struct. +******************************************************************************/ + const char * const *paths; + size_t i, n; + + size_t buf_size = 0; + char *buf = nullptr; + + pj_acquire_lock (); + + if (0!=info_initialized) { + pj_release_lock (); + return info; + } + + info.major = PROJ_VERSION_MAJOR; + info.minor = PROJ_VERSION_MINOR; + info.patch = PROJ_VERSION_PATCH; + + /* This is a controlled environment, so no risk of sprintf buffer + overflow. A normal version string is xx.yy.zz which is 8 characters + long and there is room for 64 bytes in the version string. */ + sprintf (version, "%d.%d.%d", info.major, info.minor, info.patch); + + info.searchpath = empty; + info.version = version; + info.release = pj_get_release (); + + /* build search path string */ + buf = path_append (buf, getenv ("HOME"), &buf_size); + buf = path_append (buf, getenv ("PROJ_LIB"), &buf_size); + + paths = proj_get_searchpath (); + n = (size_t) proj_get_path_count (); + + for (i = 0; i < n; i++) + buf = path_append (buf, paths[i], &buf_size); + info.searchpath = buf ? buf : empty; + + info.paths = paths; + info.path_count = n; + + info_initialized = 1; + pj_release_lock (); + return info; +} + + +/*****************************************************************************/ +PJ_PROJ_INFO proj_pj_info(PJ *P) { +/****************************************************************************** + Basic info about a particular instance of a projection object. + + Returns PJ_PROJ_INFO struct. +******************************************************************************/ + PJ_PROJ_INFO pjinfo; + char *def; + + memset(&pjinfo, 0, sizeof(PJ_PROJ_INFO)); + + /* Expected accuracy of the transformation. Hardcoded for now, will be improved */ + /* later. Most likely to be used when a transformation is set up with */ + /* proj_create_crs_to_crs in a future version that leverages the EPSG database. */ + pjinfo.accuracy = -1.0; + + if (nullptr==P) + return pjinfo; + + /* projection id */ + if (pj_param(P->ctx, P->params, "tproj").i) + pjinfo.id = pj_param(P->ctx, P->params, "sproj").s; + + /* projection description */ + pjinfo.description = P->descr; + + /* projection definition */ + if (P->def_full) + def = P->def_full; + else + def = pj_get_def(P, 0); /* pj_get_def takes a non-const PJ pointer */ + if (nullptr==def) + pjinfo.definition = empty; + else + pjinfo.definition = pj_shrink (def); + /* Make pj_free clean this up eventually */ + P->def_full = def; + + pjinfo.has_inverse = pj_has_inverse(P); + return pjinfo; +} + + +/*****************************************************************************/ +PJ_GRID_INFO proj_grid_info(const char *gridname) { +/****************************************************************************** + Information about a named datum grid. + + Returns PJ_GRID_INFO struct. +******************************************************************************/ + PJ_GRID_INFO grinfo; + + /*PJ_CONTEXT *ctx = proj_context_create(); */ + PJ_CONTEXT *ctx = pj_get_default_ctx(); + PJ_GRIDINFO *gridinfo = pj_gridinfo_init(ctx, gridname); + memset(&grinfo, 0, sizeof(PJ_GRID_INFO)); + + /* in case the grid wasn't found */ + if (gridinfo->filename == nullptr) { + pj_gridinfo_free(ctx, gridinfo); + strcpy(grinfo.format, "missing"); + return grinfo; + } + + /* The string copies below are automatically null-terminated due to */ + /* the memset above, so strncpy is safe */ + + /* name of grid */ + strncpy (grinfo.gridname, gridname, sizeof(grinfo.gridname) - 1); + + /* full path of grid */ + pj_find_file(ctx, gridname, grinfo.filename, sizeof(grinfo.filename) - 1); + + /* grid format */ + strncpy (grinfo.format, gridinfo->format, sizeof(grinfo.format) - 1); + + /* grid size */ + grinfo.n_lon = gridinfo->ct->lim.lam; + grinfo.n_lat = gridinfo->ct->lim.phi; + + /* cell size */ + grinfo.cs_lon = gridinfo->ct->del.lam; + grinfo.cs_lat = gridinfo->ct->del.phi; + + /* bounds of grid */ + grinfo.lowerleft = gridinfo->ct->ll; + grinfo.upperright.lam = grinfo.lowerleft.lam + grinfo.n_lon*grinfo.cs_lon; + grinfo.upperright.phi = grinfo.lowerleft.phi + grinfo.n_lat*grinfo.cs_lat; + + pj_gridinfo_free(ctx, gridinfo); + + return grinfo; +} + + + +/*****************************************************************************/ +PJ_INIT_INFO proj_init_info(const char *initname){ +/****************************************************************************** + Information about a named init file. + + Maximum length of initname is 64. + + Returns PJ_INIT_INFO struct. + + If the init file is not found all members of the return struct are set + to the empty string. + + If the init file is found, but the metadata is missing, the value is + set to "Unknown". +******************************************************************************/ + int file_found; + char param[80], key[74]; + paralist *start, *next; + PJ_INIT_INFO ininfo; + PJ_CONTEXT *ctx = pj_get_default_ctx(); + + memset(&ininfo, 0, sizeof(PJ_INIT_INFO)); + + file_found = pj_find_file(ctx, initname, ininfo.filename, sizeof(ininfo.filename)); + if (!file_found || strlen(initname) > 64) { + if( strcmp(initname, "epsg") == 0 || strcmp(initname, "EPSG") == 0 ) { + const char* val; + + pj_ctx_set_errno( ctx, 0 ); + + strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); + strcpy(ininfo.origin, "EPSG"); + val = proj_context_get_database_metadata(ctx, "EPSG.VERSION"); + if( val ) { + strncpy(ininfo.version, val, sizeof(ininfo.version) - 1); + } + val = proj_context_get_database_metadata(ctx, "EPSG.DATE"); + if( val ) { + strncpy(ininfo.lastupdate, val, sizeof(ininfo.lastupdate) - 1); + } + return ininfo; + } + + if( strcmp(initname, "IGNF") == 0 ) { + const char* val; + + pj_ctx_set_errno( ctx, 0 ); + + strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); + strcpy(ininfo.origin, "IGNF"); + val = proj_context_get_database_metadata(ctx, "IGNF.VERSION"); + if( val ) { + strncpy(ininfo.version, val, sizeof(ininfo.version) - 1); + } + val = proj_context_get_database_metadata(ctx, "IGNF.DATE"); + if( val ) { + strncpy(ininfo.lastupdate, val, sizeof(ininfo.lastupdate) - 1); + } + return ininfo; + } + + return ininfo; + } + + /* The initial memset (0) makes strncpy safe here */ + strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); + strcpy(ininfo.origin, "Unknown"); + strcpy(ininfo.version, "Unknown"); + strcpy(ininfo.lastupdate, "Unknown"); + + strncpy (key, initname, 64); /* make room for ":metadata\0" at the end */ + key[64] = 0; + memcpy(key + strlen(key), ":metadata", 9 + 1); + strcpy(param, "+init="); + /* The +strlen(param) avoids a cppcheck false positive warning */ + strncat(param + strlen(param), key, sizeof(param)-1-strlen(param)); + + start = pj_mkparam(param); + pj_expand_init(ctx, start); + + if (pj_param(ctx, start, "tversion").i) + strncpy(ininfo.version, pj_param(ctx, start, "sversion").s, sizeof(ininfo.version) - 1); + + if (pj_param(ctx, start, "torigin").i) + strncpy(ininfo.origin, pj_param(ctx, start, "sorigin").s, sizeof(ininfo.origin) - 1); + + if (pj_param(ctx, start, "tlastupdate").i) + strncpy(ininfo.lastupdate, pj_param(ctx, start, "slastupdate").s, sizeof(ininfo.lastupdate) - 1); + + for ( ; start; start = next) { + next = start->next; + pj_dalloc(start); + } + + return ininfo; +} + + + +/*****************************************************************************/ +PJ_FACTORS proj_factors(PJ *P, PJ_COORD lp) { +/****************************************************************************** + Cartographic characteristics at point lp. + + Characteristics include meridian, parallel and areal scales, angular + distortion, meridian/parallel, meridian convergence and scale error. + + returns PJ_FACTORS. If unsuccessful, error number is set and the + struct returned contains NULL data. +******************************************************************************/ + PJ_FACTORS factors = {0,0,0, 0,0,0, 0,0, 0,0,0,0}; + struct FACTORS f; + + if (nullptr==P) + return factors; + + if (pj_factors(lp.lp, P, 0.0, &f)) + return factors; + + factors.meridional_scale = f.h; + factors.parallel_scale = f.k; + factors.areal_scale = f.s; + + factors.angular_distortion = f.omega; + factors.meridian_parallel_angle = f.thetap; + factors.meridian_convergence = f.conv; + + factors.tissot_semimajor = f.a; + factors.tissot_semiminor = f.b; + + /* Raw derivatives, for completeness's sake */ + factors.dx_dlam = f.der.x_l; + factors.dx_dphi = f.der.x_p; + factors.dy_dlam = f.der.y_l; + factors.dy_dphi = f.der.y_p; + + return factors; +} diff --git a/src/Makefile.am b/src/Makefile.am index 4912ae02..c67f187e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,7 @@ include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesi EXTRA_DIST = bin_cct.cmake bin_gie.cmake bin_cs2cs.cmake \ bin_geod.cmake bin_nad2bin.cmake bin_proj.cmake bin_projinfo.cmake \ lib_proj.cmake CMakeLists.txt bin_geodtest.cmake tests/geodtest.cpp \ - pj_wkt1_grammar.y pj_wkt2_grammar.y apps/emess.h + wkt1_grammar.y wkt2_grammar.y apps/emess.h proj_SOURCES = apps/proj.cpp apps/gen_cheb.cpp apps/p_series.cpp apps/emess.cpp projinfo_SOURCES = apps/projinfo.cpp @@ -63,166 +63,166 @@ libproj_la_SOURCES = \ iso19111/factory.cpp \ iso19111/c_api.cpp \ \ - projections/PJ_aeqd.cpp \ - projections/PJ_gnom.cpp \ - projections/PJ_laea.cpp \ - projections/PJ_mod_ster.cpp \ - projections/PJ_nsper.cpp \ - projections/PJ_nzmg.cpp \ - projections/PJ_ortho.cpp \ - projections/PJ_stere.cpp \ - projections/PJ_sterea.cpp \ - projections/PJ_aea.cpp \ - projections/PJ_bipc.cpp \ - projections/PJ_bonne.cpp \ - projections/PJ_eqdc.cpp \ - projections/PJ_isea.cpp \ - projections/PJ_ccon.cpp \ - projections/PJ_imw_p.cpp \ - projections/PJ_krovak.cpp \ - projections/PJ_lcc.cpp \ - projections/PJ_poly.cpp \ - projections/PJ_rpoly.cpp \ - projections/PJ_sconics.cpp \ - projections/proj_rouss.cpp \ - projections/PJ_cass.cpp \ - projections/PJ_cc.cpp \ - projections/PJ_cea.cpp \ - projections/PJ_eqc.cpp \ - projections/PJ_gall.cpp \ - projections/PJ_labrd.cpp \ - projections/PJ_lsat.cpp \ - projections/PJ_misrsom.cpp \ - projections/PJ_merc.cpp \ - projections/PJ_mill.cpp \ - projections/PJ_ocea.cpp \ - projections/PJ_omerc.cpp \ - projections/PJ_somerc.cpp \ - projections/PJ_tcc.cpp \ - projections/PJ_tcea.cpp \ - projections/PJ_times.cpp \ - projections/PJ_tmerc.cpp \ - projections/PJ_tobmerc.cpp \ - projections/PJ_airy.cpp \ - projections/PJ_aitoff.cpp \ - projections/PJ_august.cpp \ - projections/PJ_bacon.cpp \ - projections/PJ_bertin1953.cpp \ - projections/PJ_chamb.cpp \ - projections/PJ_hammer.cpp \ - projections/PJ_lagrng.cpp \ - projections/PJ_larr.cpp \ - projections/PJ_lask.cpp \ - projections/PJ_latlong.cpp \ - projections/PJ_nocol.cpp \ - projections/PJ_ob_tran.cpp \ - projections/PJ_oea.cpp \ - projections/PJ_tpeqd.cpp \ - projections/PJ_vandg.cpp \ - projections/PJ_vandg2.cpp \ - projections/PJ_vandg4.cpp \ - projections/PJ_wag7.cpp \ - projections/PJ_lcca.cpp \ - projections/PJ_geos.cpp \ - projections/proj_etmerc.cpp \ - projections/PJ_boggs.cpp \ - projections/PJ_collg.cpp \ - projections/PJ_comill.cpp \ - projections/PJ_crast.cpp \ - projections/PJ_denoy.cpp \ - projections/PJ_eck1.cpp \ - projections/PJ_eck2.cpp \ - projections/PJ_eck3.cpp \ - projections/PJ_eck4.cpp \ - projections/PJ_eck5.cpp \ - projections/PJ_fahey.cpp \ - projections/PJ_fouc_s.cpp \ - projections/PJ_gins8.cpp \ - projections/PJ_gstmerc.cpp \ - projections/PJ_gn_sinu.cpp \ - projections/PJ_goode.cpp \ - projections/PJ_igh.cpp \ - projections/PJ_hatano.cpp \ - projections/PJ_loxim.cpp \ - projections/PJ_mbt_fps.cpp \ - projections/PJ_mbtfpp.cpp \ - projections/PJ_mbtfpq.cpp \ - projections/PJ_moll.cpp \ - projections/PJ_nell.cpp \ - projections/PJ_nell_h.cpp \ - projections/PJ_patterson.cpp \ - projections/PJ_putp2.cpp \ - projections/PJ_putp3.cpp \ - projections/PJ_putp4p.cpp \ - projections/PJ_putp5.cpp \ - projections/PJ_putp6.cpp \ - projections/PJ_qsc.cpp \ - projections/PJ_robin.cpp \ - projections/PJ_sch.cpp \ - projections/PJ_sts.cpp \ - projections/PJ_urm5.cpp \ - projections/PJ_urmfps.cpp \ - projections/PJ_wag2.cpp \ - projections/PJ_wag3.cpp \ - projections/PJ_wink1.cpp \ - projections/PJ_wink2.cpp \ - projections/PJ_healpix.cpp \ - projections/PJ_natearth.cpp \ - projections/PJ_natearth2.cpp \ - projections/PJ_calcofi.cpp \ - projections/PJ_eqearth.cpp \ + projections/aeqd.cpp \ + projections/gnom.cpp \ + projections/laea.cpp \ + projections/mod_ster.cpp \ + projections/nsper.cpp \ + projections/nzmg.cpp \ + projections/ortho.cpp \ + projections/stere.cpp \ + projections/sterea.cpp \ + projections/aea.cpp \ + projections/bipc.cpp \ + projections/bonne.cpp \ + projections/eqdc.cpp \ + projections/isea.cpp \ + projections/ccon.cpp \ + projections/imw_p.cpp \ + projections/krovak.cpp \ + projections/lcc.cpp \ + projections/poly.cpp \ + projections/rpoly.cpp \ + projections/sconics.cpp \ + projections/rouss.cpp \ + projections/cass.cpp \ + projections/cc.cpp \ + projections/cea.cpp \ + projections/eqc.cpp \ + projections/gall.cpp \ + projections/labrd.cpp \ + projections/lsat.cpp \ + projections/misrsom.cpp \ + projections/merc.cpp \ + projections/mill.cpp \ + projections/ocea.cpp \ + projections/omerc.cpp \ + projections/somerc.cpp \ + projections/tcc.cpp \ + projections/tcea.cpp \ + projections/times.cpp \ + projections/tmerc.cpp \ + projections/tobmerc.cpp \ + projections/airy.cpp \ + projections/aitoff.cpp \ + projections/august.cpp \ + projections/bacon.cpp \ + projections/bertin1953.cpp \ + projections/chamb.cpp \ + projections/hammer.cpp \ + projections/lagrng.cpp \ + projections/larr.cpp \ + projections/lask.cpp \ + projections/latlong.cpp \ + projections/nocol.cpp \ + projections/ob_tran.cpp \ + projections/oea.cpp \ + projections/tpeqd.cpp \ + projections/vandg.cpp \ + projections/vandg2.cpp \ + projections/vandg4.cpp \ + projections/wag7.cpp \ + projections/lcca.cpp \ + projections/geos.cpp \ + projections/etmerc.cpp \ + projections/boggs.cpp \ + projections/collg.cpp \ + projections/comill.cpp \ + projections/crast.cpp \ + projections/denoy.cpp \ + projections/eck1.cpp \ + projections/eck2.cpp \ + projections/eck3.cpp \ + projections/eck4.cpp \ + projections/eck5.cpp \ + projections/fahey.cpp \ + projections/fouc_s.cpp \ + projections/gins8.cpp \ + projections/gstmerc.cpp \ + projections/gn_sinu.cpp \ + projections/goode.cpp \ + projections/igh.cpp \ + projections/hatano.cpp \ + projections/loxim.cpp \ + projections/mbt_fps.cpp \ + projections/mbtfpp.cpp \ + projections/mbtfpq.cpp \ + projections/moll.cpp \ + projections/nell.cpp \ + projections/nell_h.cpp \ + projections/patterson.cpp \ + projections/putp2.cpp \ + projections/putp3.cpp \ + projections/putp4p.cpp \ + projections/putp5.cpp \ + projections/putp6.cpp \ + projections/qsc.cpp \ + projections/robin.cpp \ + projections/sch.cpp \ + projections/sts.cpp \ + projections/urm5.cpp \ + projections/urmfps.cpp \ + projections/wag2.cpp \ + projections/wag3.cpp \ + projections/wink1.cpp \ + projections/wink2.cpp \ + projections/healpix.cpp \ + projections/natearth.cpp \ + projections/natearth2.cpp \ + projections/calcofi.cpp \ + projections/eqearth.cpp \ \ - conversions/PJ_axisswap.cpp \ - conversions/PJ_cart.cpp \ - conversions/PJ_geoc.cpp \ - conversions/pj_geocent.cpp \ - conversions/PJ_unitconvert.cpp \ + conversions/axisswap.cpp \ + conversions/cart.cpp \ + conversions/geoc.cpp \ + conversions/geocent.cpp \ + conversions/unitconvert.cpp \ \ - transformations/PJ_affine.cpp \ - transformations/PJ_deformation.cpp \ - transformations/PJ_helmert.cpp \ - transformations/PJ_hgridshift.cpp \ - transformations/PJ_horner.cpp \ - transformations/PJ_molodensky.cpp \ - transformations/PJ_vgridshift.cpp \ + transformations/affine.cpp \ + transformations/deformation.cpp \ + transformations/helmert.cpp \ + transformations/hgridshift.cpp \ + transformations/horner.cpp \ + transformations/molodensky.cpp \ + transformations/vgridshift.cpp \ \ aasincos.cpp adjlon.cpp bch2bps.cpp bchgen.cpp \ - biveval.cpp dmstor.cpp mk_cheby.cpp pj_auth.cpp \ - pj_deriv.cpp pj_ell_set.cpp pj_ellps.cpp pj_errno.cpp \ - pj_factors.cpp pj_fwd.cpp pj_init.cpp pj_inv.cpp \ - pj_list.cpp pj_malloc.cpp pj_mlfn.cpp pj_msfn.cpp proj_mdist.cpp \ - pj_open_lib.cpp pj_param.cpp pj_phi2.cpp pj_pr_list.cpp \ - pj_qsfn.cpp pj_strerrno.cpp \ - pj_tsfn.cpp pj_units.cpp pj_ctx.cpp pj_log.cpp pj_zpoly1.cpp rtodms.cpp \ - vector1.cpp pj_release.cpp pj_gauss.cpp \ - pj_fileapi.cpp \ + biveval.cpp dmstor.cpp mk_cheby.cpp auth.cpp \ + deriv.cpp ell_set.cpp ellps.cpp errno.cpp \ + factors.cpp fwd.cpp init.cpp inv.cpp \ + list.cpp malloc.cpp mlfn.cpp msfn.cpp proj_mdist.cpp \ + open_lib.cpp param.cpp phi2.cpp pr_list.cpp \ + qsfn.cpp strerrno.cpp \ + tsfn.cpp units.cpp ctx.cpp log.cpp zpoly1.cpp rtodms.cpp \ + vector1.cpp release.cpp gauss.cpp \ + fileapi.cpp \ \ - pj_gc_reader.cpp pj_gridcatalog.cpp \ + gc_reader.cpp gridcatalog.cpp \ nad_cvt.cpp nad_init.cpp nad_intr.cpp \ - pj_apply_gridshift.cpp pj_datums.cpp pj_datum_set.cpp pj_transform.cpp \ - geocent.cpp geocent.h pj_utils.cpp pj_gridinfo.cpp pj_gridlist.cpp \ - jniproj.cpp pj_mutex.cpp pj_initcache.cpp pj_apply_vgridshift.cpp geodesic.cpp \ - pj_strtod.cpp pj_math.cpp \ + apply_gridshift.cpp datums.cpp datum_set.cpp transform.cpp \ + geocent.cpp geocent.h utils.cpp gridinfo.cpp gridlist.cpp \ + jniproj.cpp mutex.cpp initcache.cpp apply_vgridshift.cpp geodesic.cpp \ + strtod.cpp math.cpp \ \ - proj_4D_api.cpp PJ_pipeline.cpp \ - pj_internal.cpp \ - pj_wkt_parser.hpp pj_wkt_parser.cpp \ - pj_wkt1_parser.h pj_wkt1_parser.cpp \ - pj_wkt1_generated_parser.h pj_wkt1_generated_parser.c \ - pj_wkt2_parser.h pj_wkt2_parser.cpp \ - pj_wkt2_generated_parser.h pj_wkt2_generated_parser.c + 4D_api.cpp pipeline.cpp \ + internal.cpp \ + wkt_parser.hpp wkt_parser.cpp \ + wkt1_parser.h wkt1_parser.cpp \ + wkt1_generated_parser.h wkt1_generated_parser.c \ + wkt2_parser.h wkt2_parser.cpp \ + wkt2_generated_parser.h wkt2_generated_parser.c # The sed hack is to please MSVC wkt1_parser: - bison --no-lines -d -p pj_wkt1_ -o$(top_srcdir)/src/pj_wkt1_generated_parser.c $(top_srcdir)/src/pj_wkt1_grammar.y - sed "s/\*yyssp = yystate/\*yyssp = (yytype_int16)yystate/" < $(top_srcdir)/src/pj_wkt1_generated_parser.c | sed "s/yyerrorlab:/#if 0\nyyerrorlab:/" | sed "s/yyerrlab1:/#endif\nyyerrlab1:/" | sed "s/for (yylen = 0; yystr\[yylen\]; yylen++)/for (yylen = 0; yystr \&\& yystr\[yylen\]; yylen++)/" > $(top_srcdir)/src/pj_wkt1_generated_parser.c.tmp - mv $(top_srcdir)/src/pj_wkt1_generated_parser.c.tmp $(top_srcdir)/src/pj_wkt1_generated_parser.c + bison --no-lines -d -p pj_wkt1_ -o$(top_srcdir)/src/wkt1_generated_parser.c $(top_srcdir)/src/wkt1_grammar.y + sed "s/\*yyssp = yystate/\*yyssp = (yytype_int16)yystate/" < $(top_srcdir)/src/wkt1_generated_parser.c | sed "s/yyerrorlab:/#if 0\nyyerrorlab:/" | sed "s/yyerrlab1:/#endif\nyyerrlab1:/" | sed "s/for (yylen = 0; yystr\[yylen\]; yylen++)/for (yylen = 0; yystr \&\& yystr\[yylen\]; yylen++)/" > $(top_srcdir)/src/wkt1_generated_parser.c.tmp + mv $(top_srcdir)/src/wkt1_generated_parser.c.tmp $(top_srcdir)/src/wkt1_generated_parser.c wkt2_parser: - bison --no-lines -d -p pj_wkt2_ -o$(top_srcdir)/src/pj_wkt2_generated_parser.c $(top_srcdir)/src/pj_wkt2_grammar.y - sed "s/\*yyssp = yystate/\*yyssp = (yytype_int16)yystate/" < $(top_srcdir)/src/pj_wkt2_generated_parser.c | sed "s/yyerrorlab:/#if 0\nyyerrorlab:/" | sed "s/yyerrlab1:/#endif\nyyerrlab1:/" | sed "s/for (yylen = 0; yystr\[yylen\]; yylen++)/for (yylen = 0; yystr \&\& yystr\[yylen\]; yylen++)/" > $(top_srcdir)/src/pj_wkt2_generated_parser.c.tmp - mv $(top_srcdir)/src/pj_wkt2_generated_parser.c.tmp $(top_srcdir)/src/pj_wkt2_generated_parser.c + bison --no-lines -d -p pj_wkt2_ -o$(top_srcdir)/src/wkt2_generated_parser.c $(top_srcdir)/src/wkt2_grammar.y + sed "s/\*yyssp = yystate/\*yyssp = (yytype_int16)yystate/" < $(top_srcdir)/src/wkt2_generated_parser.c | sed "s/yyerrorlab:/#if 0\nyyerrorlab:/" | sed "s/yyerrlab1:/#endif\nyyerrlab1:/" | sed "s/for (yylen = 0; yystr\[yylen\]; yylen++)/for (yylen = 0; yystr \&\& yystr\[yylen\]; yylen++)/" > $(top_srcdir)/src/wkt2_generated_parser.c.tmp + mv $(top_srcdir)/src/wkt2_generated_parser.c.tmp $(top_srcdir)/src/wkt2_generated_parser.c install-exec-local: install-binPROGRAMS diff --git a/src/PJ_pipeline.cpp b/src/PJ_pipeline.cpp deleted file mode 100644 index 76fc58a5..00000000 --- a/src/PJ_pipeline.cpp +++ /dev/null @@ -1,503 +0,0 @@ -/******************************************************************************* - - Transformation pipeline manager - - Thomas Knudsen, 2016-05-20/2016-11-20 - -******************************************************************************** - - Geodetic transformations are typically organized in a number of - steps. For example, a datum shift could be carried out through - these steps: - - 1. Convert (latitude, longitude, ellipsoidal height) to - 3D geocentric cartesian coordinates (X, Y, Z) - 2. Transform the (X, Y, Z) coordinates to the new datum, using a - 7 parameter Helmert transformation. - 3. Convert (X, Y, Z) back to (latitude, longitude, ellipsoidal height) - - If the height system used is orthometric, rather than ellipsoidal, - another step is needed at each end of the process: - - 1. Add the local geoid undulation (N) to the orthometric height - to obtain the ellipsoidal (i.e. geometric) height. - 2. Convert (latitude, longitude, ellipsoidal height) to - 3D geocentric cartesian coordinates (X, Y, Z) - 3. Transform the (X, Y, Z) coordinates to the new datum, using a - 7 parameter Helmert transformation. - 4. Convert (X, Y, Z) back to (latitude, longitude, ellipsoidal height) - 5. Subtract the local geoid undulation (N) from the ellipsoidal height - to obtain the orthometric height. - - Additional steps can be added for e.g. change of vertical datum, so the - list can grow fairly long. None of the steps are, however, particularly - complex, and data flow is strictly from top to bottom. - - Hence, in principle, the first example above could be implemented using - Unix pipelines: - - cat my_coordinates | geographic_to_xyz | helmert | xyz_to_geographic > my_transformed_coordinates - - in the grand tradition of Software Tools [1]. - - The proj pipeline driver implements a similar concept: Stringing together - a number of steps, feeding the output of one step to the input of the next. - - It is a very powerful concept, that increases the range of relevance of the - proj.4 system substantially. It is, however, not a particularly intrusive - addition to the PROJ.4 code base: The implementation is by and large completed - by adding an extra projection called "pipeline" (i.e. this file), which - handles all business, and a small amount of added functionality in the - pj_init code, implementing support for multilevel, embedded pipelines. - - Syntactically, the pipeline system introduces the "+step" keyword (which - indicates the start of each transformation step), and reintroduces the +inv - keyword (indicating that a given transformation step should run in reverse, i.e. - forward, when the pipeline is executed in inverse direction, and vice versa). - - Hence, the first transformation example above, can be implemented as: - - +proj=pipeline +step proj=cart +step proj=helmert +step proj=cart +inv - - Where indicate the Helmert arguments: 3 translations (+x=..., +y=..., - +z=...), 3 rotations (+rx=..., +ry=..., +rz=...) and a scale factor (+s=...). - Following geodetic conventions, the rotations are given in arcseconds, - and the scale factor is given as parts-per-million. - - [1] B. W. Kernighan & P. J. Plauger: Software tools. - Reading, Massachusetts, Addison-Wesley, 1976, 338 pp. - -******************************************************************************** - -Thomas Knudsen, thokn@sdfe.dk, 2016-05-20 - -******************************************************************************** -* Copyright (c) 2016, 2017, 2018 Thomas Knudsen / SDFE -* -* 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 - -#include "geodesic.h" -#include "proj.h" -#include "proj_internal.h" -#include "projects.h" - -PROJ_HEAD(pipeline, "Transformation pipeline manager"); - -/* Projection specific elements for the PJ object */ -namespace { // anonymous namespace -struct pj_opaque { - int steps; - char **argv; - char **current_argv; - PJ **pipeline; -}; -} // anonymous namespace - - - -static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P); -static PJ_COORD pipeline_reverse_4d (PJ_COORD point, PJ *P); -static XYZ pipeline_forward_3d (LPZ lpz, PJ *P); -static LPZ pipeline_reverse_3d (XYZ xyz, PJ *P); -static XY pipeline_forward (LP lp, PJ *P); -static LP pipeline_reverse (XY xy, PJ *P); - - - - -static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P) { - int i, first_step, last_step; - - first_step = 1; - last_step = static_cast(P->opaque)->steps + 1; - - for (i = first_step; i != last_step; i++) - point = proj_trans (static_cast(P->opaque)->pipeline[i], PJ_FWD, point); - - return point; -} - - -static PJ_COORD pipeline_reverse_4d (PJ_COORD point, PJ *P) { - int i, first_step, last_step; - - first_step = static_cast(P->opaque)->steps; - last_step = 0; - - for (i = first_step; i != last_step; i--) - point = proj_trans (static_cast(P->opaque)->pipeline[i], PJ_INV, point); - - return point; -} - - - - -static XYZ pipeline_forward_3d (LPZ lpz, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - int i; - point.lpz = lpz; - - for (i = 1; i <= static_cast(P->opaque)->steps; i++) - point = pj_approx_3D_trans (static_cast(P->opaque)->pipeline[i], PJ_FWD, point); - - return point.xyz; -} - - -static LPZ pipeline_reverse_3d (XYZ xyz, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - int i; - point.xyz = xyz; - - for (i = static_cast(P->opaque)->steps; i > 0 ; i--) - point = pj_approx_3D_trans (static_cast(P->opaque)->pipeline[i], PJ_INV, point); - - return point.lpz; -} - - - - -static XY pipeline_forward (LP lp, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - int i; - point.lp = lp; - - for (i = 1; i <= static_cast(P->opaque)->steps; i++) - point = pj_approx_2D_trans (static_cast(P->opaque)->pipeline[i], PJ_FWD, point); - - return point.xy; -} - - -static LP pipeline_reverse (XY xy, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - int i; - point.xy = xy; - for (i = static_cast(P->opaque)->steps; i > 0 ; i--) - point = pj_approx_2D_trans (static_cast(P->opaque)->pipeline[i], PJ_INV, point); - - return point.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); - - /* Deallocate each pipeine step, then pipeline array */ - if (nullptr!=static_cast(P->opaque)->pipeline) - for (i = 0; i < static_cast(P->opaque)->steps; i++) - proj_destroy (static_cast(P->opaque)->pipeline[i+1]); - pj_dealloc (static_cast(P->opaque)->pipeline); - - pj_dealloc (static_cast(P->opaque)->argv); - pj_dealloc (static_cast(P->opaque)->current_argv); - - return pj_default_destructor(P, errlev); -} - - -static PJ *pj_create_pipeline (PJ *P, size_t steps) { - - /* Room for the pipeline: An array of PJ * with room for sentinels at both ends */ - static_cast(P->opaque)->pipeline = static_cast(pj_calloc (steps + 2, sizeof(PJ *))); - if (nullptr==static_cast(P->opaque)->pipeline) - return nullptr; - - static_cast(P->opaque)->steps = (int)steps; - - return P; -} - - - - -/* count the number of args in pipeline definition, and mark all args as used */ -static size_t argc_params (paralist *params) { - size_t argc = 0; - for (; params != nullptr; params = params->next) { - argc++; - params->used = 1; - } - return ++argc; /* one extra for the sentinel */ -} - -/* Sentinel for argument list */ -static const char *argv_sentinel = "step"; - -/* turn paralist into argc/argv style argument list */ -static char **argv_params (paralist *params, size_t argc) { - char **argv; - size_t i = 0; - argv = static_cast(pj_calloc (argc, sizeof (char *))); - if (nullptr==argv) - return nullptr; - for (; params != nullptr; params = params->next) - argv[i++] = params->param; - argv[i++] = const_cast(argv_sentinel); - return argv; -} - - - - -/* Being the special operator that the pipeline is, we have to handle the */ -/* ellipsoid differently than usual. In general, the pipeline operation does */ -/* not need an ellipsoid, but in some cases it is beneficial nonetheless. */ -/* Unfortunately we can't use the normal ellipsoid setter in pj_init, since */ -/* it adds a +ellps parameter to the global args if nothing else is specified*/ -/* This is problematic since that ellipsoid spec is then passed on to the */ -/* pipeline children. This is rarely what we want, so here we implement our */ -/* own logic instead. If an ellipsoid is set in the global args, it is used */ -/* as the pipeline ellipsoid. Otherwise we use WGS84 parameters as default. */ -/* At last we calculate the rest of the ellipsoid parameters and */ -/* re-initialize P->geod. */ -static void set_ellipsoid(PJ *P) { - paralist *cur, *attachment; - int err = proj_errno_reset (P); - - /* Break the linked list after the global args */ - attachment = nullptr; - for (cur = P->params; cur != nullptr; cur = cur->next) - /* cur->next will always be non 0 given argv_sentinel presence, */ - /* but this is far from being obvious for a static analyzer */ - if (cur->next != nullptr && strcmp(argv_sentinel, cur->next->param) == 0) { - attachment = cur->next; - cur->next = nullptr; - break; - } - - /* Check if there's any ellipsoid specification in the global params. */ - /* If not, use WGS84 as default */ - if (0 != pj_ellipsoid (P)) { - P->a = 6378137.0; - P->es = .00669438002290341575; - - /* reset an "unerror": In this special use case, the errno is */ - /* not an error signal, but just a reply from pj_ellipsoid, */ - /* telling us that "No - there was no ellipsoid definition in */ - /* the PJ you provided". */ - proj_errno_reset (P); - } - P->a_orig = P->a; - P->es_orig = P->es; - - pj_calc_ellipsoid_params (P, P->a, P->es); - - geod_init(P->geod, P->a, (1 - sqrt (1 - P->es))); - - /* Re-attach the dangling list */ - /* Note: cur will always be non 0 given argv_sentinel presence, */ - /* but this is far from being obvious for a static analyzer */ - if( cur != nullptr ) - cur->next = attachment; - proj_errno_restore (P, err); -} - - - - -PJ *OPERATION(pipeline,0) { - int i, nsteps = 0, argc; - int i_pipeline = -1, i_first_step = -1, i_current_step; - char **argv, **current_argv; - - P->fwd4d = pipeline_forward_4d; - P->inv4d = pipeline_reverse_4d; - P->fwd3d = pipeline_forward_3d; - P->inv3d = pipeline_reverse_3d; - P->fwd = pipeline_forward; - P->inv = pipeline_reverse; - P->destructor = destructor; - P->is_pipeline = 1; - - /* Currently, the pipeline driver is a raw bit mover, enabling other operations */ - /* to collaborate efficiently. All prep/fin stuff is done at the step levels. */ - P->skip_fwd_prepare = 1; - P->skip_fwd_finalize = 1; - P->skip_inv_prepare = 1; - P->skip_inv_finalize = 1; - - - P->opaque = static_cast(pj_calloc (1, sizeof(struct pj_opaque))); - if (nullptr==P->opaque) - return destructor(P, ENOMEM); - - argc = (int)argc_params (P->params); - static_cast(P->opaque)->argv = argv = argv_params (P->params, argc); - if (nullptr==argv) - return destructor (P, ENOMEM); - - static_cast(P->opaque)->current_argv = current_argv = static_cast(pj_calloc (argc, sizeof (char *))); - if (nullptr==current_argv) - return destructor (P, ENOMEM); - - /* Do some syntactical sanity checking */ - for (i = 0; i < argc; i++) { - if (0==strcmp (argv_sentinel, argv[i])) { - if (-1==i_pipeline) { - proj_log_error (P, "Pipeline: +step before +proj=pipeline"); - return destructor (P, PJD_ERR_MALFORMED_PIPELINE); - } - if (0==nsteps) - i_first_step = i; - nsteps++; - continue; - } - - if (0==strcmp ("proj=pipeline", argv[i])) { - if (-1 != i_pipeline) { - proj_log_error (P, "Pipeline: Nesting only allowed when child pipelines are wrapped in '+init's"); - return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: nested pipelines */ - } - i_pipeline = i; - } - } - nsteps--; /* Last instance of +step is just a sentinel */ - static_cast(P->opaque)->steps = nsteps; - - if (-1==i_pipeline) - return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: no pipeline def */ - - if (0==nsteps) - return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: no pipeline def */ - - /* Make room for the pipeline and execution indicators */ - if (nullptr==pj_create_pipeline (P, nsteps)) - return destructor (P, ENOMEM); - - set_ellipsoid(P); - - /* Now loop over all steps, building a new set of arguments for each init */ - i_current_step = i_first_step; - for (i = 0; i < nsteps; i++) { - int j; - int current_argc = 0; - int err; - PJ *next_step = nullptr; - - /* Build a set of setup args for the current step */ - proj_log_trace (P, "Pipeline: Building arg list for step no. %d", i); - - /* First add the step specific args */ - for (j = i_current_step + 1; 0 != strcmp ("step", argv[j]); j++) - current_argv[current_argc++] = argv[j]; - - i_current_step = j; - - /* Then add the global args */ - for (j = i_pipeline + 1; 0 != strcmp ("step", argv[j]); j++) - current_argv[current_argc++] = argv[j]; - - proj_log_trace (P, "Pipeline: init - %s, %d", current_argv[0], current_argc); - for (j = 1; j < current_argc; j++) - proj_log_trace (P, " %s", current_argv[j]); - - err = proj_errno_reset (P); - - next_step = proj_create_argv (P->ctx, current_argc, current_argv); - proj_log_trace (P, "Pipeline: Step %d (%s) at %p", i, current_argv[0], next_step); - - if (nullptr==next_step) { - /* The step init failed, but possibly without setting errno. If so, we say "malformed" */ - int err_to_report = proj_errno(P); - if (0==err_to_report) - err_to_report = PJD_ERR_MALFORMED_PIPELINE; - proj_log_error (P, "Pipeline: Bad step definition: %s (%s)", current_argv[0], pj_strerrno (err_to_report)); - return destructor (P, err_to_report); /* ERROR: bad pipeline def */ - } - - proj_errno_restore (P, err); - - /* Is this step inverted? */ - for (j = 0; j < current_argc; j++) - if (0==strcmp("inv", current_argv[j])) { - /* if +inv exists in both global and local args the forward operation should be used */ - next_step->inverted = next_step->inverted == 0 ? 1 : 0; - } - - static_cast(P->opaque)->pipeline[i+1] = next_step; - - proj_log_trace (P, "Pipeline at [%p]: step at [%p] (%s) done", P, next_step, current_argv[0]); - } - - /* Require a forward path through the pipeline */ - for (i = 1; i <= nsteps; i++) { - PJ *Q = static_cast(P->opaque)->pipeline[i]; - if ( ( Q->inverted && (Q->inv || Q->inv3d || Q->fwd4d) ) || - (!Q->inverted && (Q->fwd || Q->fwd3d || Q->fwd4d) ) ) { - continue; - } else { - proj_log_error (P, "Pipeline: A forward operation couldn't be constructed"); - return destructor (P, PJD_ERR_MALFORMED_PIPELINE); - } - } - - /* determine if an inverse operation is possible */ - for (i = 1; i <= nsteps; i++) { - PJ *Q = static_cast(P->opaque)->pipeline[i]; - if ( pj_has_inverse(Q) ) { - continue; - } else { - P->inv = nullptr; - P->inv3d = nullptr; - P->inv4d = nullptr; - break; - } - } - - /* Check that output units from step i are compatible with expected units in step i+1 */ - for (i = 1; i < nsteps; i++) { - enum pj_io_units unit_returned = pj_right (static_cast(P->opaque)->pipeline[i]); - enum pj_io_units unit_expected = pj_left (static_cast(P->opaque)->pipeline[i+1]); - - if ( unit_returned == PJ_IO_UNITS_WHATEVER || unit_expected == PJ_IO_UNITS_WHATEVER ) - continue; - if ( unit_returned != unit_expected ) { - proj_log_error (P, "Pipeline: Mismatched units between step %d and %d", i, i+1); - return destructor (P, PJD_ERR_MALFORMED_PIPELINE); - } - } - - proj_log_trace (P, "Pipeline: %d steps built. Determining i/o characteristics", nsteps); - - /* Determine forward input (= reverse output) data type */ - P->left = pj_left (static_cast(P->opaque)->pipeline[1]); - - /* Now, correspondingly determine forward output (= reverse input) data type */ - P->right = pj_right (static_cast(P->opaque)->pipeline[nsteps]); - return P; -} diff --git a/src/apply_gridshift.cpp b/src/apply_gridshift.cpp new file mode 100644 index 00000000..4c8115cc --- /dev/null +++ b/src/apply_gridshift.cpp @@ -0,0 +1,356 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Apply datum shifts based on grid shift files (normally NAD27 to + * NAD83 or the reverse). This module is responsible for keeping + * a list of loaded grids, and calling with each one that is + * allowed for a given datum (expressed as the nadgrids= parameter). + * 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include +#include + +#include "proj_internal.h" +#include "projects.h" + +/************************************************************************/ +/* pj_apply_gridshift() */ +/* */ +/* This is the externally callable interface - part of the */ +/* public API - though it is not used internally any more and I */ +/* doubt it is used by any other applications. But we preserve */ +/* it to honour our public api. */ +/************************************************************************/ + +int pj_apply_gridshift( projCtx ctx, const char *nadgrids, int inverse, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + PJ_GRIDINFO **gridlist; + int grid_count; + int ret; + + gridlist = pj_gridlist_from_nadgrids( ctx, nadgrids, &grid_count ); + + if( gridlist == nullptr || grid_count == 0 ) + return ctx->last_errno; + + ret = pj_apply_gridshift_3( ctx, gridlist, grid_count, inverse, + point_count, point_offset, x, y, z ); + + /* + ** Note this frees the array of grid list pointers, but not the grids + ** which is as intended. The grids themselves live on. + */ + pj_dalloc( gridlist ); + + return ret; +} + +/************************************************************************/ +/* pj_apply_gridshift_2() */ +/* */ +/* This implementation uses the gridlist from a coordinate */ +/* system definition. If the gridlist has not yet been */ +/* populated in the coordinate system definition we set it up */ +/* now. */ +/************************************************************************/ + +int pj_apply_gridshift_2( PJ *defn, int inverse, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + if( defn->catalog_name != nullptr ) + return pj_gc_apply_gridshift( defn, inverse, point_count, point_offset, + x, y, z ); + + if( defn->gridlist == nullptr ) + { + defn->gridlist = + pj_gridlist_from_nadgrids( pj_get_ctx( defn ), + pj_param(defn->ctx, defn->params,"snadgrids").s, + &(defn->gridlist_count) ); + + if( defn->gridlist == nullptr || defn->gridlist_count == 0 ) + return defn->ctx->last_errno; + } + + return pj_apply_gridshift_3( pj_get_ctx( defn ), + defn->gridlist, defn->gridlist_count, inverse, + point_count, point_offset, x, y, z ); +} + +/************************************************************************/ +/* find_ctable() */ +/* */ +/* Determine which grid is the correct given an input coordinate. */ +/************************************************************************/ + +static struct CTABLE* find_ctable(projCtx ctx, LP input, int grid_count, PJ_GRIDINFO **tables) { + int itable; + + /* keep trying till we find a table that works */ + for( itable = 0; itable < grid_count; itable++ ) + { + + PJ_GRIDINFO *gi = tables[itable]; + struct CTABLE *ct = gi->ct; + double epsilon = (fabs(ct->del.phi)+fabs(ct->del.lam))/10000.0; + /* skip tables that don't match our point at all. */ + if ( ct->ll.phi - epsilon > input.phi + || ct->ll.lam - epsilon > input.lam + || (ct->ll.phi + (ct->lim.phi-1) * ct->del.phi + epsilon < input.phi) + || (ct->ll.lam + (ct->lim.lam-1) * ct->del.lam + epsilon < input.lam) ) { + continue; + } + + /* If we have child nodes, check to see if any of them apply. */ + while( gi->child ) + { + PJ_GRIDINFO *child; + + for( child = gi->child; child != nullptr; child = child->next ) + { + struct CTABLE *ct1 = child->ct; + epsilon = (fabs(ct1->del.phi)+fabs(ct1->del.lam))/10000.0; + + if( ct1->ll.phi - epsilon > input.phi + || ct1->ll.lam - epsilon > input.lam + || (ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi + epsilon < input.phi) + || (ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam + epsilon < input.lam) ) { + continue; + } + break; + } + + /* If we didn't find a child then nothing more to do */ + if( child == nullptr ) break; + + /* Otherwise use the child, first checking it's children */ + gi = child; + ct = child->ct; + } + /* load the grid shift info if we don't have it. */ + if( ct->cvs == nullptr) { + if (!pj_gridinfo_load( ctx, gi ) ) { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return nullptr; + } + } + /* if we get this far we have found a suitable grid */ + return ct; + } + + return nullptr; +} + +/************************************************************************/ +/* pj_apply_gridshift_3() */ +/* */ +/* This is the real workhorse, given a gridlist. */ +/************************************************************************/ + +int pj_apply_gridshift_3( projCtx ctx, PJ_GRIDINFO **gridlist, int gridlist_count, + int inverse, long point_count, int point_offset, + double *x, double *y, double *z ) +{ + int i; + struct CTABLE *ct; + static int debug_count = 0; + (void) z; + + if( gridlist== nullptr || gridlist_count == 0 ) + { + pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + return PJD_ERR_FAILED_TO_LOAD_GRID; + } + + ctx->last_errno = 0; + + for( i = 0; i < point_count; i++ ) + { + long io = i * point_offset; + LP input, output; + int itable; + + input.phi = y[io]; + input.lam = x[io]; + output.phi = HUGE_VAL; + output.lam = HUGE_VAL; + + ct = find_ctable(ctx, input, gridlist_count, gridlist); + if( ct != nullptr ) + { + output = nad_cvt( input, inverse, ct ); + + if ( output.lam != HUGE_VAL && debug_count++ < 20 ) + pj_log( ctx, PJ_LOG_DEBUG_MINOR, "pj_apply_gridshift(): used %s", ct->id ); + } + + if ( output.lam == HUGE_VAL ) + { + if( ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) + { + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "pj_apply_gridshift(): failed to find a grid shift table for\n" + " location (%.7fdW,%.7fdN)", + x[io] * RAD_TO_DEG, + y[io] * RAD_TO_DEG ); + for( itable = 0; itable < gridlist_count; itable++ ) + { + PJ_GRIDINFO *gi = gridlist[itable]; + if( itable == 0 ) + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, " tried: %s", gi->gridname ); + else + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, ",%s", gi->gridname ); + } + } + + /* + * We don't actually have any machinery currently to set the + * following macro, so this is mostly kept here to make it clear + * how we ought to operate if we wanted to make it super clear + * that an error has occurred when points are outside our available + * datum shift areas. But if this is on, we will find that "low + * value" points on the fringes of some datasets will completely + * fail causing lots of problems when it is more or less ok to + * just not apply a datum shift. So rather than deal with + * that we just fallback to no shift. (see also bug #45). + */ +#ifdef ERR_GRID_AREA_TRANSIENT_SEVERE + y[io] = HUGE_VAL; + x[io] = HUGE_VAL; +#else + /* leave x/y unshifted. */ +#endif + } + else + { + y[io] = output.phi; + x[io] = output.lam; + } + } + + return 0; +} + +/**********************************************/ +int proj_hgrid_init(PJ* P, const char *grids) { +/********************************************** + + Initizalize and populate list of horizontal + grids. + + Takes a PJ-object and the plus-parameter + name that is used in the proj-string to + specify the grids to load, e.g. "+grids". + The + should be left out here. + + Returns the number of loaded grids. + +***********************************************/ + + /* prepend "s" to the "grids" string to allow usage with pj_param */ + char *sgrids = (char *) pj_malloc( (strlen(grids)+1+1) *sizeof(char) ); + sprintf(sgrids, "%s%s", "s", grids); + + if (P->gridlist == nullptr) { + P->gridlist = pj_gridlist_from_nadgrids( + P->ctx, + pj_param(P->ctx, P->params, sgrids).s, + &(P->gridlist_count) + ); + + if( P->gridlist == nullptr || P->gridlist_count == 0 ) { + pj_dealloc(sgrids); + return 0; + } + } + + if (P->gridlist_count == 0) { + proj_errno_set(P, PJD_ERR_FAILED_TO_LOAD_GRID); + } + + pj_dealloc(sgrids); + return P->gridlist_count; +} + +/********************************************/ +/* proj_hgrid_value() */ +/* */ +/* Return coordinate offset in grid */ +/********************************************/ +LP proj_hgrid_value(PJ *P, LP lp) { + struct CTABLE *ct; + LP out = proj_coord_error().lp; + + ct = find_ctable(P->ctx, lp, P->gridlist_count, P->gridlist); + if (ct == nullptr) { + pj_ctx_set_errno( P->ctx, PJD_ERR_GRID_AREA); + return out; + } + + /* normalize input to ll origin */ + lp.lam -= ct->ll.lam; + lp.phi -= ct->ll.phi; + + lp.lam = adjlon(lp.lam - M_PI) + M_PI; + + out = nad_intr(lp, ct); + + if (out.lam == HUGE_VAL || out.phi == HUGE_VAL) { + pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA); + } + + return out; +} + +LP proj_hgrid_apply(PJ *P, LP lp, PJ_DIRECTION direction) { + struct CTABLE *ct; + int inverse; + LP out; + + out.lam = HUGE_VAL; out.phi = HUGE_VAL; + + ct = find_ctable(P->ctx, lp, P->gridlist_count, P->gridlist); + + if (ct == nullptr || ct->cvs == nullptr) { + pj_ctx_set_errno( P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return out; + } + + inverse = direction == PJ_FWD ? 0 : 1; + out = nad_cvt(lp, inverse, ct); + + if (out.lam == HUGE_VAL || out.phi == HUGE_VAL) + pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA); + + return out; + +} diff --git a/src/apply_vgridshift.cpp b/src/apply_vgridshift.cpp new file mode 100644 index 00000000..1facfed6 --- /dev/null +++ b/src/apply_vgridshift.cpp @@ -0,0 +1,331 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Apply vertical datum shifts based on grid shift files, normally + * geoid grids mapping WGS84 to NAVD88 or something similar. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2010, 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include + +#include "proj_math.h" +#include "proj_internal.h" +#include "projects.h" + +static int is_nodata(float value) +{ + /* nodata? */ + /* GTX official nodata value if -88.88880f, but some grids also */ + /* use other big values for nodata (e.g naptrans2008.gtx has */ + /* nodata values like -2147479936), so test them too */ + return value > 1000 || value < -1000 || value == -88.88880f; +} + +static double read_vgrid_value( PJ *defn, LP input, int *gridlist_count_p, PJ_GRIDINFO **tables, struct CTABLE *ct) { + int itable = 0; + double value = HUGE_VAL; + double grid_x, grid_y; + long grid_ix, grid_iy; + long grid_ix2, grid_iy2; + float *cvs; + /* do not deal with NaN coordinates */ + /* cppcheck-suppress duplicateExpression */ + if( isnan(input.phi) || isnan(input.lam) ) + itable = *gridlist_count_p; + + /* keep trying till we find a table that works */ + for ( ; itable < *gridlist_count_p; itable++ ) + { + PJ_GRIDINFO *gi = tables[itable]; + + ct = gi->ct; + + /* skip tables that don't match our point at all. */ + if( ct->ll.phi > input.phi || ct->ll.lam > input.lam + || ct->ll.phi + (ct->lim.phi-1) * ct->del.phi < input.phi + || ct->ll.lam + (ct->lim.lam-1) * ct->del.lam < input.lam ) + continue; + + /* If we have child nodes, check to see if any of them apply. */ + while( gi->child != nullptr ) + { + PJ_GRIDINFO *child; + + for( child = gi->child; child != nullptr; child = child->next ) + { + struct CTABLE *ct1 = child->ct; + + if( ct1->ll.phi > input.phi || ct1->ll.lam > input.lam + || ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi < input.phi + || ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam < input.lam) + continue; + + break; + } + + /* we didn't find a more refined child node to use, so go with current grid */ + if( child == nullptr ) + { + break; + } + + /* Otherwise let's try for childrens children .. */ + gi = child; + ct = child->ct; + } + + /* load the grid shift info if we don't have it. */ + if( ct->cvs == nullptr && !pj_gridinfo_load( pj_get_ctx(defn), gi ) ) + { + pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return PJD_ERR_FAILED_TO_LOAD_GRID; + } + + + /* Interpolation a location within the grid */ + grid_x = (input.lam - ct->ll.lam) / ct->del.lam; + grid_y = (input.phi - ct->ll.phi) / ct->del.phi; + grid_ix = lround(floor(grid_x)); + grid_iy = lround(floor(grid_y)); + grid_x -= grid_ix; + grid_y -= grid_iy; + + grid_ix2 = grid_ix + 1; + if( grid_ix2 >= ct->lim.lam ) + grid_ix2 = ct->lim.lam - 1; + grid_iy2 = grid_iy + 1; + if( grid_iy2 >= ct->lim.phi ) + grid_iy2 = ct->lim.phi - 1; + + cvs = (float *) ct->cvs; + { + float value_a = cvs[grid_ix + grid_iy * ct->lim.lam]; + float value_b = cvs[grid_ix2 + grid_iy * ct->lim.lam]; + float value_c = cvs[grid_ix + grid_iy2 * ct->lim.lam]; + float value_d = cvs[grid_ix2 + grid_iy2 * ct->lim.lam]; + double total_weight = 0.0; + int n_weights = 0; + value = 0.0f; + if( !is_nodata(value_a) ) + { + double weight = (1.0-grid_x) * (1.0-grid_y); + value += value_a * weight; + total_weight += weight; + n_weights ++; + } + if( !is_nodata(value_b) ) + { + double weight = (grid_x) * (1.0-grid_y); + value += value_b * weight; + total_weight += weight; + n_weights ++; + } + if( !is_nodata(value_c) ) + { + double weight = (1.0-grid_x) * (grid_y); + value += value_c * weight; + total_weight += weight; + n_weights ++; + } + if( !is_nodata(value_d) ) + { + double weight = (grid_x) * (grid_y); + value += value_d * weight; + total_weight += weight; + n_weights ++; + } + if( n_weights == 0 ) + value = HUGE_VAL; + else if( n_weights != 4 ) + value /= total_weight; + } + + } + + return value; +} + +/************************************************************************/ +/* pj_apply_vgridshift() */ +/* */ +/* This implementation takes uses the gridlist from a coordinate */ +/* system definition. If the gridlist has not yet been */ +/* populated in the coordinate system definition we set it up */ +/* now. */ +/************************************************************************/ +int pj_apply_vgridshift( PJ *defn, const char *listname, + PJ_GRIDINFO ***gridlist_p, + int *gridlist_count_p, + int inverse, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + int i; + static int debug_count = 0; + PJ_GRIDINFO **tables; + struct CTABLE ct; + + if( *gridlist_p == nullptr ) + { + *gridlist_p = + pj_gridlist_from_nadgrids( pj_get_ctx(defn), + pj_param(defn->ctx,defn->params,listname).s, + gridlist_count_p ); + + if( *gridlist_p == nullptr || *gridlist_count_p == 0 ) + return defn->ctx->last_errno; + } + + if( *gridlist_count_p == 0 ) + { + pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + return PJD_ERR_FAILED_TO_LOAD_GRID; + } + + tables = *gridlist_p; + defn->ctx->last_errno = 0; + + for( i = 0; i < point_count; i++ ) + { + double value; + long io = i * point_offset; + LP input; + + input.phi = y[io]; + input.lam = x[io]; + + value = read_vgrid_value(defn, input, gridlist_count_p, tables, &ct); + + if( inverse ) + z[io] -= value; + else + z[io] += value; + if( value != HUGE_VAL ) + { + if( debug_count++ < 20 ) { + proj_log_trace(defn, "pj_apply_gridshift(): used %s", ct.id); + break; + } + } + + if( value == HUGE_VAL ) + { + int itable; + char gridlist[3000]; + + proj_log_debug(defn, + "pj_apply_vgridshift(): failed to find a grid shift table for\n" + " location (%.7fdW,%.7fdN)", + x[io] * RAD_TO_DEG, + y[io] * RAD_TO_DEG ); + + gridlist[0] = '\0'; + for( itable = 0; itable < *gridlist_count_p; itable++ ) + { + PJ_GRIDINFO *gi = tables[itable]; + if( strlen(gridlist) + strlen(gi->gridname) > sizeof(gridlist)-100 ) + { + strcat( gridlist, "..." ); + break; + } + + if( itable == 0 ) + sprintf( gridlist, " tried: %s", gi->gridname ); + else + sprintf( gridlist+strlen(gridlist), ",%s", gi->gridname ); + } + + proj_log_debug(defn, "%s", gridlist); + pj_ctx_set_errno( defn->ctx, PJD_ERR_GRID_AREA ); + + return PJD_ERR_GRID_AREA; + } + } + + return 0; +} + +/**********************************************/ +int proj_vgrid_init(PJ* P, const char *grids) { +/********************************************** + + Initizalize and populate gridlist. + + Takes a PJ-object and the plus-parameter + name that is used in the proj-string to + specify the grids to load, e.g. "+grids". + The + should be left out here. + + Returns the number of loaded grids. + +***********************************************/ + + /* prepend "s" to the "grids" string to allow usage with pj_param */ + char *sgrids = (char *) pj_malloc( (strlen(grids)+1+1) *sizeof(char) ); + sprintf(sgrids, "%s%s", "s", grids); + + if (P->vgridlist_geoid == nullptr) { + P->vgridlist_geoid = pj_gridlist_from_nadgrids( + P->ctx, + pj_param(P->ctx, P->params, sgrids).s, + &(P->vgridlist_geoid_count) + ); + + if( P->vgridlist_geoid == nullptr || P->vgridlist_geoid_count == 0 ) { + pj_dealloc(sgrids); + return 0; + } + } + + if (P->vgridlist_geoid_count == 0) { + proj_errno_set(P, PJD_ERR_FAILED_TO_LOAD_GRID); + } + + pj_dealloc(sgrids); + return P->vgridlist_geoid_count; +} + +/***********************************************/ +double proj_vgrid_value(PJ *P, LP lp){ +/*********************************************** + + Read grid value at position lp in grids loaded + with proj_grid_init. + + Returns the grid value of the given coordinate. + +************************************************/ + + struct CTABLE used_grid; + double value; + memset(&used_grid, 0, sizeof(struct CTABLE)); + + value = read_vgrid_value(P, lp, &(P->vgridlist_geoid_count), P->vgridlist_geoid, &used_grid); + proj_log_trace(P, "proj_vgrid_value: (%f, %f) = %f", lp.lam*RAD_TO_DEG, lp.phi*RAD_TO_DEG, value); + + return value; +} diff --git a/src/auth.cpp b/src/auth.cpp new file mode 100644 index 00000000..cde60a29 --- /dev/null +++ b/src/auth.cpp @@ -0,0 +1,36 @@ +/* determine latitude from authalic latitude */ + +#include +#include + +#include "projects.h" + +# define P00 .33333333333333333333 /* 1 / 3 */ +# define P01 .17222222222222222222 /* 31 / 180 */ +# define P02 .10257936507936507937 /* 517 / 5040 */ +# define P10 .06388888888888888888 /* 23 / 360 */ +# define P11 .06640211640211640212 /* 251 / 3780 */ +# define P20 .01677689594356261023 /* 761 / 45360 */ +#define APA_SIZE 3 + + double * +pj_authset(double es) { + double t, *APA; + + if ((APA = (double *)pj_malloc(APA_SIZE * sizeof(double))) != nullptr) { + APA[0] = es * P00; + t = es * es; + APA[0] += t * P01; + APA[1] = t * P10; + t *= es; + APA[0] += t * P02; + APA[1] += t * P11; + APA[2] = t * P20; + } + return APA; +} + double +pj_authlat(double beta, double *APA) { + double t = beta+beta; + return(beta + APA[0] * sin(t) + APA[1] * sin(t+t) + APA[2] * sin(t+t+t)); +} diff --git a/src/conversions/PJ_axisswap.cpp b/src/conversions/PJ_axisswap.cpp deleted file mode 100644 index 8714ec85..00000000 --- a/src/conversions/PJ_axisswap.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/*********************************************************************** - - Axis order operation for use with transformation pipelines. - - Kristian Evers, kreve@sdfe.dk, 2017-10-31 - -************************************************************************ - -Change the order and sign of 2,3 or 4 axes. Each of the possible four -axes are numbered with 1-4, such that the first input axis is 1, the -second is 2 and so on. The output ordering is controlled by a list of the -input axes re-ordered to the new mapping. Examples: - -Reversing the order of the axes: - - +proj=axisswap +order=4,3,2,1 - -Swapping the first two axes (x and y): - - +proj=axisswap +order=2,1,3,4 - -The direction, or sign, of an axis can be changed by adding a minus in -front of the axis-number: - - +proj=axisswap +order=1,-2,3,4 - -It is only necessary to specify the axes that are affected by the swap -operation: - - +proj=axisswap +order=2,1 - -************************************************************************ -* Copyright (c) 2017, Kristian Evers / SDFE -* -* 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_internal.h" -#include "projects.h" - -PROJ_HEAD(axisswap, "Axis ordering"); - -namespace { // anonymous namespace -struct pj_opaque { - unsigned int axis[4]; - int sign[4]; -}; -} // anonymous namespace - -static int sign(int x) { - return (x > 0) - (x < 0); -} - -static XY forward_2d(LP lp, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - unsigned int i; - PJ_COORD out, in; - - in.lp = lp; - out = proj_coord_error(); - - for (i=0; i<2; i++) - out.v[i] = in.v[Q->axis[i]] * Q->sign[i]; - - return out.xy; -} - - -static LP reverse_2d(XY xy, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - unsigned int i; - PJ_COORD out, in; - - in.xy = xy; - out = proj_coord_error(); - - for (i=0; i<2; i++) - out.v[Q->axis[i]] = in.v[i] * Q->sign[i]; - - return out.lp; -} - - -static XYZ forward_3d(LPZ lpz, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - unsigned int i; - PJ_COORD out, in; - - in.lpz = lpz; - out = proj_coord_error(); - - for (i=0; i<3; i++) - out.v[i] = in.v[Q->axis[i]] * Q->sign[i]; - - return out.xyz; -} - -static LPZ reverse_3d(XYZ xyz, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - unsigned int i; - PJ_COORD in, out; - - out = proj_coord_error(); - in.xyz = xyz; - - for (i=0; i<3; i++) - out.v[Q->axis[i]] = in.v[i] * Q->sign[i]; - - return out.lpz; -} - - -static PJ_COORD forward_4d(PJ_COORD coo, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - unsigned int i; - PJ_COORD out; - - out = proj_coord_error(); - - for (i=0; i<4; i++) - out.v[i] = coo.v[Q->axis[i]] * Q->sign[i]; - - return out; -} - - -static PJ_COORD reverse_4d(PJ_COORD coo, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - unsigned int i; - PJ_COORD out; - - out = proj_coord_error(); - - for (i=0; i<4; i++) - out.v[Q->axis[i]] = coo.v[i] * Q->sign[i]; - - return out; -} - - -/***********************************************************************/ -PJ *CONVERSION(axisswap,0) { -/***********************************************************************/ - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - char *s; - unsigned int i, j, n = 0; - - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = (void *) Q; - - - /* +order and +axis are mutually exclusive */ - if ( !pj_param_exists(P->params, "order") == !pj_param_exists(P->params, "axis") ) - return pj_default_destructor(P, PJD_ERR_AXIS); - - /* fill axis list with indices from 4-7 to simplify duplicate search further down */ - for (i=0; i<4; i++) { - Q->axis[i] = i+4; - Q->sign[i] = 1; - } - - /* if the "order" parameter is used */ - if ( pj_param_exists(P->params, "order") ) { - /* read axis order */ - char *order = pj_param(P->ctx, P->params, "sorder").s; - - /* check that all characters are valid */ - for (i=0; iaxis[n] = abs(atoi(s))-1; - if (Q->axis[n] > 3) { - proj_log_error(P, "axisswap: invalid axis '%d'", Q->axis[n]); - return pj_default_destructor(P, PJD_ERR_AXIS); - } - Q->sign[n++] = sign(atoi(s)); - while ( *s != '\0' && *s != ',' ) - s++; - if ( *s == ',' ) - s++; - } - } - - /* if the "axis" parameter is used */ - if ( pj_param_exists(P->params, "axis") ) { - /* parse the classic PROJ.4 enu axis specification */ - for (i=0; i < 3; i++) { - switch(P->axis[i]) { - case 'w': - Q->sign[i] = -1; - Q->axis[i] = 0; - break; - case 'e': - Q->sign[i] = 1; - Q->axis[i] = 0; - break; - case 's': - Q->sign[i] = -1; - Q->axis[i] = 1; - break; - case 'n': - Q->sign[i] = 1; - Q->axis[i] = 1; - break; - case 'd': - Q->sign[i] = -1; - Q->axis[i] = 2; - break; - case 'u': - Q->sign[i] = 1; - Q->axis[i] = 2; - break; - default: - proj_log_error(P, "axisswap: unknown axis '%c'", P->axis[i]); - return pj_default_destructor(P, PJD_ERR_AXIS); - } - } - n = 3; - } - - /* check for duplicate axes */ - for (i=0; i<4; i++) - for (j=0; j<4; j++) { - if (i==j) - continue; - if (Q->axis[i] == Q->axis[j]) { - proj_log_error(P, "swapaxis: duplicate axes specified"); - return pj_default_destructor(P, PJD_ERR_AXIS); - } - } - - - /* only map fwd/inv functions that are possible with the given axis setup */ - if (n == 4) { - P->fwd4d = forward_4d; - P->inv4d = reverse_4d; - } - if (n == 3 && Q->axis[0] < 3 && Q->axis[1] < 3 && Q->axis[2] < 3) { - P->fwd3d = forward_3d; - P->inv3d = reverse_3d; - } - if (n == 2 && Q->axis[0] < 2 && Q->axis[1] < 2) { - P->fwd = forward_2d; - P->inv = reverse_2d; - } - - - if (P->fwd4d == nullptr && P->fwd3d == nullptr && P->fwd == nullptr) { - proj_log_error(P, "swapaxis: bad axis order"); - return pj_default_destructor(P, PJD_ERR_AXIS); - } - - if (pj_param(P->ctx, P->params, "tangularunits").i) { - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_ANGULAR; - } else { - P->left = PJ_IO_UNITS_WHATEVER; - P->right = PJ_IO_UNITS_WHATEVER; - } - - - /* Preparation and finalization steps are skipped, since the raison */ - /* d'etre of axisswap is to bring input coordinates in line with the */ - /* the internally expected order (ENU), such that handling of offsets */ - /* etc. can be done correctly in a later step of a pipeline */ - P->skip_fwd_prepare = 1; - P->skip_fwd_finalize = 1; - P->skip_inv_prepare = 1; - P->skip_inv_finalize = 1; - - return P; -} diff --git a/src/conversions/PJ_cart.cpp b/src/conversions/PJ_cart.cpp deleted file mode 100644 index 6fed9985..00000000 --- a/src/conversions/PJ_cart.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Convert between ellipsoidal, geodetic coordinates and - * cartesian, geocentric coordinates. - * - * Formally, this functionality is also found in the PJ_geocent.c - * code. - * - * Actually, however, the PJ_geocent transformations are carried - * out in concert between 2D stubs in PJ_geocent.c and 3D code - * placed in pj_transform.c. - * - * For pipeline-style datum shifts, we do need direct access - * to the full 3D interface for this functionality. - * - * Hence this code, which may look like "just another PJ_geocent" - * but really is something substantially different. - * - * Author: Thomas Knudsen, thokn@sdfe.dk - * - ****************************************************************************** - * Copyright (c) 2016, Thomas Knudsen / SDFE - * - * 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_internal.h" -#include "projects.h" -#include "proj_math.h" - -PROJ_HEAD(cart, "Geodetic/cartesian conversions"); - - -/************************************************************** - CARTESIAN / GEODETIC CONVERSIONS -*************************************************************** - This material follows: - - Bernhard Hofmann-Wellenhof & Helmut Moritz: - Physical Geodesy, 2nd edition. - Springer, 2005. - - chapter 5.6: Coordinate transformations - (HM, below), - - and - - Wikipedia: Geographic Coordinate Conversion, - https://en.wikipedia.org/wiki/Geographic_coordinate_conversion - - (WP, below). - - The cartesian-to-geodetic conversion is based on Bowring's - celebrated method: - - B. R. Bowring: - Transformation from spatial to geographical coordinates - Survey Review 23(181), pp. 323-327, 1976 - - (BB, below), - - but could probably use some TLC from a newer and faster - algorithm: - - Toshio Fukushima: - Transformation from Cartesian to Geodetic Coordinates - Accelerated by Halley’s Method - Journal of Geodesy, February 2006 - - (TF, below). - - Close to the poles, we avoid singularities by switching to an - approximation requiring knowledge of the geocentric radius - at the given latitude. For this, we use an adaptation of the - formula given in: - - Wikipedia: Earth Radius - https://en.wikipedia.org/wiki/Earth_radius#Radius_at_a_given_geodetic_latitude - (Derivation and commentary at https://gis.stackexchange.com/q/20200) - - (WP2, below) - - These routines are probably not as robust at those in - geocent.c, at least thay haven't been through as heavy - use as their geocent sisters. Some care has been taken - to avoid singularities, but extreme cases (e.g. setting - es, the squared eccentricity, to 1), will cause havoc. - -**************************************************************/ - - -/*********************************************************************/ -static double normal_radius_of_curvature (double a, double es, double phi) { -/*********************************************************************/ - double s = sin(phi); - if (es==0) - return a; - /* This is from WP. HM formula 2-149 gives an a,b version */ - return a / sqrt (1 - es*s*s); -} - -/*********************************************************************/ -static double geocentric_radius (double a, double b, double phi) { -/********************************************************************* - Return the geocentric radius at latitude phi, of an ellipsoid - with semimajor axis a and semiminor axis b. - - This is from WP2, but uses hypot() for potentially better - numerical robustness -***********************************************************************/ - return hypot (a*a*cos (phi), b*b*sin(phi)) / hypot (a*cos(phi), b*sin(phi)); -} - - -/*********************************************************************/ -static XYZ cartesian (LPZ geod, PJ *P) { -/*********************************************************************/ - double N, cosphi = cos(geod.phi); - XYZ xyz; - - N = normal_radius_of_curvature(P->a, P->es, geod.phi); - - /* HM formula 5-27 (z formula follows WP) */ - xyz.x = (N + geod.z) * cosphi * cos(geod.lam); - xyz.y = (N + geod.z) * cosphi * sin(geod.lam); - xyz.z = (N * (1 - P->es) + geod.z) * sin(geod.phi); - - return xyz; -} - - -/*********************************************************************/ -static LPZ geodetic (XYZ cart, PJ *P) { -/*********************************************************************/ - double N, p, theta, c, s; - LPZ lpz; - - /* Perpendicular distance from point to Z-axis (HM eq. 5-28) */ - p = hypot (cart.x, cart.y); - - /* HM eq. (5-37) */ - theta = atan2 (cart.z * P->a, p * P->b); - - /* HM eq. (5-36) (from BB, 1976) */ - c = cos(theta); - s = sin(theta); - lpz.phi = atan2 (cart.z + P->e2s*P->b*s*s*s, p - P->es*P->a*c*c*c); - lpz.lam = atan2 (cart.y, cart.x); - N = normal_radius_of_curvature (P->a, P->es, lpz.phi); - - - c = cos(lpz.phi); - if (fabs(c) < 1e-6) { - /* poleward of 89.99994 deg, we avoid division by zero */ - /* by computing the height as the cartesian z value */ - /* minus the geocentric radius of the Earth at the given */ - /* latitude */ - double r = geocentric_radius (P->a, P->b, lpz.phi); - lpz.z = fabs (cart.z) - r; - } - else - lpz.z = p / c - N; - - return lpz; -} - - - -/* In effect, 2 cartesian coordinates of a point on the ellipsoid. Rather pointless, but... */ -static XY cart_forward (LP lp, PJ *P) { - PJ_COORD point; - point.lp = lp; - point.lpz.z = 0; - - point.xyz = cartesian (point.lpz, P); - return point.xy; -} - -/* And the other way round. Still rather pointless, but... */ -static LP cart_reverse (XY xy, PJ *P) { - PJ_COORD point; - point.xy = xy; - point.xyz.z = 0; - - point.lpz = geodetic (point.xyz, P); - return point.lp; -} - - - -/*********************************************************************/ -PJ *CONVERSION(cart,1) { -/*********************************************************************/ - P->fwd3d = cartesian; - P->inv3d = geodetic; - P->fwd = cart_forward; - P->inv = cart_reverse; - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_CARTESIAN; - return P; -} diff --git a/src/conversions/PJ_geoc.cpp b/src/conversions/PJ_geoc.cpp deleted file mode 100644 index 0455fada..00000000 --- a/src/conversions/PJ_geoc.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Conversion from geographic to geocentric latitude and back. - * Author: Thomas Knudsen (2017) - * - ****************************************************************************** - * Copyright (c) 2017, SDFE, http://www.sdfe.dk - * Copyright (c) 2017, Thomas Knudsen - * - * 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 "proj_internal.h" -#include "projects.h" - -PROJ_HEAD(geoc, "Geocentric Latitude"); - -/* Geographical to geocentric */ -static PJ_COORD forward(PJ_COORD coo, PJ *P) { - return pj_geocentric_latitude (P, PJ_FWD, coo); -} - -/* Geocentric to geographical */ -static PJ_COORD inverse(PJ_COORD coo, PJ *P) { - return pj_geocentric_latitude (P, PJ_INV, coo); -} - - -static PJ *CONVERSION(geoc, 1) { - P->inv4d = inverse; - P->fwd4d = forward; - - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_ANGULAR; - - P->is_latlong = 1; - return P; -} diff --git a/src/conversions/PJ_unitconvert.cpp b/src/conversions/PJ_unitconvert.cpp deleted file mode 100644 index b25fd5d2..00000000 --- a/src/conversions/PJ_unitconvert.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/*********************************************************************** - - Unit conversion pseudo-projection for use with - transformation pipelines. - - Kristian Evers, 2017-05-16 - -************************************************************************ - -A pseudo-projection that can be used to convert units of input and -output data. Primarily useful in pipelines. - -Unit conversion is performed by means of a pivot unit. The pivot unit -for distance units are the meter and for time we use the modified julian -date. A time unit conversion is performed like - - Unit A -> Modified Julian date -> Unit B - -distance units are converted in the same manner, with meter being the -central unit. - -The modified Julian date is chosen as the pivot unit since it has a -fairly high precision, goes sufficiently long backwards in time, has no -danger of hitting the upper limit in the near future and it is a fairly -common time unit in astronomy and geodesy. Note that we are using the -Julian date and not day. The difference being that the latter is defined -as an integer and is thus limited to days in resolution. This approach -has been extended wherever it makes sense, e.g. the GPS week unit also -has a fractional part that makes it possible to determine the day, hour -and minute of an observation. - -In- and output units are controlled with the parameters - - +xy_in, +xy_out, +z_in, +z_out, +t_in and +t_out - -where xy denotes horizontal units, z vertical units and t time units. - -************************************************************************ - -Kristian Evers, kreve@sdfe.dk, 2017-05-09 -Last update: 2017-05-16 - -************************************************************************ -* Copyright (c) 2017, Kristian Evers / SDFE -* -* 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 - -#include "proj_internal.h" -#include "proj_math.h" -#include "projects.h" - -PROJ_HEAD(unitconvert, "Unit conversion"); - -typedef double (*tconvert)(double); - -namespace { // anonymous namespace -struct TIME_UNITS { - const char *id; /* units keyword */ - tconvert t_in; /* unit -> mod. julian date function pointer */ - tconvert t_out; /* mod. julian date > unit function pointer */ - const char *name; /* comments */ -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque_unitconvert { - int t_in_id; /* time unit id for the time input unit */ - int t_out_id; /* time unit id for the time output unit */ - double xy_factor; /* unit conversion factor for horizontal components */ - double z_factor; /* unit conversion factor for vertical components */ -}; -} // anonymous namespace - - -/***********************************************************************/ -static int is_leap_year(long year) { -/***********************************************************************/ - return ((year % 4 == 0 && year % 100 != 0) || year % 400 ==0); -} - - -/***********************************************************************/ -static int days_in_year(long year) { -/***********************************************************************/ - return is_leap_year(year) ? 366 : 365; -} - -/***********************************************************************/ -static unsigned int days_in_month(unsigned long year, unsigned long month) { -/***********************************************************************/ - const unsigned int month_table[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - unsigned int days; - - if (month > 12) month = 12; - if (month == 0) month = 1; - - days = month_table[month-1]; - if (is_leap_year(year) && month == 2) days++; - - return days; -} - - -/***********************************************************************/ -static int daynumber_in_year(unsigned long year, unsigned long month, unsigned long day) { -/***********************************************************************/ - unsigned int daynumber=0, i; - - if (month > 12) month = 12; - if (month == 0) month = 1; - if (day > days_in_month(year, month)) day = days_in_month(year, month); - - for (i = 1; i < month; i++) - daynumber += days_in_month(year, i); - - daynumber += day; - - return daynumber; - -} - -/***********************************************************************/ -static double mjd_to_mjd(double mjd) { -/*********************************************************************** - Modified julian date no-op function. - - The Julian date is defined as (fractional) days since midnight - on 16th of November in 1858. -************************************************************************/ - return mjd; -} - - -/***********************************************************************/ -static double decimalyear_to_mjd(double decimalyear) { -/*********************************************************************** - Epoch of modified julian date is 1858-11-16 00:00 -************************************************************************/ - long year; - double fractional_year; - double mjd; - - if( decimalyear < -10000 || decimalyear > 10000 ) - return 0; - - year = lround(floor(decimalyear)); - fractional_year = decimalyear - year; - mjd = (year - 1859)*365 + 14 + 31; - mjd += (double)fractional_year*(double)days_in_year(year); - - /* take care of leap days */ - year--; - for (; year > 1858; year--) - if (is_leap_year(year)) - mjd++; - - return mjd; -} - - -/***********************************************************************/ -static double mjd_to_decimalyear(double mjd) { -/*********************************************************************** - Epoch of modified julian date is 1858-11-16 00:00 -************************************************************************/ - double decimalyear = mjd; - double mjd_iter = 14 + 31; - int year = 1859; - - /* a smarter brain than mine could probably to do this more elegantly - - I'll just brute-force my way out of this... */ - for (; mjd >= mjd_iter; year++) { - mjd_iter += days_in_year(year); - } - year--; - mjd_iter -= days_in_year(year); - - decimalyear = year + (mjd-mjd_iter)/days_in_year(year); - return decimalyear; -} - - -/***********************************************************************/ -static double gps_week_to_mjd(double gps_week) { -/*********************************************************************** - GPS weeks are defined as the number of weeks since January the 6th - 1980. - - Epoch of gps weeks is 1980-01-06 00:00, which in modified Julian - date is 44244. -************************************************************************/ - return 44244.0 + gps_week*7.0; -} - - -/***********************************************************************/ -static double mjd_to_gps_week(double mjd) { -/*********************************************************************** - GPS weeks are defined as the number of weeks since January the 6th - 1980. - - Epoch of gps weeks is 1980-01-06 00:00, which in modified Julian - date is 44244. -************************************************************************/ - return (mjd - 44244.0) / 7.0; -} - - -/***********************************************************************/ -static double yyyymmdd_to_mjd(double yyyymmdd) { -/************************************************************************ - Date given in YYYY-MM-DD format. -************************************************************************/ - - long year = lround(floor( yyyymmdd / 10000 )); - long month = lround(floor((yyyymmdd - year*10000) / 100)); - long day = lround(floor( yyyymmdd - year*10000 - month*100)); - double mjd = daynumber_in_year(year, month, day); - - for (year -= 1; year > 1858; year--) - mjd += days_in_year(year); - - return mjd + 13 + 31; -} - - -/***********************************************************************/ -static double mjd_to_yyyymmdd(double mjd) { -/************************************************************************ - Date given in YYYY-MM-DD format. -************************************************************************/ - double mjd_iter = 14 + 31; - int year = 1859, month=0, day=0; - - for (; mjd >= mjd_iter; year++) { - mjd_iter += days_in_year(year); - } - year--; - mjd_iter -= days_in_year(year); - - for (month=1; mjd_iter + days_in_month(year, month) <= mjd; month++) - mjd_iter += days_in_month(year, month); - - day = (int)(mjd - mjd_iter + 1); - - return year*10000.0 + month*100.0 + day; -} - -static const struct TIME_UNITS time_units[] = { - {"mjd", mjd_to_mjd, mjd_to_mjd, "Modified julian date"}, - {"decimalyear", decimalyear_to_mjd, mjd_to_decimalyear, "Decimal year"}, - {"gps_week", gps_week_to_mjd, mjd_to_gps_week, "GPS Week"}, - {"yyyymmdd", yyyymmdd_to_mjd, mjd_to_yyyymmdd, "YYYYMMDD date"}, - {nullptr, nullptr, nullptr, nullptr} -}; - - -/***********************************************************************/ -static XY forward_2d(LP lp, PJ *P) { -/************************************************************************ - Forward unit conversions in the plane -************************************************************************/ - struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - point.lp = lp; - - point.xy.x *= Q->xy_factor; - point.xy.y *= Q->xy_factor; - - return point.xy; -} - - -/***********************************************************************/ -static LP reverse_2d(XY xy, PJ *P) { -/************************************************************************ - Reverse unit conversions in the plane -************************************************************************/ - struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - point.xy = xy; - - point.xy.x /= Q->xy_factor; - point.xy.y /= Q->xy_factor; - - return point.lp; -} - - -/***********************************************************************/ -static XYZ forward_3d(LPZ lpz, PJ *P) { -/************************************************************************ - Forward unit conversions the vertical component -************************************************************************/ - struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - point.lpz = lpz; - - /* take care of the horizontal components in the 2D function */ - point.xy = forward_2d(point.lp, P); - - point.xyz.z *= Q->z_factor; - - return point.xyz; -} - -/***********************************************************************/ -static LPZ reverse_3d(XYZ xyz, PJ *P) { -/************************************************************************ - Reverse unit conversions the vertical component -************************************************************************/ - struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - point.xyz = xyz; - - /* take care of the horizontal components in the 2D function */ - point.lp = reverse_2d(point.xy, P); - - point.xyz.z /= Q->z_factor; - - return point.lpz; -} - - -/***********************************************************************/ -static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { -/************************************************************************ - Forward conversion of time units -************************************************************************/ - struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; - PJ_COORD out = obs; - - /* delegate unit conversion of physical dimensions to the 3D function */ - out.xyz = forward_3d(obs.lpz, P); - - if (Q->t_in_id >= 0) - out.xyzt.t = time_units[Q->t_in_id].t_in( obs.xyzt.t ); - if (Q->t_out_id >= 0) - out.xyzt.t = time_units[Q->t_out_id].t_out( out.xyzt.t ); - - return out; -} - - -/***********************************************************************/ -static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { -/************************************************************************ - Reverse conversion of time units -************************************************************************/ - struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; - PJ_COORD out = obs; - - /* delegate unit conversion of physical dimensions to the 3D function */ - out.lpz = reverse_3d(obs.xyz, P); - - if (Q->t_out_id >= 0) - out.xyzt.t = time_units[Q->t_out_id].t_in( obs.xyzt.t ); - if (Q->t_in_id >= 0) - out.xyzt.t = time_units[Q->t_in_id].t_out( out.xyzt.t ); - - return out; -} - -/***********************************************************************/ -static double get_unit_conversion_factor(const char* name, - int* p_is_linear, - const char** p_normalized_name) { -/***********************************************************************/ - int i; - const char* s; - const PJ_UNITS *units; - - units = proj_list_units(); - - /* Try first with linear units */ - for (i = 0; (s = units[i].id) ; ++i) { - if ( strcmp(s, name) == 0 ) { - if( p_normalized_name ) { - *p_normalized_name = units[i].name; - } - if( p_is_linear ) { - *p_is_linear = 1; - } - return units[i].factor; - } - } - - /* And then angular units */ - units = proj_list_angular_units(); - for (i = 0; (s = units[i].id) ; ++i) { - if ( strcmp(s, name) == 0 ) { - if( p_normalized_name ) { - *p_normalized_name = units[i].name; - } - if( p_is_linear ) { - *p_is_linear = 0; - } - return units[i].factor; - } - } - if( p_normalized_name ) { - *p_normalized_name = nullptr; - } - if( p_is_linear ) { - *p_is_linear = -1; - } - return 0.0; -} - -/***********************************************************************/ -PJ *CONVERSION(unitconvert,0) { -/***********************************************************************/ - struct pj_opaque_unitconvert *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque_unitconvert))); - const char *s, *name; - int i; - double f; - int xy_in_is_linear = -1; /* unknown */ - int xy_out_is_linear = -1; /* unknown */ - int z_in_is_linear = -1; /* unknown */ - int z_out_is_linear = -1; /* unknown */ - - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = (void *) Q; - - P->fwd4d = forward_4d; - P->inv4d = reverse_4d; - P->fwd3d = forward_3d; - P->inv3d = reverse_3d; - P->fwd = forward_2d; - P->inv = reverse_2d; - - P->left = PJ_IO_UNITS_WHATEVER; - P->right = PJ_IO_UNITS_WHATEVER; - - /* if no time input/output unit is specified we can skip them */ - Q->t_in_id = -1; - Q->t_out_id = -1; - - Q->xy_factor = 1.0; - Q->z_factor = 1.0; - - if ((name = pj_param (P->ctx, P->params, "sxy_in").s) != nullptr) { - const char* normalized_name = nullptr; - f = get_unit_conversion_factor(name, &xy_in_is_linear, &normalized_name); - if (f != 0.0) { - proj_log_debug(P, "xy_in unit: %s", normalized_name); - } else { - if ( (f = pj_param (P->ctx, P->params, "dxy_in").f) == 0.0) - return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); - } - if (f != 0.0) - Q->xy_factor *= f; - } - - if ((name = pj_param (P->ctx, P->params, "sxy_out").s) != nullptr) { - const char* normalized_name = nullptr; - f = get_unit_conversion_factor(name, &xy_out_is_linear, &normalized_name); - if (f != 0.0) { - proj_log_debug(P, "xy_out unit: %s", normalized_name); - } else { - if ( (f = pj_param (P->ctx, P->params, "dxy_out").f) == 0.0) - return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); - } - if (f != 0.0) - Q->xy_factor /= f; - } - - if( xy_in_is_linear >= 0 && xy_out_is_linear >= 0 && - xy_in_is_linear != xy_out_is_linear ) { - proj_log_debug(P, "inconsistent unit type between xy_in and xy_out"); - return pj_default_destructor(P, PJD_ERR_INCONSISTENT_UNIT); - } - - if ((name = pj_param (P->ctx, P->params, "sz_in").s) != nullptr) { - const char* normalized_name = nullptr; - f = get_unit_conversion_factor(name, &z_in_is_linear, &normalized_name); - if (f != 0.0) { - proj_log_debug(P, "z_in unit: %s", normalized_name); - } else { - if ( (f = pj_param (P->ctx, P->params, "dz_in").f) == 0.0) - return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); - } - if (f != 0.0) - Q->z_factor *= f; - } - - if ((name = pj_param (P->ctx, P->params, "sz_out").s) != nullptr) { - const char* normalized_name = nullptr; - f = get_unit_conversion_factor(name, &z_out_is_linear, &normalized_name); - if (f != 0.0) { - proj_log_debug(P, "z_out unit: %s", normalized_name); - } else { - if ( (f = pj_param (P->ctx, P->params, "dz_out").f) == 0.0) - return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); - } - if (f != 0.0) - Q->z_factor /= f; - } - - if( z_in_is_linear >= 0 && z_out_is_linear >= 0 && - z_in_is_linear != z_out_is_linear ) { - proj_log_debug(P, "inconsistent unit type between z_in and z_out"); - return pj_default_destructor(P, PJD_ERR_INCONSISTENT_UNIT); - } - - if ((name = pj_param (P->ctx, P->params, "st_in").s) != nullptr) { - for (i = 0; (s = time_units[i].id) && strcmp(name, s) ; ++i); - - if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); /* unknown unit conversion id */ - - Q->t_in_id = i; - proj_log_debug(P, "t_in unit: %s", time_units[i].name); - } - - s = nullptr; - if ((name = pj_param (P->ctx, P->params, "st_out").s) != nullptr) { - for (i = 0; (s = time_units[i].id) && strcmp(name, s) ; ++i); - - if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); /* unknown unit conversion id */ - - Q->t_out_id = i; - proj_log_debug(P, "t_out unit: %s", time_units[i].name); - } - - return P; -} diff --git a/src/conversions/axisswap.cpp b/src/conversions/axisswap.cpp new file mode 100644 index 00000000..8714ec85 --- /dev/null +++ b/src/conversions/axisswap.cpp @@ -0,0 +1,302 @@ +/*********************************************************************** + + Axis order operation for use with transformation pipelines. + + Kristian Evers, kreve@sdfe.dk, 2017-10-31 + +************************************************************************ + +Change the order and sign of 2,3 or 4 axes. Each of the possible four +axes are numbered with 1-4, such that the first input axis is 1, the +second is 2 and so on. The output ordering is controlled by a list of the +input axes re-ordered to the new mapping. Examples: + +Reversing the order of the axes: + + +proj=axisswap +order=4,3,2,1 + +Swapping the first two axes (x and y): + + +proj=axisswap +order=2,1,3,4 + +The direction, or sign, of an axis can be changed by adding a minus in +front of the axis-number: + + +proj=axisswap +order=1,-2,3,4 + +It is only necessary to specify the axes that are affected by the swap +operation: + + +proj=axisswap +order=2,1 + +************************************************************************ +* Copyright (c) 2017, Kristian Evers / SDFE +* +* 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_internal.h" +#include "projects.h" + +PROJ_HEAD(axisswap, "Axis ordering"); + +namespace { // anonymous namespace +struct pj_opaque { + unsigned int axis[4]; + int sign[4]; +}; +} // anonymous namespace + +static int sign(int x) { + return (x > 0) - (x < 0); +} + +static XY forward_2d(LP lp, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + unsigned int i; + PJ_COORD out, in; + + in.lp = lp; + out = proj_coord_error(); + + for (i=0; i<2; i++) + out.v[i] = in.v[Q->axis[i]] * Q->sign[i]; + + return out.xy; +} + + +static LP reverse_2d(XY xy, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + unsigned int i; + PJ_COORD out, in; + + in.xy = xy; + out = proj_coord_error(); + + for (i=0; i<2; i++) + out.v[Q->axis[i]] = in.v[i] * Q->sign[i]; + + return out.lp; +} + + +static XYZ forward_3d(LPZ lpz, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + unsigned int i; + PJ_COORD out, in; + + in.lpz = lpz; + out = proj_coord_error(); + + for (i=0; i<3; i++) + out.v[i] = in.v[Q->axis[i]] * Q->sign[i]; + + return out.xyz; +} + +static LPZ reverse_3d(XYZ xyz, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + unsigned int i; + PJ_COORD in, out; + + out = proj_coord_error(); + in.xyz = xyz; + + for (i=0; i<3; i++) + out.v[Q->axis[i]] = in.v[i] * Q->sign[i]; + + return out.lpz; +} + + +static PJ_COORD forward_4d(PJ_COORD coo, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + unsigned int i; + PJ_COORD out; + + out = proj_coord_error(); + + for (i=0; i<4; i++) + out.v[i] = coo.v[Q->axis[i]] * Q->sign[i]; + + return out; +} + + +static PJ_COORD reverse_4d(PJ_COORD coo, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + unsigned int i; + PJ_COORD out; + + out = proj_coord_error(); + + for (i=0; i<4; i++) + out.v[Q->axis[i]] = coo.v[i] * Q->sign[i]; + + return out; +} + + +/***********************************************************************/ +PJ *CONVERSION(axisswap,0) { +/***********************************************************************/ + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + char *s; + unsigned int i, j, n = 0; + + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = (void *) Q; + + + /* +order and +axis are mutually exclusive */ + if ( !pj_param_exists(P->params, "order") == !pj_param_exists(P->params, "axis") ) + return pj_default_destructor(P, PJD_ERR_AXIS); + + /* fill axis list with indices from 4-7 to simplify duplicate search further down */ + for (i=0; i<4; i++) { + Q->axis[i] = i+4; + Q->sign[i] = 1; + } + + /* if the "order" parameter is used */ + if ( pj_param_exists(P->params, "order") ) { + /* read axis order */ + char *order = pj_param(P->ctx, P->params, "sorder").s; + + /* check that all characters are valid */ + for (i=0; iaxis[n] = abs(atoi(s))-1; + if (Q->axis[n] > 3) { + proj_log_error(P, "axisswap: invalid axis '%d'", Q->axis[n]); + return pj_default_destructor(P, PJD_ERR_AXIS); + } + Q->sign[n++] = sign(atoi(s)); + while ( *s != '\0' && *s != ',' ) + s++; + if ( *s == ',' ) + s++; + } + } + + /* if the "axis" parameter is used */ + if ( pj_param_exists(P->params, "axis") ) { + /* parse the classic PROJ.4 enu axis specification */ + for (i=0; i < 3; i++) { + switch(P->axis[i]) { + case 'w': + Q->sign[i] = -1; + Q->axis[i] = 0; + break; + case 'e': + Q->sign[i] = 1; + Q->axis[i] = 0; + break; + case 's': + Q->sign[i] = -1; + Q->axis[i] = 1; + break; + case 'n': + Q->sign[i] = 1; + Q->axis[i] = 1; + break; + case 'd': + Q->sign[i] = -1; + Q->axis[i] = 2; + break; + case 'u': + Q->sign[i] = 1; + Q->axis[i] = 2; + break; + default: + proj_log_error(P, "axisswap: unknown axis '%c'", P->axis[i]); + return pj_default_destructor(P, PJD_ERR_AXIS); + } + } + n = 3; + } + + /* check for duplicate axes */ + for (i=0; i<4; i++) + for (j=0; j<4; j++) { + if (i==j) + continue; + if (Q->axis[i] == Q->axis[j]) { + proj_log_error(P, "swapaxis: duplicate axes specified"); + return pj_default_destructor(P, PJD_ERR_AXIS); + } + } + + + /* only map fwd/inv functions that are possible with the given axis setup */ + if (n == 4) { + P->fwd4d = forward_4d; + P->inv4d = reverse_4d; + } + if (n == 3 && Q->axis[0] < 3 && Q->axis[1] < 3 && Q->axis[2] < 3) { + P->fwd3d = forward_3d; + P->inv3d = reverse_3d; + } + if (n == 2 && Q->axis[0] < 2 && Q->axis[1] < 2) { + P->fwd = forward_2d; + P->inv = reverse_2d; + } + + + if (P->fwd4d == nullptr && P->fwd3d == nullptr && P->fwd == nullptr) { + proj_log_error(P, "swapaxis: bad axis order"); + return pj_default_destructor(P, PJD_ERR_AXIS); + } + + if (pj_param(P->ctx, P->params, "tangularunits").i) { + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_ANGULAR; + } else { + P->left = PJ_IO_UNITS_WHATEVER; + P->right = PJ_IO_UNITS_WHATEVER; + } + + + /* Preparation and finalization steps are skipped, since the raison */ + /* d'etre of axisswap is to bring input coordinates in line with the */ + /* the internally expected order (ENU), such that handling of offsets */ + /* etc. can be done correctly in a later step of a pipeline */ + P->skip_fwd_prepare = 1; + P->skip_fwd_finalize = 1; + P->skip_inv_prepare = 1; + P->skip_inv_finalize = 1; + + return P; +} diff --git a/src/conversions/cart.cpp b/src/conversions/cart.cpp new file mode 100644 index 00000000..6fed9985 --- /dev/null +++ b/src/conversions/cart.cpp @@ -0,0 +1,219 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Convert between ellipsoidal, geodetic coordinates and + * cartesian, geocentric coordinates. + * + * Formally, this functionality is also found in the PJ_geocent.c + * code. + * + * Actually, however, the PJ_geocent transformations are carried + * out in concert between 2D stubs in PJ_geocent.c and 3D code + * placed in pj_transform.c. + * + * For pipeline-style datum shifts, we do need direct access + * to the full 3D interface for this functionality. + * + * Hence this code, which may look like "just another PJ_geocent" + * but really is something substantially different. + * + * Author: Thomas Knudsen, thokn@sdfe.dk + * + ****************************************************************************** + * Copyright (c) 2016, Thomas Knudsen / SDFE + * + * 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_internal.h" +#include "projects.h" +#include "proj_math.h" + +PROJ_HEAD(cart, "Geodetic/cartesian conversions"); + + +/************************************************************** + CARTESIAN / GEODETIC CONVERSIONS +*************************************************************** + This material follows: + + Bernhard Hofmann-Wellenhof & Helmut Moritz: + Physical Geodesy, 2nd edition. + Springer, 2005. + + chapter 5.6: Coordinate transformations + (HM, below), + + and + + Wikipedia: Geographic Coordinate Conversion, + https://en.wikipedia.org/wiki/Geographic_coordinate_conversion + + (WP, below). + + The cartesian-to-geodetic conversion is based on Bowring's + celebrated method: + + B. R. Bowring: + Transformation from spatial to geographical coordinates + Survey Review 23(181), pp. 323-327, 1976 + + (BB, below), + + but could probably use some TLC from a newer and faster + algorithm: + + Toshio Fukushima: + Transformation from Cartesian to Geodetic Coordinates + Accelerated by Halley’s Method + Journal of Geodesy, February 2006 + + (TF, below). + + Close to the poles, we avoid singularities by switching to an + approximation requiring knowledge of the geocentric radius + at the given latitude. For this, we use an adaptation of the + formula given in: + + Wikipedia: Earth Radius + https://en.wikipedia.org/wiki/Earth_radius#Radius_at_a_given_geodetic_latitude + (Derivation and commentary at https://gis.stackexchange.com/q/20200) + + (WP2, below) + + These routines are probably not as robust at those in + geocent.c, at least thay haven't been through as heavy + use as their geocent sisters. Some care has been taken + to avoid singularities, but extreme cases (e.g. setting + es, the squared eccentricity, to 1), will cause havoc. + +**************************************************************/ + + +/*********************************************************************/ +static double normal_radius_of_curvature (double a, double es, double phi) { +/*********************************************************************/ + double s = sin(phi); + if (es==0) + return a; + /* This is from WP. HM formula 2-149 gives an a,b version */ + return a / sqrt (1 - es*s*s); +} + +/*********************************************************************/ +static double geocentric_radius (double a, double b, double phi) { +/********************************************************************* + Return the geocentric radius at latitude phi, of an ellipsoid + with semimajor axis a and semiminor axis b. + + This is from WP2, but uses hypot() for potentially better + numerical robustness +***********************************************************************/ + return hypot (a*a*cos (phi), b*b*sin(phi)) / hypot (a*cos(phi), b*sin(phi)); +} + + +/*********************************************************************/ +static XYZ cartesian (LPZ geod, PJ *P) { +/*********************************************************************/ + double N, cosphi = cos(geod.phi); + XYZ xyz; + + N = normal_radius_of_curvature(P->a, P->es, geod.phi); + + /* HM formula 5-27 (z formula follows WP) */ + xyz.x = (N + geod.z) * cosphi * cos(geod.lam); + xyz.y = (N + geod.z) * cosphi * sin(geod.lam); + xyz.z = (N * (1 - P->es) + geod.z) * sin(geod.phi); + + return xyz; +} + + +/*********************************************************************/ +static LPZ geodetic (XYZ cart, PJ *P) { +/*********************************************************************/ + double N, p, theta, c, s; + LPZ lpz; + + /* Perpendicular distance from point to Z-axis (HM eq. 5-28) */ + p = hypot (cart.x, cart.y); + + /* HM eq. (5-37) */ + theta = atan2 (cart.z * P->a, p * P->b); + + /* HM eq. (5-36) (from BB, 1976) */ + c = cos(theta); + s = sin(theta); + lpz.phi = atan2 (cart.z + P->e2s*P->b*s*s*s, p - P->es*P->a*c*c*c); + lpz.lam = atan2 (cart.y, cart.x); + N = normal_radius_of_curvature (P->a, P->es, lpz.phi); + + + c = cos(lpz.phi); + if (fabs(c) < 1e-6) { + /* poleward of 89.99994 deg, we avoid division by zero */ + /* by computing the height as the cartesian z value */ + /* minus the geocentric radius of the Earth at the given */ + /* latitude */ + double r = geocentric_radius (P->a, P->b, lpz.phi); + lpz.z = fabs (cart.z) - r; + } + else + lpz.z = p / c - N; + + return lpz; +} + + + +/* In effect, 2 cartesian coordinates of a point on the ellipsoid. Rather pointless, but... */ +static XY cart_forward (LP lp, PJ *P) { + PJ_COORD point; + point.lp = lp; + point.lpz.z = 0; + + point.xyz = cartesian (point.lpz, P); + return point.xy; +} + +/* And the other way round. Still rather pointless, but... */ +static LP cart_reverse (XY xy, PJ *P) { + PJ_COORD point; + point.xy = xy; + point.xyz.z = 0; + + point.lpz = geodetic (point.xyz, P); + return point.lp; +} + + + +/*********************************************************************/ +PJ *CONVERSION(cart,1) { +/*********************************************************************/ + P->fwd3d = cartesian; + P->inv3d = geodetic; + P->fwd = cart_forward; + P->inv = cart_reverse; + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_CARTESIAN; + return P; +} diff --git a/src/conversions/geoc.cpp b/src/conversions/geoc.cpp new file mode 100644 index 00000000..0455fada --- /dev/null +++ b/src/conversions/geoc.cpp @@ -0,0 +1,59 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Conversion from geographic to geocentric latitude and back. + * Author: Thomas Knudsen (2017) + * + ****************************************************************************** + * Copyright (c) 2017, SDFE, http://www.sdfe.dk + * Copyright (c) 2017, Thomas Knudsen + * + * 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 "proj_internal.h" +#include "projects.h" + +PROJ_HEAD(geoc, "Geocentric Latitude"); + +/* Geographical to geocentric */ +static PJ_COORD forward(PJ_COORD coo, PJ *P) { + return pj_geocentric_latitude (P, PJ_FWD, coo); +} + +/* Geocentric to geographical */ +static PJ_COORD inverse(PJ_COORD coo, PJ *P) { + return pj_geocentric_latitude (P, PJ_INV, coo); +} + + +static PJ *CONVERSION(geoc, 1) { + P->inv4d = inverse; + P->fwd4d = forward; + + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_ANGULAR; + + P->is_latlong = 1; + return P; +} diff --git a/src/conversions/geocent.cpp b/src/conversions/geocent.cpp new file mode 100644 index 00000000..0e9d725e --- /dev/null +++ b/src/conversions/geocent.cpp @@ -0,0 +1,62 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Stub projection for geocentric. The transformation isn't + * really done here since this code is 2D. The real transformation + * is handled by pj_transform.c. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2002, 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. + *****************************************************************************/ + +#define PJ_LIB__ +#include "projects.h" + +PROJ_HEAD(geocent, "Geocentric") "\n\t"; + +static XY 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 inverse(XY xy, PJ *P) { + LP lp = {0.0,0.0}; + (void) P; + lp.phi = xy.y; + lp.lam = xy.x; + return lp; +} + +PJ *CONVERSION (geocent, 0) { + P->is_geocent = 1; + P->x0 = 0.0; + P->y0 = 0.0; + P->inv = inverse; + P->fwd = forward; + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_CARTESIAN; + + return P; +} + diff --git a/src/conversions/pj_geocent.cpp b/src/conversions/pj_geocent.cpp deleted file mode 100644 index 0e9d725e..00000000 --- a/src/conversions/pj_geocent.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Stub projection for geocentric. The transformation isn't - * really done here since this code is 2D. The real transformation - * is handled by pj_transform.c. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2002, 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. - *****************************************************************************/ - -#define PJ_LIB__ -#include "projects.h" - -PROJ_HEAD(geocent, "Geocentric") "\n\t"; - -static XY 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 inverse(XY xy, PJ *P) { - LP lp = {0.0,0.0}; - (void) P; - lp.phi = xy.y; - lp.lam = xy.x; - return lp; -} - -PJ *CONVERSION (geocent, 0) { - P->is_geocent = 1; - P->x0 = 0.0; - P->y0 = 0.0; - P->inv = inverse; - P->fwd = forward; - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_CARTESIAN; - - return P; -} - diff --git a/src/conversions/unitconvert.cpp b/src/conversions/unitconvert.cpp new file mode 100644 index 00000000..b25fd5d2 --- /dev/null +++ b/src/conversions/unitconvert.cpp @@ -0,0 +1,552 @@ +/*********************************************************************** + + Unit conversion pseudo-projection for use with + transformation pipelines. + + Kristian Evers, 2017-05-16 + +************************************************************************ + +A pseudo-projection that can be used to convert units of input and +output data. Primarily useful in pipelines. + +Unit conversion is performed by means of a pivot unit. The pivot unit +for distance units are the meter and for time we use the modified julian +date. A time unit conversion is performed like + + Unit A -> Modified Julian date -> Unit B + +distance units are converted in the same manner, with meter being the +central unit. + +The modified Julian date is chosen as the pivot unit since it has a +fairly high precision, goes sufficiently long backwards in time, has no +danger of hitting the upper limit in the near future and it is a fairly +common time unit in astronomy and geodesy. Note that we are using the +Julian date and not day. The difference being that the latter is defined +as an integer and is thus limited to days in resolution. This approach +has been extended wherever it makes sense, e.g. the GPS week unit also +has a fractional part that makes it possible to determine the day, hour +and minute of an observation. + +In- and output units are controlled with the parameters + + +xy_in, +xy_out, +z_in, +z_out, +t_in and +t_out + +where xy denotes horizontal units, z vertical units and t time units. + +************************************************************************ + +Kristian Evers, kreve@sdfe.dk, 2017-05-09 +Last update: 2017-05-16 + +************************************************************************ +* Copyright (c) 2017, Kristian Evers / SDFE +* +* 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 + +#include "proj_internal.h" +#include "proj_math.h" +#include "projects.h" + +PROJ_HEAD(unitconvert, "Unit conversion"); + +typedef double (*tconvert)(double); + +namespace { // anonymous namespace +struct TIME_UNITS { + const char *id; /* units keyword */ + tconvert t_in; /* unit -> mod. julian date function pointer */ + tconvert t_out; /* mod. julian date > unit function pointer */ + const char *name; /* comments */ +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque_unitconvert { + int t_in_id; /* time unit id for the time input unit */ + int t_out_id; /* time unit id for the time output unit */ + double xy_factor; /* unit conversion factor for horizontal components */ + double z_factor; /* unit conversion factor for vertical components */ +}; +} // anonymous namespace + + +/***********************************************************************/ +static int is_leap_year(long year) { +/***********************************************************************/ + return ((year % 4 == 0 && year % 100 != 0) || year % 400 ==0); +} + + +/***********************************************************************/ +static int days_in_year(long year) { +/***********************************************************************/ + return is_leap_year(year) ? 366 : 365; +} + +/***********************************************************************/ +static unsigned int days_in_month(unsigned long year, unsigned long month) { +/***********************************************************************/ + const unsigned int month_table[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + unsigned int days; + + if (month > 12) month = 12; + if (month == 0) month = 1; + + days = month_table[month-1]; + if (is_leap_year(year) && month == 2) days++; + + return days; +} + + +/***********************************************************************/ +static int daynumber_in_year(unsigned long year, unsigned long month, unsigned long day) { +/***********************************************************************/ + unsigned int daynumber=0, i; + + if (month > 12) month = 12; + if (month == 0) month = 1; + if (day > days_in_month(year, month)) day = days_in_month(year, month); + + for (i = 1; i < month; i++) + daynumber += days_in_month(year, i); + + daynumber += day; + + return daynumber; + +} + +/***********************************************************************/ +static double mjd_to_mjd(double mjd) { +/*********************************************************************** + Modified julian date no-op function. + + The Julian date is defined as (fractional) days since midnight + on 16th of November in 1858. +************************************************************************/ + return mjd; +} + + +/***********************************************************************/ +static double decimalyear_to_mjd(double decimalyear) { +/*********************************************************************** + Epoch of modified julian date is 1858-11-16 00:00 +************************************************************************/ + long year; + double fractional_year; + double mjd; + + if( decimalyear < -10000 || decimalyear > 10000 ) + return 0; + + year = lround(floor(decimalyear)); + fractional_year = decimalyear - year; + mjd = (year - 1859)*365 + 14 + 31; + mjd += (double)fractional_year*(double)days_in_year(year); + + /* take care of leap days */ + year--; + for (; year > 1858; year--) + if (is_leap_year(year)) + mjd++; + + return mjd; +} + + +/***********************************************************************/ +static double mjd_to_decimalyear(double mjd) { +/*********************************************************************** + Epoch of modified julian date is 1858-11-16 00:00 +************************************************************************/ + double decimalyear = mjd; + double mjd_iter = 14 + 31; + int year = 1859; + + /* a smarter brain than mine could probably to do this more elegantly + - I'll just brute-force my way out of this... */ + for (; mjd >= mjd_iter; year++) { + mjd_iter += days_in_year(year); + } + year--; + mjd_iter -= days_in_year(year); + + decimalyear = year + (mjd-mjd_iter)/days_in_year(year); + return decimalyear; +} + + +/***********************************************************************/ +static double gps_week_to_mjd(double gps_week) { +/*********************************************************************** + GPS weeks are defined as the number of weeks since January the 6th + 1980. + + Epoch of gps weeks is 1980-01-06 00:00, which in modified Julian + date is 44244. +************************************************************************/ + return 44244.0 + gps_week*7.0; +} + + +/***********************************************************************/ +static double mjd_to_gps_week(double mjd) { +/*********************************************************************** + GPS weeks are defined as the number of weeks since January the 6th + 1980. + + Epoch of gps weeks is 1980-01-06 00:00, which in modified Julian + date is 44244. +************************************************************************/ + return (mjd - 44244.0) / 7.0; +} + + +/***********************************************************************/ +static double yyyymmdd_to_mjd(double yyyymmdd) { +/************************************************************************ + Date given in YYYY-MM-DD format. +************************************************************************/ + + long year = lround(floor( yyyymmdd / 10000 )); + long month = lround(floor((yyyymmdd - year*10000) / 100)); + long day = lround(floor( yyyymmdd - year*10000 - month*100)); + double mjd = daynumber_in_year(year, month, day); + + for (year -= 1; year > 1858; year--) + mjd += days_in_year(year); + + return mjd + 13 + 31; +} + + +/***********************************************************************/ +static double mjd_to_yyyymmdd(double mjd) { +/************************************************************************ + Date given in YYYY-MM-DD format. +************************************************************************/ + double mjd_iter = 14 + 31; + int year = 1859, month=0, day=0; + + for (; mjd >= mjd_iter; year++) { + mjd_iter += days_in_year(year); + } + year--; + mjd_iter -= days_in_year(year); + + for (month=1; mjd_iter + days_in_month(year, month) <= mjd; month++) + mjd_iter += days_in_month(year, month); + + day = (int)(mjd - mjd_iter + 1); + + return year*10000.0 + month*100.0 + day; +} + +static const struct TIME_UNITS time_units[] = { + {"mjd", mjd_to_mjd, mjd_to_mjd, "Modified julian date"}, + {"decimalyear", decimalyear_to_mjd, mjd_to_decimalyear, "Decimal year"}, + {"gps_week", gps_week_to_mjd, mjd_to_gps_week, "GPS Week"}, + {"yyyymmdd", yyyymmdd_to_mjd, mjd_to_yyyymmdd, "YYYYMMDD date"}, + {nullptr, nullptr, nullptr, nullptr} +}; + + +/***********************************************************************/ +static XY forward_2d(LP lp, PJ *P) { +/************************************************************************ + Forward unit conversions in the plane +************************************************************************/ + struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + point.lp = lp; + + point.xy.x *= Q->xy_factor; + point.xy.y *= Q->xy_factor; + + return point.xy; +} + + +/***********************************************************************/ +static LP reverse_2d(XY xy, PJ *P) { +/************************************************************************ + Reverse unit conversions in the plane +************************************************************************/ + struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + point.xy = xy; + + point.xy.x /= Q->xy_factor; + point.xy.y /= Q->xy_factor; + + return point.lp; +} + + +/***********************************************************************/ +static XYZ forward_3d(LPZ lpz, PJ *P) { +/************************************************************************ + Forward unit conversions the vertical component +************************************************************************/ + struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + point.lpz = lpz; + + /* take care of the horizontal components in the 2D function */ + point.xy = forward_2d(point.lp, P); + + point.xyz.z *= Q->z_factor; + + return point.xyz; +} + +/***********************************************************************/ +static LPZ reverse_3d(XYZ xyz, PJ *P) { +/************************************************************************ + Reverse unit conversions the vertical component +************************************************************************/ + struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + point.xyz = xyz; + + /* take care of the horizontal components in the 2D function */ + point.lp = reverse_2d(point.xy, P); + + point.xyz.z /= Q->z_factor; + + return point.lpz; +} + + +/***********************************************************************/ +static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { +/************************************************************************ + Forward conversion of time units +************************************************************************/ + struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; + PJ_COORD out = obs; + + /* delegate unit conversion of physical dimensions to the 3D function */ + out.xyz = forward_3d(obs.lpz, P); + + if (Q->t_in_id >= 0) + out.xyzt.t = time_units[Q->t_in_id].t_in( obs.xyzt.t ); + if (Q->t_out_id >= 0) + out.xyzt.t = time_units[Q->t_out_id].t_out( out.xyzt.t ); + + return out; +} + + +/***********************************************************************/ +static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { +/************************************************************************ + Reverse conversion of time units +************************************************************************/ + struct pj_opaque_unitconvert *Q = (struct pj_opaque_unitconvert *) P->opaque; + PJ_COORD out = obs; + + /* delegate unit conversion of physical dimensions to the 3D function */ + out.lpz = reverse_3d(obs.xyz, P); + + if (Q->t_out_id >= 0) + out.xyzt.t = time_units[Q->t_out_id].t_in( obs.xyzt.t ); + if (Q->t_in_id >= 0) + out.xyzt.t = time_units[Q->t_in_id].t_out( out.xyzt.t ); + + return out; +} + +/***********************************************************************/ +static double get_unit_conversion_factor(const char* name, + int* p_is_linear, + const char** p_normalized_name) { +/***********************************************************************/ + int i; + const char* s; + const PJ_UNITS *units; + + units = proj_list_units(); + + /* Try first with linear units */ + for (i = 0; (s = units[i].id) ; ++i) { + if ( strcmp(s, name) == 0 ) { + if( p_normalized_name ) { + *p_normalized_name = units[i].name; + } + if( p_is_linear ) { + *p_is_linear = 1; + } + return units[i].factor; + } + } + + /* And then angular units */ + units = proj_list_angular_units(); + for (i = 0; (s = units[i].id) ; ++i) { + if ( strcmp(s, name) == 0 ) { + if( p_normalized_name ) { + *p_normalized_name = units[i].name; + } + if( p_is_linear ) { + *p_is_linear = 0; + } + return units[i].factor; + } + } + if( p_normalized_name ) { + *p_normalized_name = nullptr; + } + if( p_is_linear ) { + *p_is_linear = -1; + } + return 0.0; +} + +/***********************************************************************/ +PJ *CONVERSION(unitconvert,0) { +/***********************************************************************/ + struct pj_opaque_unitconvert *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque_unitconvert))); + const char *s, *name; + int i; + double f; + int xy_in_is_linear = -1; /* unknown */ + int xy_out_is_linear = -1; /* unknown */ + int z_in_is_linear = -1; /* unknown */ + int z_out_is_linear = -1; /* unknown */ + + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = (void *) Q; + + P->fwd4d = forward_4d; + P->inv4d = reverse_4d; + P->fwd3d = forward_3d; + P->inv3d = reverse_3d; + P->fwd = forward_2d; + P->inv = reverse_2d; + + P->left = PJ_IO_UNITS_WHATEVER; + P->right = PJ_IO_UNITS_WHATEVER; + + /* if no time input/output unit is specified we can skip them */ + Q->t_in_id = -1; + Q->t_out_id = -1; + + Q->xy_factor = 1.0; + Q->z_factor = 1.0; + + if ((name = pj_param (P->ctx, P->params, "sxy_in").s) != nullptr) { + const char* normalized_name = nullptr; + f = get_unit_conversion_factor(name, &xy_in_is_linear, &normalized_name); + if (f != 0.0) { + proj_log_debug(P, "xy_in unit: %s", normalized_name); + } else { + if ( (f = pj_param (P->ctx, P->params, "dxy_in").f) == 0.0) + return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); + } + if (f != 0.0) + Q->xy_factor *= f; + } + + if ((name = pj_param (P->ctx, P->params, "sxy_out").s) != nullptr) { + const char* normalized_name = nullptr; + f = get_unit_conversion_factor(name, &xy_out_is_linear, &normalized_name); + if (f != 0.0) { + proj_log_debug(P, "xy_out unit: %s", normalized_name); + } else { + if ( (f = pj_param (P->ctx, P->params, "dxy_out").f) == 0.0) + return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); + } + if (f != 0.0) + Q->xy_factor /= f; + } + + if( xy_in_is_linear >= 0 && xy_out_is_linear >= 0 && + xy_in_is_linear != xy_out_is_linear ) { + proj_log_debug(P, "inconsistent unit type between xy_in and xy_out"); + return pj_default_destructor(P, PJD_ERR_INCONSISTENT_UNIT); + } + + if ((name = pj_param (P->ctx, P->params, "sz_in").s) != nullptr) { + const char* normalized_name = nullptr; + f = get_unit_conversion_factor(name, &z_in_is_linear, &normalized_name); + if (f != 0.0) { + proj_log_debug(P, "z_in unit: %s", normalized_name); + } else { + if ( (f = pj_param (P->ctx, P->params, "dz_in").f) == 0.0) + return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); + } + if (f != 0.0) + Q->z_factor *= f; + } + + if ((name = pj_param (P->ctx, P->params, "sz_out").s) != nullptr) { + const char* normalized_name = nullptr; + f = get_unit_conversion_factor(name, &z_out_is_linear, &normalized_name); + if (f != 0.0) { + proj_log_debug(P, "z_out unit: %s", normalized_name); + } else { + if ( (f = pj_param (P->ctx, P->params, "dz_out").f) == 0.0) + return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); + } + if (f != 0.0) + Q->z_factor /= f; + } + + if( z_in_is_linear >= 0 && z_out_is_linear >= 0 && + z_in_is_linear != z_out_is_linear ) { + proj_log_debug(P, "inconsistent unit type between z_in and z_out"); + return pj_default_destructor(P, PJD_ERR_INCONSISTENT_UNIT); + } + + if ((name = pj_param (P->ctx, P->params, "st_in").s) != nullptr) { + for (i = 0; (s = time_units[i].id) && strcmp(name, s) ; ++i); + + if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); /* unknown unit conversion id */ + + Q->t_in_id = i; + proj_log_debug(P, "t_in unit: %s", time_units[i].name); + } + + s = nullptr; + if ((name = pj_param (P->ctx, P->params, "st_out").s) != nullptr) { + for (i = 0; (s = time_units[i].id) && strcmp(name, s) ; ++i); + + if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); /* unknown unit conversion id */ + + Q->t_out_id = i; + proj_log_debug(P, "t_out unit: %s", time_units[i].name); + } + + return P; +} diff --git a/src/ctx.cpp b/src/ctx.cpp new file mode 100644 index 00000000..ab51d6c1 --- /dev/null +++ b/src/ctx.cpp @@ -0,0 +1,233 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the projCtx thread context object. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2010, 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. + *****************************************************************************/ + +#include +#include +#include + +#include "proj_internal.h" +#include "projects.h" + +static projCtx_t default_context; +static volatile int default_context_initialized = 0; + +/************************************************************************/ +/* pj_get_ctx() */ +/************************************************************************/ + +projCtx pj_get_ctx( projPJ pj ) + +{ + if (nullptr==pj) + return pj_get_default_ctx (); + if (nullptr==pj->ctx) + return pj_get_default_ctx (); + return pj->ctx; +} + +/************************************************************************/ +/* pj_set_ctx() */ +/* */ +/* Note we do not deallocate the old context! */ +/************************************************************************/ + +void pj_set_ctx( projPJ pj, projCtx ctx ) + +{ + if (pj==nullptr) + return; + pj->ctx = ctx; +} + +/************************************************************************/ +/* pj_get_default_ctx() */ +/************************************************************************/ + +projCtx pj_get_default_ctx() + +{ + /* If already initialized, don't bother locking */ + if( default_context_initialized ) + return &default_context; + + pj_acquire_lock(); + + /* Ask again, since it may have been initialized in another thread */ + if( !default_context_initialized ) + { + default_context.last_errno = 0; + default_context.debug_level = PJ_LOG_NONE; + default_context.logger = pj_stderr_logger; + default_context.app_data = nullptr; + default_context.fileapi = pj_get_default_fileapi(); + default_context.cpp_context = nullptr; + default_context.use_proj4_init_rules = -1; + default_context.epsg_file_exists = -1; + + if( getenv("PROJ_DEBUG") != nullptr ) + { + if( atoi(getenv("PROJ_DEBUG")) >= -PJ_LOG_DEBUG_MINOR ) + default_context.debug_level = atoi(getenv("PROJ_DEBUG")); + else + default_context.debug_level = PJ_LOG_DEBUG_MINOR; + } + default_context_initialized = 1; + } + + pj_release_lock(); + + return &default_context; +} + +/************************************************************************/ +/* pj_ctx_alloc() */ +/************************************************************************/ + +projCtx pj_ctx_alloc() + +{ + projCtx ctx = (projCtx_t *) malloc(sizeof(projCtx_t)); + if (nullptr==ctx) + return nullptr; + memcpy( ctx, pj_get_default_ctx(), sizeof(projCtx_t) ); + ctx->last_errno = 0; + ctx->cpp_context = nullptr; + ctx->use_proj4_init_rules = -1; + + return ctx; +} + +/************************************************************************/ +/* pj_ctx_free() */ +/************************************************************************/ + +void pj_ctx_free( projCtx ctx ) + +{ + proj_context_delete_cpp_context( ctx->cpp_context ); + pj_dealloc( ctx ); +} + +/************************************************************************/ +/* pj_ctx_get_errno() */ +/************************************************************************/ + +int pj_ctx_get_errno( projCtx ctx ) + +{ + if (nullptr==ctx) + return pj_get_default_ctx ()->last_errno; + return ctx->last_errno; +} + +/************************************************************************/ +/* pj_ctx_set_errno() */ +/* */ +/* Also sets the global errno */ +/************************************************************************/ + +void pj_ctx_set_errno( projCtx ctx, int new_errno ) + +{ + ctx->last_errno = new_errno; + if( new_errno == 0 ) + return; + errno = new_errno; + pj_errno = new_errno; +} + +/************************************************************************/ +/* pj_ctx_set_debug() */ +/************************************************************************/ + +void pj_ctx_set_debug( projCtx ctx, int new_debug ) + +{ + if (nullptr==ctx) + return; + ctx->debug_level = new_debug; +} + +/************************************************************************/ +/* pj_ctx_set_logger() */ +/************************************************************************/ + +void pj_ctx_set_logger( projCtx ctx, void (*new_logger)(void*,int,const char*) ) + +{ + if (nullptr==ctx) + return; + ctx->logger = new_logger; +} + +/************************************************************************/ +/* pj_ctx_set_app_data() */ +/************************************************************************/ + +void pj_ctx_set_app_data( projCtx ctx, void *new_app_data ) + +{ + if (nullptr==ctx) + return; + ctx->app_data = new_app_data; +} + +/************************************************************************/ +/* pj_ctx_get_app_data() */ +/************************************************************************/ + +void *pj_ctx_get_app_data( projCtx ctx ) + +{ + if (nullptr==ctx) + return nullptr; + return ctx->app_data; +} + +/************************************************************************/ +/* pj_ctx_set_fileapi() */ +/************************************************************************/ + +void pj_ctx_set_fileapi( projCtx ctx, projFileAPI *fileapi ) + +{ + if (nullptr==ctx) + return; + ctx->fileapi = fileapi; +} + +/************************************************************************/ +/* pj_ctx_get_fileapi() */ +/************************************************************************/ + +projFileAPI *pj_ctx_get_fileapi( projCtx ctx ) + +{ + if (nullptr==ctx) + return nullptr; + return ctx->fileapi; +} diff --git a/src/datum_set.cpp b/src/datum_set.cpp new file mode 100644 index 00000000..c9dfdb80 --- /dev/null +++ b/src/datum_set.cpp @@ -0,0 +1,169 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Apply datum definition to PJ structure from initialization string. + * Author: Frank Warmerdam, warmerda@home.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. + *****************************************************************************/ + +#include +#include + +#include "projects.h" + +/* SEC_TO_RAD = Pi/180/3600 */ +#define SEC_TO_RAD 4.84813681109535993589914102357e-6 + +/************************************************************************/ +/* pj_datum_set() */ +/************************************************************************/ + +int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef) + +{ + const char *name, *towgs84, *nadgrids, *catalog; + + projdef->datum_type = PJD_UNKNOWN; + +/* -------------------------------------------------------------------- */ +/* Is there a datum definition in the parameters list? If so, */ +/* add the defining values to the parameter list. Note that */ +/* this will append the ellipse definition as well as the */ +/* towgs84= and related parameters. It should also be pointed */ +/* out that the addition is permanent rather than temporary */ +/* like most other keyword expansion so that the ellipse */ +/* definition will last into the pj_ell_set() function called */ +/* after this one. */ +/* -------------------------------------------------------------------- */ + if( (name = pj_param(ctx, pl,"sdatum").s) != nullptr ) + { + paralist *curr; + const char *s; + int i; + + /* find the end of the list, so we can add to it */ + for (curr = pl; curr && curr->next ; curr = curr->next) {} + + /* cannot happen in practice, but makes static analyzers happy */ + if( !curr ) return -1; + + /* find the datum definition */ + for (i = 0; (s = pj_datums[i].id) && strcmp(name, s) ; ++i) {} + + if (!s) { + pj_ctx_set_errno(ctx, PJD_ERR_UNKNOWN_ELLP_PARAM); + return 1; + } + + if( pj_datums[i].ellipse_id && strlen(pj_datums[i].ellipse_id) > 0 ) + { + char entry[100]; + + strcpy( entry, "ellps=" ); + strncpy( entry + strlen(entry), pj_datums[i].ellipse_id, + sizeof(entry) - 1 - strlen(entry) ); + entry[ sizeof(entry) - 1 ] = '\0'; + + curr = curr->next = pj_mkparam(entry); + } + + if( pj_datums[i].defn && strlen(pj_datums[i].defn) > 0 ) + curr = curr->next = pj_mkparam(pj_datums[i].defn); + + (void)curr; /* make clang static analyzer happy */ + } + +/* -------------------------------------------------------------------- */ +/* Check for nadgrids parameter. */ +/* -------------------------------------------------------------------- */ + nadgrids = pj_param(ctx, pl,"snadgrids").s; + if( nadgrids != nullptr ) + { + /* We don't actually save the value separately. It will continue + to exist int he param list for use in pj_apply_gridshift.c */ + + projdef->datum_type = PJD_GRIDSHIFT; + } + +/* -------------------------------------------------------------------- */ +/* Check for grid catalog parameter, and optional date. */ +/* -------------------------------------------------------------------- */ + else if( (catalog = pj_param(ctx, pl,"scatalog").s) != nullptr ) + { + const char *date; + + projdef->datum_type = PJD_GRIDSHIFT; + projdef->catalog_name = pj_strdup(catalog); + if (!projdef->catalog_name) { + pj_ctx_set_errno(ctx, ENOMEM); + return 1; + } + + date = pj_param(ctx, pl, "sdate").s; + if( date != nullptr) + projdef->datum_date = pj_gc_parsedate( ctx, date); + } + +/* -------------------------------------------------------------------- */ +/* Check for towgs84 parameter. */ +/* -------------------------------------------------------------------- */ + else if( (towgs84 = pj_param(ctx, pl,"stowgs84").s) != nullptr ) + { + int parm_count = 0; + const char *s; + + memset( projdef->datum_params, 0, sizeof(double) * 7); + + /* parse out the parameters */ + for( s = towgs84; *s != '\0' && parm_count < 7; ) + { + projdef->datum_params[parm_count++] = pj_atof(s); + while( *s != '\0' && *s != ',' ) + s++; + if( *s == ',' ) + s++; + } + + if( projdef->datum_params[3] != 0.0 + || projdef->datum_params[4] != 0.0 + || projdef->datum_params[5] != 0.0 + || projdef->datum_params[6] != 0.0 ) + { + projdef->datum_type = PJD_7PARAM; + + /* transform from arc seconds to radians */ + projdef->datum_params[3] *= SEC_TO_RAD; + projdef->datum_params[4] *= SEC_TO_RAD; + projdef->datum_params[5] *= SEC_TO_RAD; + /* transform from parts per million to scaling factor */ + projdef->datum_params[6] = + (projdef->datum_params[6]/1000000.0) + 1; + } + else + projdef->datum_type = PJD_3PARAM; + + /* Note that pj_init() will later switch datum_type to + PJD_WGS84 if shifts are all zero, and ellipsoid is WGS84 or GRS80 */ + } + + return 0; +} diff --git a/src/datums.cpp b/src/datums.cpp new file mode 100644 index 00000000..acbe12f7 --- /dev/null +++ b/src/datums.cpp @@ -0,0 +1,99 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Built in datum list. + * Author: Frank Warmerdam, warmerda@home.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. + *****************************************************************************/ + +#include + +#include "proj.h" + +#define PJ_DATUMS__ +#include "projects.h" + +/* + * The ellipse code must match one from pj_ellps.c. The datum id should + * be kept to 12 characters or less if possible. Use the official OGC + * datum name for the comments if available. + */ + +C_NAMESPACE_VAR const struct PJ_DATUMS pj_datums[] = { +/* id definition ellipse comments */ +/* -- ---------- ------- -------- */ +{"WGS84", "towgs84=0,0,0", "WGS84", ""}, +{"GGRS87", "towgs84=-199.87,74.79,246.62", "GRS80", + "Greek_Geodetic_Reference_System_1987"}, +{"NAD83", "towgs84=0,0,0", "GRS80", + "North_American_Datum_1983"}, +{"NAD27", "nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat", + "clrk66", + "North_American_Datum_1927"}, +{"potsdam", /*"towgs84=598.1,73.7,418.2,0.202,0.045,-2.455,6.7",*/ + "nadgrids=@BETA2007.gsb", + "bessel", + "Potsdam Rauenberg 1950 DHDN"}, +{"carthage","towgs84=-263.0,6.0,431.0", "clrk80ign", + "Carthage 1934 Tunisia"}, +{"hermannskogel", "towgs84=577.326,90.129,463.919,5.137,1.474,5.297,2.4232", + "bessel", + "Hermannskogel"}, +{"ire65", "towgs84=482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15", + "mod_airy", + "Ireland 1965"}, +{"nzgd49", "towgs84=59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993", + "intl", "New Zealand Geodetic Datum 1949"}, +{"OSGB36", "towgs84=446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894", + "airy", "Airy 1830"}, +{nullptr, nullptr, nullptr, nullptr} +}; + +struct PJ_DATUMS *pj_get_datums_ref() +{ + return (struct PJ_DATUMS *)pj_datums; +} + +static const struct PJ_PRIME_MERIDIANS pj_prime_meridians[] = { + /* id definition */ + /* -- ---------- */ + {"greenwich", "0dE"}, + {"lisbon", "9d07'54.862\"W"}, + {"paris", "2d20'14.025\"E"}, + {"bogota", "74d04'51.3\"W"}, + {"madrid", "3d41'16.58\"W"}, + {"rome", "12d27'8.4\"E"}, + {"bern", "7d26'22.5\"E"}, + {"jakarta", "106d48'27.79\"E"}, + {"ferro", "17d40'W"}, + {"brussels", "4d22'4.71\"E"}, + {"stockholm", "18d3'29.8\"E"}, + {"athens", "23d42'58.815\"E"}, + {"oslo", "10d43'22.5\"E"}, + {"copenhagen","12d34'40.35\"E"}, + {nullptr, nullptr} +}; + +const PJ_PRIME_MERIDIANS *proj_list_prime_meridians(void) +{ + return pj_prime_meridians; +} diff --git a/src/deriv.cpp b/src/deriv.cpp new file mode 100644 index 00000000..0e285265 --- /dev/null +++ b/src/deriv.cpp @@ -0,0 +1,70 @@ +/* dervative of (*P->fwd) projection */ +#define PJ_LIB__ + +#include + +#include "projects.h" + +int pj_deriv(LP lp, double h, const PJ *P, struct DERIVS *der) { + XY t; + /* get rid of constness until we can do it for real */ + PJ *Q = (PJ *) P; + if (nullptr==Q->fwd) + return 1; + + lp.lam += h; + lp.phi += h; + if (fabs(lp.phi) > M_HALFPI) + return 1; + + h += h; + t = (*Q->fwd)(lp, Q); + if (t.x == HUGE_VAL) + return 1; + + der->x_l = t.x; + der->y_p = t.y; + der->x_p = t.x; + der->y_l = t.y; + + lp.phi -= h; + if (fabs(lp.phi) > M_HALFPI) + return 1; + + t = (*Q->fwd)(lp, Q); + if (t.x == HUGE_VAL) + return 1; + + der->x_l += t.x; + der->y_p -= t.y; + der->x_p -= t.x; + der->y_l += t.y; + + lp.lam -= h; + t = (*Q->fwd)(lp, Q); + if (t.x == HUGE_VAL) + return 1; + + der->x_l -= t.x; + der->y_p -= t.y; + der->x_p -= t.x; + der->y_l -= t.y; + + lp.phi += h; + t = (*Q->fwd)(lp, Q); + if (t.x == HUGE_VAL) + return 1; + + der->x_l -= t.x; + der->y_p += t.y; + der->x_p += t.x; + der->y_l -= t.y; + + h += h; + der->x_l /= h; + der->y_p /= h; + der->x_p /= h; + der->y_l /= h; + + return 0; +} diff --git a/src/ell_set.cpp b/src/ell_set.cpp new file mode 100644 index 00000000..486230a5 --- /dev/null +++ b/src/ell_set.cpp @@ -0,0 +1,727 @@ +/* set ellipsoid parameters a and es */ + +#include +#include +#include + +#include "proj.h" +#include "proj_internal.h" +#include "projects.h" + + +/* Prototypes of the pj_ellipsoid helper functions */ +static int ellps_ellps (PJ *P); +static int ellps_size (PJ *P); +static int ellps_shape (PJ *P); +static int ellps_spherification (PJ *P); + +static paralist *pj_get_param (paralist *list, const char *key); +static char *pj_param_value (paralist *list); +static const PJ_ELLPS *pj_find_ellps (const char *name); + + +/***************************************************************************************/ +int pj_ellipsoid (PJ *P) { +/**************************************************************************************** + This is a replacement for the classic PROJ pj_ell_set function. The main difference + is that pj_ellipsoid augments the PJ object with a copy of the exact tags used to + define its related ellipsoid. + + This makes it possible to let a new PJ object inherit the geometrical properties + of an existing one. + + A complete ellipsoid definition comprises a size (primary) and a shape (secondary) + parameter. + + Size parameters supported are: + R, defining the radius of a spherical planet + a, defining the semimajor axis of an ellipsoidal planet + + Shape parameters supported are: + rf, the reverse flattening of the ellipsoid + f, the flattening of the ellipsoid + es, the eccentricity squared + e, the eccentricity + b, the semiminor axis + + The ellps=xxx parameter provides both size and shape for a number of built in + ellipsoid definitions. + + The ellipsoid definition may be augmented with a spherification flag, turning + the ellipsoid into a sphere with features defined by the ellipsoid. + + Spherification parameters supported are: + R_A, which gives a sphere with the same surface area as the ellipsoid + R_A, which gives a sphere with the same volume as the ellipsoid + + R_a, which gives a sphere with R = (a + b)/2 (arithmetic mean) + R_g, which gives a sphere with R = sqrt(a*b) (geometric mean) + R_h, which gives a sphere with R = 2*a*b/(a+b) (harmonic mean) + + R_lat_a=phi, which gives a sphere with R being the arithmetic mean of + of the corresponding ellipsoid at latitude phi. + R_lat_g=phi, which gives a sphere with R being the geometric mean of + of the corresponding ellipsoid at latitude phi. + + If R is given as size parameter, any shape and spherification parameters + given are ignored. + + If size and shape are given as ellps=xxx, later shape and size parameters + are are taken into account as modifiers for the built in ellipsoid definition. + + While this may seem strange, it is in accordance with historical PROJ + behaviour. It can e.g. be used to define coordinates on the ellipsoid + scaled to unit semimajor axis by specifying "+ellps=xxx +a=1" + +****************************************************************************************/ + int err = proj_errno_reset (P); + const char *empty = {""}; + + P->def_size = P->def_shape = P->def_spherification = P->def_ellps = nullptr; + + /* Specifying R overrules everything */ + if (pj_get_param (P->params, "R")) { + ellps_size (P); + pj_calc_ellipsoid_params (P, P->a, 0); + if (proj_errno (P)) + return 1; + return proj_errno_restore (P, err); + } + + + /* If an ellps argument is specified, start by using that */ + if (0 != ellps_ellps (P)) + return 1; + + /* We may overwrite the size */ + if (0 != ellps_size (P)) + return 2; + + /* We may also overwrite the shape */ + if (0 != ellps_shape (P)) + return 3; + + /* When we're done with it, we compute all related ellipsoid parameters */ + pj_calc_ellipsoid_params (P, P->a, P->es); + + /* And finally, we may turn it into a sphere */ + if (0 != ellps_spherification (P)) + return 4; + + proj_log_debug (P, "pj_ellipsoid - final: a=%.3f f=1/%7.3f, errno=%d", + P->a, P->f!=0? 1/P->f: 0, proj_errno (P)); + proj_log_debug (P, "pj_ellipsoid - final: %s %s %s %s", + P->def_size? P->def_size: empty, + P->def_shape? P->def_shape: empty, + P->def_spherification? P->def_spherification: empty, + P->def_ellps? P->def_ellps: empty ); + + if (proj_errno (P)) + return 5; + + /* success */ + return proj_errno_restore (P, err); +} + + +/***************************************************************************************/ +static int ellps_ellps (PJ *P) { +/***************************************************************************************/ + PJ B; + const PJ_ELLPS *ellps; + paralist *par = nullptr; + char *name; + int err; + + /* Sail home if ellps=xxx is not specified */ + par = pj_get_param (P->params, "ellps"); + if (nullptr==par) + return 0; + + /* Otherwise produce a fake PJ to make ellps_size/ellps_shape do the hard work for us */ + + /* First move B into P's context to get error messages onto the right channel */ + B.ctx = P->ctx; + + /* Then look up the right size and shape parameters from the builtin list */ + if (strlen (par->param) < 7) + return proj_errno_set (P, PJD_ERR_INVALID_ARG); + name = par->param + 6; + ellps = pj_find_ellps (name); + if (nullptr==ellps) + return proj_errno_set (P, PJD_ERR_UNKNOWN_ELLP_PARAM); + + /* Now, get things ready for ellps_size/ellps_shape, make them do their thing, and clean up */ + err = proj_errno_reset (P); + B = *P; + pj_erase_ellipsoid_def (&B); + B.params = pj_mkparam (ellps->major); + B.params->next = pj_mkparam (ellps->ell); + + ellps_size (&B); + ellps_shape (&B); + + pj_dealloc (B.params->next); + pj_dealloc (B.params); + if (proj_errno (&B)) + return proj_errno (&B); + + /* Finally update P and sail home */ + pj_inherit_ellipsoid_def (&B, P); + P->def_ellps = par->param; + par->used = 1; + + return proj_errno_restore (P, err); +} + + +/***************************************************************************************/ +static int ellps_size (PJ *P) { +/***************************************************************************************/ + paralist *par = nullptr; + int a_was_set = 0; + + /* A size parameter *must* be given, but may have been given as ellps prior */ + if (P->a != 0) + a_was_set = 1; + + /* Check which size key is specified */ + par = pj_get_param (P->params, "R"); + if (nullptr==par) + par = pj_get_param (P->params, "a"); + if (nullptr==par) + return a_was_set? 0: proj_errno_set (P, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); + + P->def_size = par->param; + par->used = 1; + P->a = pj_atof (pj_param_value (par)); + if (P->a <= 0) + return proj_errno_set (P, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); + if (HUGE_VAL==P->a) + return proj_errno_set (P, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); + + if ('R'==par->param[0]) { + P->es = P->f = P->e = P->rf = 0; + P->b = P->a; + } + return 0; +} + + +/***************************************************************************************/ +static int ellps_shape (PJ *P) { +/***************************************************************************************/ + const char *keys[] = {"rf", "f", "es", "e", "b"}; + paralist *par = nullptr; + char *def = nullptr; + size_t i, len; + + par = nullptr; + len = sizeof (keys) / sizeof (char *); + + /* Check which shape key is specified */ + for (i = 0; i < len; i++) { + par = pj_get_param (P->params, keys[i]); + if (par) + break; + } + + /* Not giving a shape parameter means selecting a sphere, unless shape */ + /* has been selected previously via ellps=xxx */ + if (nullptr==par && P->es != 0) + return 0; + if (nullptr==par && P->es==0) { + P->es = P->f = 0; + P->b = P->a; + return 0; + } + + P->def_shape = def = par->param; + par->used = 1; + P->es = P->f = P->b = P->e = P->rf = 0; + + switch (i) { + + /* reverse flattening, rf */ + case 0: + P->rf = pj_atof (pj_param_value (par)); + if (HUGE_VAL==P->rf) + return proj_errno_set (P, PJD_ERR_INVALID_ARG); + if (0==P->rf) + return proj_errno_set (P, PJD_ERR_REV_FLATTENING_IS_ZERO); + P->f = 1 / P->rf; + P->es = 2*P->f - P->f*P->f; + break; + + /* flattening, f */ + case 1: + P->f = pj_atof (pj_param_value (par)); + if (HUGE_VAL==P->f) + return proj_errno_set (P, PJD_ERR_INVALID_ARG); + + P->rf = P->f != 0.0 ? 1.0/P->f: HUGE_VAL; + P->es = 2*P->f - P->f*P->f; + break; + + /* eccentricity squared, es */ + case 2: + P->es = pj_atof (pj_param_value (par)); + if (HUGE_VAL==P->es) + return proj_errno_set (P, PJD_ERR_INVALID_ARG); + if (1==P->es) + return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); + break; + + /* eccentricity, e */ + case 3: + P->e = pj_atof (pj_param_value (par)); + if (HUGE_VAL==P->e) + return proj_errno_set (P, PJD_ERR_INVALID_ARG); + if (0==P->e) + return proj_errno_set (P, PJD_ERR_INVALID_ARG); + if (1==P->e) + return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); + P->es = P->e * P->e; + break; + + /* semiminor axis, b */ + case 4: + P->b = pj_atof (pj_param_value (par)); + if (HUGE_VAL==P->b) + return proj_errno_set (P, PJD_ERR_INVALID_ARG); + if (0==P->b) + return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); + if (P->b==P->a) + break; + P->f = (P->a - P->b) / P->a; + P->es = 2*P->f - P->f*P->f; + break; + default: + return PJD_ERR_INVALID_ARG; + + } + + if (P->es < 0) + return proj_errno_set (P, PJD_ERR_ES_LESS_THAN_ZERO); + return 0; +} + + +/* series coefficients for calculating ellipsoid-equivalent spheres */ +static const double SIXTH = 1/6.; +static const double RA4 = 17/360.; +static const double RA6 = 67/3024.; +static const double RV4 = 5/72.; +static const double RV6 = 55/1296.; + +/***************************************************************************************/ +static int ellps_spherification (PJ *P) { +/***************************************************************************************/ + const char *keys[] = {"R_A", "R_V", "R_a", "R_g", "R_h", "R_lat_a", "R_lat_g"}; + size_t len, i; + paralist *par = nullptr; + char *def = nullptr; + + double t; + char *v, *endp; + + len = sizeof (keys) / sizeof (char *); + P->def_spherification = nullptr; + + /* Check which spherification key is specified */ + for (i = 0; i < len; i++) { + par = pj_get_param (P->params, keys[i]); + if (par) + break; + } + + /* No spherification specified? Then we're done */ + if (i==len) + return 0; + + /* Store definition */ + P->def_spherification = def = par->param; + par->used = 1; + + switch (i) { + + /* R_A - a sphere with same area as ellipsoid */ + case 0: + P->a *= 1. - P->es * (SIXTH + P->es * (RA4 + P->es * RA6)); + break; + + /* R_V - a sphere with same volume as ellipsoid */ + case 1: + P->a *= 1. - P->es * (SIXTH + P->es * (RV4 + P->es * RV6)); + break; + + /* R_a - a sphere with R = the arithmetic mean of the ellipsoid */ + case 2: + P->a = (P->a + P->b) / 2; + break; + + /* R_g - a sphere with R = the geometric mean of the ellipsoid */ + case 3: + P->a = sqrt (P->a * P->b); + break; + + /* R_h - a sphere with R = the harmonic mean of the ellipsoid */ + case 4: + if (P->a + P->b == 0) + return proj_errno_set (P, PJD_ERR_TOLERANCE_CONDITION); + P->a = (2*P->a * P->b) / (P->a + P->b); + break; + + /* R_lat_a - a sphere with R = the arithmetic mean of the ellipsoid at given latitude */ + case 5: + /* R_lat_g - a sphere with R = the geometric mean of the ellipsoid at given latitude */ + case 6: + v = pj_param_value (par); + t = proj_dmstor (v, &endp); + if (fabs (t) > M_HALFPI) + return proj_errno_set (P, PJD_ERR_REF_RAD_LARGER_THAN_90); + t = sin (t); + t = 1 - P->es * t * t; + if (i==5) /* arithmetic */ + P->a *= (1. - P->es + t) / (2 * t * sqrt(t)); + else /* geometric */ + P->a *= sqrt (1 - P->es) / t; + break; + } + + /* Clean up the ellipsoidal parameters to reflect the sphere */ + P->es = P->e = P->f = 0; + P->rf = HUGE_VAL; + P->b = P->a; + pj_calc_ellipsoid_params (P, P->a, 0); + + return 0; +} + + +/* locate parameter in list */ +static paralist *pj_get_param (paralist *list, const char *key) { + size_t l = strlen(key); + while (list && !(0==strncmp(list->param, key, l) && (0==list->param[l] || list->param[l] == '=') ) ) + list = list->next; + return list; +} + + +static char *pj_param_value (paralist *list) { + char *key, *value; + if (nullptr==list) + return nullptr; + + key = list->param; + value = strchr (key, '='); + + /* a flag (i.e. a key without value) has its own name (key) as value */ + return value? value + 1: key; +} + + +static const PJ_ELLPS *pj_find_ellps (const char *name) { + int i; + const char *s; + const PJ_ELLPS *ellps; + + if (nullptr==name) + return nullptr; + + ellps = proj_list_ellps(); + + /* Search through internal ellipsoid list for name */ + for (i = 0; (s = ellps[i].id) && strcmp(name, s) ; ++i); + if (nullptr==s) + return nullptr; + return ellps + i; +} + + +/**************************************************************************************/ +void pj_erase_ellipsoid_def (PJ *P) { +/*************************************************************************************** + Erase all ellipsoidal parameters in P +***************************************************************************************/ + PJ B; + + /* Make a blank PJ to copy from */ + memset (&B, 0, sizeof (B)); + + /* And use it to overwrite all existing ellipsoid defs */ + pj_inherit_ellipsoid_def (&B, P); +} + + +/**************************************************************************************/ +void pj_inherit_ellipsoid_def (const PJ *src, PJ *dst) { +/*************************************************************************************** + Brute force copy the ellipsoidal parameters from src to dst. This code was + written before the actual ellipsoid setup parameters were kept available in + the PJ->def_xxx elements. +***************************************************************************************/ + + /* The linear parameters */ + dst->a = src->a; + dst->b = src->b; + dst->ra = src->ra; + dst->rb = src->rb; + + /* The eccentricities */ + dst->alpha = src->alpha; + dst->e = src->e; + dst->es = src->es; + dst->e2 = src->e2; + dst->e2s = src->e2s; + dst->e3 = src->e3; + dst->e3s = src->e3s; + dst->one_es = src->one_es; + dst->rone_es = src->rone_es; + + /* The flattenings */ + dst->f = src->f; + dst->f2 = src->f2; + dst->n = src->n; + dst->rf = src->rf; + dst->rf2 = src->rf2; + dst->rn = src->rn; + + /* This one's for GRS80 */ + dst->J = src->J; + + /* es and a before any +proj related adjustment */ + dst->es_orig = src->es_orig; + dst->a_orig = src->a_orig; +} + + +/***************************************************************************************/ +int pj_calc_ellipsoid_params (PJ *P, double a, double es) { +/**************************************************************************************** + Calculate a large number of ancillary ellipsoidal parameters, in addition to + the two traditional PROJ defining parameters: Semimajor axis, a, and the + eccentricity squared, es. + + Most of these parameters are fairly cheap to compute in comparison to the overall + effort involved in initializing a PJ object. They may, however, take a substantial + part of the time taken in computing an individual point transformation. + + So by providing them up front, we can amortize the (already modest) cost over all + transformations carried out over the entire lifetime of a PJ object, rather than + incur that cost for every single transformation. + + Most of the parameter calculations here are based on the "angular eccentricity", + i.e. the angle, measured from the semiminor axis, of a line going from the north + pole to one of the foci of the ellipsoid - or in other words: The arc sine of the + eccentricity. + + The formulae used are mostly taken from: + + Richard H. Rapp: Geometric Geodesy, Part I, (178 pp, 1991). + Columbus, Ohio: Dept. of Geodetic Science + and Surveying, Ohio State University. + +****************************************************************************************/ + + P->a = a; + P->es = es; + + /* Compute some ancillary ellipsoidal parameters */ + if (P->e==0) + P->e = sqrt(P->es); /* eccentricity */ + P->alpha = asin (P->e); /* angular eccentricity */ + + /* second eccentricity */ + P->e2 = tan (P->alpha); + P->e2s = P->e2 * P->e2; + + /* third eccentricity */ + P->e3 = (0!=P->alpha)? sin (P->alpha) / sqrt(2 - sin (P->alpha)*sin (P->alpha)): 0; + P->e3s = P->e3 * P->e3; + + /* flattening */ + if (0==P->f) + P->f = 1 - cos (P->alpha); /* = 1 - sqrt (1 - PIN->es); */ + P->rf = P->f != 0.0 ? 1.0/P->f: HUGE_VAL; + + /* second flattening */ + P->f2 = (cos(P->alpha)!=0)? 1/cos (P->alpha) - 1: 0; + P->rf2 = P->f2 != 0.0 ? 1/P->f2: HUGE_VAL; + + /* third flattening */ + P->n = pow (tan (P->alpha/2), 2); + P->rn = P->n != 0.0 ? 1/P->n: HUGE_VAL; + + /* ...and a few more */ + if (0==P->b) + P->b = (1 - P->f)*P->a; + P->rb = 1. / P->b; + P->ra = 1. / P->a; + + P->one_es = 1. - P->es; + if (P->one_es == 0.) { + pj_ctx_set_errno( P->ctx, PJD_ERR_ECCENTRICITY_IS_ONE); + return PJD_ERR_ECCENTRICITY_IS_ONE; + } + + P->rone_es = 1./P->one_es; + + return 0; +} + + + +#ifndef KEEP_ORIGINAL_PJ_ELL_SET +/**************************************************************************************/ +int pj_ell_set (PJ_CONTEXT *ctx, paralist *pl, double *a, double *es) { +/*************************************************************************************** + Initialize ellipsoidal parameters by emulating the original ellipsoid setup + function by Gerald Evenden, through a call to pj_ellipsoid +***************************************************************************************/ + PJ B; + int ret; + + memset (&B, 0, sizeof (B)); + B.ctx = ctx; + B.params = pl; + + ret = pj_ellipsoid (&B); + if (ret) + return ret; + + *a = B.a; + *es = B.es; + return 0; +} +#else + + +/**************************************************************************************/ +int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { +/*************************************************************************************** + Initialize ellipsoidal parameters: This is the original ellipsoid setup + function by Gerald Evenden - significantly more compact than pj_ellipsoid and + its many helper functions, and still quite readable. + + It is, however, also so tight that it is hard to modify and add functionality, + and equally hard to find the right place to add further commentary for improved + future maintainability. + + Hence, when the need to store in the PJ object, the parameters actually used to + define the ellipsoid came up, rather than modifying this little gem of + "economy of expression", a much more verbose reimplementation, pj_ellipsoid, + was written. +***************************************************************************************/ + int i; + double b=0.0, e; + char *name; + paralist *start = 0; + + /* clear any previous error */ + pj_ctx_set_errno(ctx,0); + + /* check for varying forms of ellipsoid input */ + *a = *es = 0.; + + /* R takes precedence */ + if (pj_param(ctx, pl, "tR").i) + *a = pj_param(ctx,pl, "dR").f; + + /* probable elliptical figure */ + else { + /* check if ellps present and temporarily append its values to pl */ + if ((name = pj_param(ctx,pl, "sellps").s) != NULL) { + char *s; + + for (start = pl; start && start->next ; start = start->next) ; + for (i = 0; (s = pj_ellps[i].id) && strcmp(name, s) ; ++i) ; + if (!s) { + pj_ctx_set_errno( ctx, PJD_ERR_UNKNOWN_ELLP_PARAM); + return 1; + } + start->next = pj_mkparam(pj_ellps[i].major); + start->next->next = pj_mkparam(pj_ellps[i].ell); + } + + *a = pj_param(ctx,pl, "da").f; + + if (pj_param(ctx,pl, "tes").i) /* eccentricity squared */ + *es = pj_param(ctx,pl, "des").f; + else if (pj_param(ctx,pl, "te").i) { /* eccentricity */ + e = pj_param(ctx,pl, "de").f; + *es = e * e; + } else if (pj_param(ctx,pl, "trf").i) { /* recip flattening */ + *es = pj_param(ctx,pl, "drf").f; + if (*es == 0.0) { + pj_ctx_set_errno(ctx, PJD_ERR_REV_FLATTENING_IS_ZERO); + goto bomb; + } + *es = 1./ *es; + *es = *es * (2. - *es); + } else if (pj_param(ctx,pl, "tf").i) { /* flattening */ + *es = pj_param(ctx,pl, "df").f; + *es = *es * (2. - *es); + } else if (pj_param(ctx,pl, "tb").i) { /* minor axis */ + b = pj_param(ctx,pl, "db").f; + *es = 1. - (b * b) / (*a * *a); + } /* else *es == 0. and sphere of radius *a */ + if (b == 0.0) + b = *a * sqrt(1. - *es); + + + /* following options turn ellipsoid into equivalent sphere */ + if (pj_param(ctx,pl, "bR_A").i) { /* sphere--area of ellipsoid */ + *a *= 1. - *es * (SIXTH + *es * (RA4 + *es * RA6)); + *es = 0.; + } else if (pj_param(ctx,pl, "bR_V").i) { /* sphere--vol. of ellipsoid */ + *a *= 1. - *es * (SIXTH + *es * (RV4 + *es * RV6)); + *es = 0.; + } else if (pj_param(ctx,pl, "bR_a").i) { /* sphere--arithmetic mean */ + *a = .5 * (*a + b); + *es = 0.; + } else if (pj_param(ctx,pl, "bR_g").i) { /* sphere--geometric mean */ + *a = sqrt(*a * b); + *es = 0.; + } else if (pj_param(ctx,pl, "bR_h").i) { /* sphere--harmonic mean */ + if ( (*a + b) == 0.0) { + pj_ctx_set_errno(ctx, PJD_ERR_TOLERANCE_CONDITION); + goto bomb; + } + *a = 2. * *a * b / (*a + b); + *es = 0.; + } else if ((i = pj_param(ctx,pl, "tR_lat_a").i) || /* sphere--arith. */ + pj_param(ctx,pl, "tR_lat_g").i) { /* or geom. mean at latitude */ + double tmp; + + tmp = sin(pj_param(ctx,pl, i ? "rR_lat_a" : "rR_lat_g").f); + if (fabs(tmp) > M_HALFPI) { + pj_ctx_set_errno(ctx, PJD_ERR_REF_RAD_LARGER_THAN_90); + goto bomb; + } + tmp = 1. - *es * tmp * tmp; + *a *= i ? .5 * (1. - *es + tmp) / ( tmp * sqrt(tmp)) : + sqrt(1. - *es) / tmp; + *es = 0.; + } +bomb: + if (start) { /* clean up temporary extension of list */ + pj_dalloc(start->next->next); + pj_dalloc(start->next); + start->next = 0; + } + if (ctx->last_errno) + return 1; + } + /* some remaining checks */ + if (*es < 0.) { + pj_ctx_set_errno(ctx, PJD_ERR_ES_LESS_THAN_ZERO); + return 1; + } + if (*a <= 0.) { + pj_ctx_set_errno(ctx, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); + return 1; + } + return 0; +} +#endif diff --git a/src/ellps.cpp b/src/ellps.cpp new file mode 100644 index 00000000..f548d30d --- /dev/null +++ b/src/ellps.cpp @@ -0,0 +1,62 @@ +/* definition of standard geoids */ + +#include + +#include "proj.h" +#include "projects.h" + +static const struct PJ_ELLPS +pj_ellps[] = { +{"MERIT", "a=6378137.0", "rf=298.257", "MERIT 1983"}, +{"SGS85", "a=6378136.0", "rf=298.257", "Soviet Geodetic System 85"}, +{"GRS80", "a=6378137.0", "rf=298.257222101", "GRS 1980(IUGG, 1980)"}, +{"IAU76", "a=6378140.0", "rf=298.257", "IAU 1976"}, +{"airy", "a=6377563.396", "rf=299.3249646", "Airy 1830"}, +{"APL4.9", "a=6378137.0", "rf=298.25", "Appl. Physics. 1965"}, +{"NWL9D", "a=6378145.0", "rf=298.25", "Naval Weapons Lab., 1965"}, +{"mod_airy", "a=6377340.189", "b=6356034.446", "Modified Airy"}, +{"andrae", "a=6377104.43", "rf=300.0", "Andrae 1876 (Den., Iclnd.)"}, +{"danish", "a=6377019.2563", "rf=300.0", "Andrae 1876 (Denmark, Iceland)"}, +{"aust_SA", "a=6378160.0", "rf=298.25", "Australian Natl & S. Amer. 1969"}, +{"GRS67", "a=6378160.0", "rf=298.2471674270", "GRS 67(IUGG 1967)"}, +{"GSK2011", "a=6378136.5", "rf=298.2564151", "GSK-2011"}, +{"bessel", "a=6377397.155", "rf=299.1528128", "Bessel 1841"}, +{"bess_nam", "a=6377483.865", "rf=299.1528128", "Bessel 1841 (Namibia)"}, +{"clrk66", "a=6378206.4", "b=6356583.8", "Clarke 1866"}, +{"clrk80", "a=6378249.145", "rf=293.4663", "Clarke 1880 mod."}, +{"clrk80ign", "a=6378249.2", "rf=293.4660212936269", "Clarke 1880 (IGN)."}, +{"CPM", "a=6375738.7", "rf=334.29", "Comm. des Poids et Mesures 1799"}, +{"delmbr", "a=6376428.", "rf=311.5", "Delambre 1810 (Belgium)"}, +{"engelis", "a=6378136.05", "rf=298.2566", "Engelis 1985"}, +{"evrst30", "a=6377276.345", "rf=300.8017", "Everest 1830"}, +{"evrst48", "a=6377304.063", "rf=300.8017", "Everest 1948"}, +{"evrst56", "a=6377301.243", "rf=300.8017", "Everest 1956"}, +{"evrst69", "a=6377295.664", "rf=300.8017", "Everest 1969"}, +{"evrstSS", "a=6377298.556", "rf=300.8017", "Everest (Sabah & Sarawak)"}, +{"fschr60", "a=6378166.", "rf=298.3", "Fischer (Mercury Datum) 1960"}, +{"fschr60m", "a=6378155.", "rf=298.3", "Modified Fischer 1960"}, +{"fschr68", "a=6378150.", "rf=298.3", "Fischer 1968"}, +{"helmert", "a=6378200.", "rf=298.3", "Helmert 1906"}, +{"hough", "a=6378270.0", "rf=297.", "Hough"}, +{"intl", "a=6378388.0", "rf=297.", "International 1909 (Hayford)"}, +{"krass", "a=6378245.0", "rf=298.3", "Krassovsky, 1942"}, +{"kaula", "a=6378163.", "rf=298.24", "Kaula 1961"}, +{"lerch", "a=6378139.", "rf=298.257", "Lerch 1979"}, +{"mprts", "a=6397300.", "rf=191.", "Maupertius 1738"}, +{"new_intl", "a=6378157.5", "b=6356772.2", "New International 1967"}, +{"plessis", "a=6376523.", "b=6355863.", "Plessis 1817 (France)"}, +{"PZ90", "a=6378136.0", "rf=298.25784", "PZ-90"}, +{"SEasia", "a=6378155.0", "b=6356773.3205", "Southeast Asia"}, +{"walbeck", "a=6376896.0", "b=6355834.8467", "Walbeck"}, +{"WGS60", "a=6378165.0", "rf=298.3", "WGS 60"}, +{"WGS66", "a=6378145.0", "rf=298.25", "WGS 66"}, +{"WGS72", "a=6378135.0", "rf=298.26", "WGS 72"}, +{"WGS84", "a=6378137.0", "rf=298.257223563", "WGS 84"}, +{"sphere", "a=6370997.0", "b=6370997.0", "Normal Sphere (r=6370997)"}, +{nullptr, nullptr, nullptr, nullptr} +}; + +const PJ_ELLPS *proj_list_ellps(void) +{ + return pj_ellps; +} diff --git a/src/errno.cpp b/src/errno.cpp new file mode 100644 index 00000000..f6ea9bfc --- /dev/null +++ b/src/errno.cpp @@ -0,0 +1,17 @@ +/* For full ANSI compliance of global variable */ + +#include "projects.h" + +int pj_errno = 0; + +/************************************************************************/ +/* pj_get_errno_ref() */ +/************************************************************************/ + +int *pj_get_errno_ref() + +{ + return &pj_errno; +} + +/* end */ diff --git a/src/factors.cpp b/src/factors.cpp new file mode 100644 index 00000000..768bf585 --- /dev/null +++ b/src/factors.cpp @@ -0,0 +1,107 @@ +/* projection scale factors */ +#define PJ_LIB__ +#include "proj.h" +#include "proj_internal.h" +#include "proj_math.h" +#include "projects.h" + +#include + +#ifndef DEFAULT_H +#define DEFAULT_H 1e-5 /* radian default for numeric h */ +#endif + +#define EPS 1.0e-12 + +int pj_factors(LP lp, const PJ *P, double h, struct FACTORS *fac) { + double cosphi, t, n, r; + int err; + PJ_COORD coo = {{0, 0, 0, 0}}; + coo.lp = lp; + + /* Failing the 3 initial checks will most likely be due to */ + /* earlier errors, so we leave errno alone */ + if (nullptr==fac) + return 1; + + if (nullptr==P) + return 1; + + if (HUGE_VAL==lp.lam) + return 1; + + /* But from here, we're ready to make our own mistakes */ + err = proj_errno_reset (P); + + /* Indicate that all factors are numerical approximations */ + fac->code = 0; + + /* Check for latitude or longitude overange */ + if ((fabs (lp.phi)-M_HALFPI) > EPS || fabs (lp.lam) > 10.) { + proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); + return 1; + } + + /* Set a reasonable step size for the numerical derivatives */ + h = fabs (h); + if (h < EPS) + h = DEFAULT_H; + + /* If input latitudes are geocentric, convert to geographic */ + if (P->geoc) + lp = pj_geocentric_latitude (P, PJ_INV, coo).lp; + + /* If latitude + one step overshoots the pole, move it slightly inside, */ + /* so the numerical derivative still exists */ + if (fabs (lp.phi) > (M_HALFPI - h)) + lp.phi = lp.phi < 0. ? -(M_HALFPI-h) : (M_HALFPI-h); + + /* Longitudinal distance from central meridian */ + lp.lam -= P->lam0; + if (!P->over) + lp.lam = adjlon(lp.lam); + + /* Derivatives */ + if (pj_deriv (lp, h, P, &(fac->der))) { + proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); + return 1; + } + + /* Scale factors */ + cosphi = cos (lp.phi); + fac->h = hypot (fac->der.x_p, fac->der.y_p); + fac->k = hypot (fac->der.x_l, fac->der.y_l) / cosphi; + + if (P->es != 0.0) { + t = sin(lp.phi); + t = 1. - P->es * t * t; + n = sqrt(t); + fac->h *= t * n / P->one_es; + fac->k *= n; + r = t * t / P->one_es; + } else + r = 1.; + + /* Convergence */ + fac->conv = -atan2 (fac->der.x_p, fac->der.y_p); + + /* Areal scale factor */ + fac->s = (fac->der.y_p * fac->der.x_l - fac->der.x_p * fac->der.y_l) * r / cosphi; + + /* Meridian-parallel angle (theta prime) */ + fac->thetap = aasin(P->ctx,fac->s / (fac->h * fac->k)); + + /* Tissot ellipse axis */ + t = fac->k * fac->k + fac->h * fac->h; + fac->a = sqrt(t + 2. * fac->s); + t = t - 2. * fac->s; + t = t > 0? sqrt(t): 0; + fac->b = 0.5 * (fac->a - t); + fac->a = 0.5 * (fac->a + t); + + /* Angular distortion */ + fac->omega = 2. * aasin(P->ctx, (fac->a - fac->b) / (fac->a + fac->b) ); + + proj_errno_restore (P, err); + return 0; +} diff --git a/src/fileapi.cpp b/src/fileapi.cpp new file mode 100644 index 00000000..3df73236 --- /dev/null +++ b/src/fileapi.cpp @@ -0,0 +1,213 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of the pj_ctx_* file api, and the default stdio + * based implementation. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2013, 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. + *****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "projects.h" + +static PAFile stdio_fopen(projCtx ctx, const char *filename, + const char *access); +static size_t stdio_fread(void *buffer, size_t size, size_t nmemb, + PAFile file); +static int stdio_fseek(PAFile file, long offset, int whence); +static long stdio_ftell(PAFile file); +static void stdio_fclose(PAFile file); + +static projFileAPI default_fileapi = { + stdio_fopen, + stdio_fread, + stdio_fseek, + stdio_ftell, + stdio_fclose +}; + +typedef struct { + projCtx ctx; + FILE *fp; +} stdio_pafile; + +/************************************************************************/ +/* pj_get_default_fileapi() */ +/************************************************************************/ + +projFileAPI *pj_get_default_fileapi(void) +{ + return &default_fileapi; +} + +/************************************************************************/ +/* stdio_fopen() */ +/************************************************************************/ + +static PAFile stdio_fopen(projCtx ctx, const char *filename, + const char *access) +{ + stdio_pafile *pafile; + FILE *fp; + + fp = fopen(filename, access); + if (fp == nullptr) + { + return nullptr; + } + + pafile = (stdio_pafile *) malloc(sizeof(stdio_pafile)); + if (!pafile) + { + pj_ctx_set_errno(ctx, ENOMEM); + fclose(fp); + return nullptr; + } + + pafile->fp = fp; + pafile->ctx = ctx; + return (PAFile) pafile; +} + +/************************************************************************/ +/* stdio_fread() */ +/************************************************************************/ + +static size_t stdio_fread(void *buffer, size_t size, size_t nmemb, + PAFile file) +{ + stdio_pafile *pafile = (stdio_pafile *) file; + return fread(buffer, size, nmemb, pafile->fp); +} + +/************************************************************************/ +/* stdio_fseek() */ +/************************************************************************/ +static int stdio_fseek(PAFile file, long offset, int whence) +{ + stdio_pafile *pafile = (stdio_pafile *) file; + return fseek(pafile->fp, offset, whence); +} + +/************************************************************************/ +/* stdio_ftell() */ +/************************************************************************/ +static long stdio_ftell(PAFile file) +{ + stdio_pafile *pafile = (stdio_pafile *) file; + return ftell(pafile->fp); +} + +/************************************************************************/ +/* stdio_fclose() */ +/************************************************************************/ +static void stdio_fclose(PAFile file) +{ + stdio_pafile *pafile = (stdio_pafile *) file; + fclose(pafile->fp); + free(pafile); +} + +/************************************************************************/ +/* pj_ctx_fopen() */ +/* */ +/* Open a file using the provided file io hooks. */ +/************************************************************************/ + +PAFile pj_ctx_fopen(projCtx ctx, const char *filename, const char *access) +{ + return ctx->fileapi->FOpen(ctx, filename, access); +} + +/************************************************************************/ +/* pj_ctx_fread() */ +/************************************************************************/ +size_t pj_ctx_fread(projCtx ctx, void *buffer, size_t size, size_t nmemb, PAFile file) +{ + return ctx->fileapi->FRead(buffer, size, nmemb, file); +} + +/************************************************************************/ +/* pj_ctx_fseek() */ +/************************************************************************/ +int pj_ctx_fseek(projCtx ctx, PAFile file, long offset, int whence) +{ + return ctx->fileapi->FSeek(file, offset, whence); +} + +/************************************************************************/ +/* pj_ctx_ftell() */ +/************************************************************************/ +long pj_ctx_ftell(projCtx ctx, PAFile file) +{ + return ctx->fileapi->FTell(file); +} + +/************************************************************************/ +/* pj_ctx_fclose() */ +/************************************************************************/ +void pj_ctx_fclose(projCtx ctx, PAFile file) +{ + ctx->fileapi->FClose(file); +} + +/************************************************************************/ +/* pj_ctx_fgets() */ +/* */ +/* A not very optimal implementation of fgets on top of */ +/* fread(). If we end up using this a lot more care should be */ +/* taken. */ +/************************************************************************/ + +char *pj_ctx_fgets(projCtx ctx, char *line, int size, PAFile file) +{ + long start = pj_ctx_ftell(ctx, file); + size_t bytes_read; + int i; + int max_size; + + line[size-1] = '\0'; + bytes_read = pj_ctx_fread(ctx, line, 1, size-1, file); + if(bytes_read == 0) + return nullptr; + if(bytes_read < (size_t)size) + { + line[bytes_read] = '\0'; + } + + max_size = (int)MIN(bytes_read, (size_t)(size > 2 ? size - 2 : 0)); + for( i = 0; i < max_size; i++) + { + if (line[i] == '\n') + { + line[i+1] = '\0'; + pj_ctx_fseek(ctx, file, start + i + 1, SEEK_SET); + break; + } + } + return line; +} diff --git a/src/fwd.cpp b/src/fwd.cpp new file mode 100644 index 00000000..e8f73999 --- /dev/null +++ b/src/fwd.cpp @@ -0,0 +1,261 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Forward operation invocation + * Author: Thomas Knudsen, thokn@sdfe.dk, 2018-01-02 + * Based on material from Gerald Evenden (original pj_fwd) + * and Piyush Agram (original pj_fwd3d) + * + ****************************************************************************** + * Copyright (c) 2000, Frank Warmerdam + * Copyright (c) 2018, Thomas Knudsen / SDFE + * + * 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. + *****************************************************************************/ + +#include +#include + +#include "proj_internal.h" +#include "proj_math.h" +#include "projects.h" + +#define INPUT_UNITS P->left +#define OUTPUT_UNITS P->right + + +static PJ_COORD fwd_prepare (PJ *P, PJ_COORD coo) { + if (HUGE_VAL==coo.v[0] || HUGE_VAL==coo.v[1] || HUGE_VAL==coo.v[2]) + return proj_coord_error (); + + /* The helmert datum shift will choke unless it gets a sensible 4D coordinate */ + if (HUGE_VAL==coo.v[2] && P->helmert) coo.v[2] = 0.0; + if (HUGE_VAL==coo.v[3] && P->helmert) coo.v[3] = 0.0; + + /* Check validity of angular input coordinates */ + if (INPUT_UNITS==PJ_IO_UNITS_ANGULAR) { + double t; + + /* check for latitude or longitude over-range */ + t = (coo.lp.phi < 0 ? -coo.lp.phi : coo.lp.phi) - M_HALFPI; + if (t > PJ_EPS_LAT || coo.lp.lam > 10 || coo.lp.lam < -10) { + proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); + return proj_coord_error (); + } + + /* Clamp latitude to -90..90 degree range */ + if (coo.lp.phi > M_HALFPI) + coo.lp.phi = M_HALFPI; + if (coo.lp.phi < -M_HALFPI) + coo.lp.phi = -M_HALFPI; + + /* If input latitude is geocentrical, convert to geographical */ + if (P->geoc) + coo = pj_geocentric_latitude (P, PJ_INV, coo); + + /* Ensure longitude is in the -pi:pi range */ + if (0==P->over) + coo.lp.lam = adjlon(coo.lp.lam); + + if (P->hgridshift) + coo = proj_trans (P->hgridshift, PJ_INV, coo); + else if (P->helmert || (P->cart_wgs84 != nullptr && P->cart != nullptr)) { + coo = proj_trans (P->cart_wgs84, PJ_FWD, coo); /* Go cartesian in WGS84 frame */ + if( P->helmert ) + coo = proj_trans (P->helmert, PJ_INV, coo); /* Step into local frame */ + coo = proj_trans (P->cart, PJ_INV, coo); /* Go back to angular using local ellps */ + } + if (coo.lp.lam==HUGE_VAL) + return coo; + if (P->vgridshift) + coo = proj_trans (P->vgridshift, PJ_FWD, coo); /* Go orthometric from geometric */ + + /* Distance from central meridian, taking system zero meridian into account */ + coo.lp.lam = (coo.lp.lam - P->from_greenwich) - P->lam0; + + /* Ensure longitude is in the -pi:pi range */ + if (0==P->over) + coo.lp.lam = adjlon(coo.lp.lam); + + return coo; + } + + + /* We do not support gridshifts on cartesian input */ + if (INPUT_UNITS==PJ_IO_UNITS_CARTESIAN && P->helmert) + return proj_trans (P->helmert, PJ_INV, coo); + return coo; +} + + +static PJ_COORD fwd_finalize (PJ *P, PJ_COORD coo) { + + switch (OUTPUT_UNITS) { + + /* Handle false eastings/northings and non-metric linear units */ + case PJ_IO_UNITS_CARTESIAN: + + if (P->is_geocent) { + coo = proj_trans (P->cart, PJ_FWD, coo); + } + coo.xyz.x *= P->fr_meter; + coo.xyz.y *= P->fr_meter; + coo.xyz.z *= P->fr_meter; + + break; + + /* Classic proj.4 functions return plane coordinates in units of the semimajor axis */ + case PJ_IO_UNITS_CLASSIC: + coo.xy.x *= P->a; + coo.xy.y *= P->a; + + /* Falls through */ /* (<-- GCC warning silencer) */ + /* to continue processing in common with PJ_IO_UNITS_PROJECTED */ + case PJ_IO_UNITS_PROJECTED: + coo.xyz.x = P->fr_meter * (coo.xyz.x + P->x0); + coo.xyz.y = P->fr_meter * (coo.xyz.y + P->y0); + coo.xyz.z = P->vfr_meter * (coo.xyz.z + P->z0); + break; + + case PJ_IO_UNITS_WHATEVER: + break; + + case PJ_IO_UNITS_ANGULAR: + coo.lpz.z = P->vfr_meter * (coo.lpz.z + P->z0); + + if( P->is_long_wrap_set ) { + if( coo.lpz.lam != HUGE_VAL ) { + coo.lpz.lam = P->long_wrap_center + + adjlon(coo.lpz.lam - P->long_wrap_center); + } + } + + break; + } + + if (P->axisswap) + coo = proj_trans (P->axisswap, PJ_FWD, coo); + + return coo; +} + + +static PJ_COORD error_or_coord(PJ *P, PJ_COORD coord, int last_errno) { + if (proj_errno(P)) + return proj_coord_error(); + + proj_errno_restore(P, last_errno); + return coord; +} + + +XY pj_fwd(LP lp, PJ *P) { + int last_errno; + PJ_COORD coo = {{0,0,0,0}}; + coo.lp = lp; + + last_errno = proj_errno_reset(P); + + if (!P->skip_fwd_prepare) + coo = fwd_prepare (P, coo); + if (HUGE_VAL==coo.v[0] || HUGE_VAL==coo.v[1]) + return proj_coord_error ().xy; + + /* Do the transformation, using the lowest dimensional transformer available */ + if (P->fwd) + coo.xy = P->fwd(coo.lp, P); + else if (P->fwd3d) + coo.xyz = P->fwd3d (coo.lpz, P); + else if (P->fwd4d) + coo = P->fwd4d (coo, P); + else { + proj_errno_set (P, EINVAL); + return proj_coord_error ().xy; + } + if (HUGE_VAL==coo.v[0]) + return proj_coord_error ().xy; + + if (!P->skip_fwd_finalize) + coo = fwd_finalize (P, coo); + + return error_or_coord(P, coo, last_errno).xy; +} + + + +XYZ pj_fwd3d(LPZ lpz, PJ *P) { + int last_errno; + PJ_COORD coo = {{0,0,0,0}}; + coo.lpz = lpz; + + last_errno = proj_errno_reset(P); + + if (!P->skip_fwd_prepare) + coo = fwd_prepare (P, coo); + if (HUGE_VAL==coo.v[0]) + return proj_coord_error ().xyz; + + /* Do the transformation, using the lowest dimensional transformer feasible */ + if (P->fwd3d) + coo.xyz = P->fwd3d(coo.lpz, P); + else if (P->fwd4d) + coo = P->fwd4d (coo, P); + else if (P->fwd) + coo.xy = P->fwd (coo.lp, P); + else { + proj_errno_set (P, EINVAL); + return proj_coord_error ().xyz; + } + if (HUGE_VAL==coo.v[0]) + return proj_coord_error ().xyz; + + if (!P->skip_fwd_finalize) + coo = fwd_finalize (P, coo); + + return error_or_coord(P, coo, last_errno).xyz; +} + + + +PJ_COORD pj_fwd4d (PJ_COORD coo, PJ *P) { + int last_errno = proj_errno_reset(P); + + if (!P->skip_fwd_prepare) + coo = fwd_prepare (P, coo); + if (HUGE_VAL==coo.v[0]) + return proj_coord_error (); + + /* Call the highest dimensional converter available */ + if (P->fwd4d) + coo = P->fwd4d (coo, P); + else if (P->fwd3d) + coo.xyz = P->fwd3d (coo.lpz, P); + else if (P->fwd) + coo.xy = P->fwd (coo.lp, P); + else { + proj_errno_set (P, EINVAL); + return proj_coord_error (); + } + if (HUGE_VAL==coo.v[0]) + return proj_coord_error (); + + if (!P->skip_fwd_finalize) + coo = fwd_finalize (P, coo); + + return error_or_coord(P, coo, last_errno); +} diff --git a/src/gauss.cpp b/src/gauss.cpp new file mode 100644 index 00000000..2db713ad --- /dev/null +++ b/src/gauss.cpp @@ -0,0 +1,103 @@ +/* +** 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 + +#include "projects.h" + +#define MAX_ITER 20 + +namespace { // anonymous namespace +struct GAUSS { + double C; + double K; + double e; + double ratexp; +}; +} // anonymous namespace +#define DEL_TOL 1e-14 + +static double srat(double esinp, double ratexp) { + return(pow((1.-esinp)/(1.+esinp), ratexp)); +} + +void *pj_gauss_ini(double e, double phi0, double *chi, double *rc) { + double sphi, cphi, es; + struct GAUSS *en; + + if ((en = (struct GAUSS *)malloc(sizeof(struct GAUSS))) == nullptr) + return (nullptr); + es = e * e; + en->e = e; + sphi = sin(phi0); + cphi = cos(phi0); cphi *= cphi; + *rc = sqrt(1. - es) / (1. - es * sphi * sphi); + en->C = sqrt(1. + es * cphi * cphi / (1. - es)); + if (en->C == 0.0) { + free(en); + return nullptr; + } + *chi = asin(sphi / en->C); + en->ratexp = 0.5 * en->C * e; + en->K = tan(.5 * *chi + M_FORTPI) / ( + pow(tan(.5 * phi0 + M_FORTPI), en->C) * + srat(en->e * sphi, en->ratexp) ); + return ((void *)en); +} + +LP pj_gauss(projCtx ctx, LP elp, const void *data) { + const struct GAUSS *en = (const struct GAUSS *)data; + LP slp; + (void) ctx; + + slp.phi = 2. * atan( en->K * + pow(tan(.5 * elp.phi + M_FORTPI), en->C) * + srat(en->e * sin(elp.phi), en->ratexp) ) - M_HALFPI; + slp.lam = en->C * (elp.lam); + return(slp); +} + +LP pj_inv_gauss(projCtx ctx, LP slp, const void *data) { + const struct GAUSS *en = (const struct GAUSS *)data; + LP elp; + double num; + int i; + + elp.lam = slp.lam / en->C; + num = pow(tan(.5 * slp.phi + M_FORTPI)/en->K, 1./en->C); + for (i = MAX_ITER; i; --i) { + elp.phi = 2. * atan(num * srat(en->e * sin(slp.phi), -.5 * en->e)) + - M_HALFPI; + if (fabs(elp.phi - slp.phi) < DEL_TOL) break; + slp.phi = elp.phi; + } + /* convergence failed */ + if (!i) + pj_ctx_set_errno(ctx, PJD_ERR_NON_CONV_INV_MERI_DIST); + return (elp); +} diff --git a/src/gc_reader.cpp b/src/gc_reader.cpp new file mode 100644 index 00000000..118aadf6 --- /dev/null +++ b/src/gc_reader.cpp @@ -0,0 +1,247 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Code to read a grid catalog from a .cvs file. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2012, 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include +#include +#include + +#include "projects.h" + +static int gc_readentry(projCtx ctx, PAFile fid, PJ_GridCatalogEntry *entry); + +/************************************************************************/ +/* pj_gc_readcatalog() */ +/* */ +/* Read a grid catalog from a .csv file. */ +/************************************************************************/ + +PJ_GridCatalog *pj_gc_readcatalog( projCtx ctx, const char *catalog_name ) +{ + PAFile fid; + PJ_GridCatalog *catalog; + int entry_max; + char line[302]; + + fid = pj_open_lib( ctx, catalog_name, "r" ); + if (fid == nullptr) + return nullptr; + + /* discard title line */ + pj_ctx_fgets(ctx, line, sizeof(line)-1, fid); + + catalog = (PJ_GridCatalog *) calloc(1,sizeof(PJ_GridCatalog)); + if( !catalog ) + { + pj_ctx_set_errno(ctx, ENOMEM); + pj_ctx_fclose(ctx, fid); + return nullptr; + } + + catalog->catalog_name = pj_strdup(catalog_name); + if (!catalog->catalog_name) { + pj_ctx_set_errno(ctx, ENOMEM); + free(catalog); + pj_ctx_fclose(ctx, fid); + return nullptr; + } + + entry_max = 10; + catalog->entries = (PJ_GridCatalogEntry *) + malloc(entry_max * sizeof(PJ_GridCatalogEntry)); + if (!catalog->entries) { + pj_ctx_set_errno(ctx, ENOMEM); + free(catalog->catalog_name); + free(catalog); + pj_ctx_fclose(ctx, fid); + return nullptr; + } + + while( gc_readentry( ctx, fid, + catalog->entries+catalog->entry_count) == 0) + { + catalog->entry_count++; + + if( catalog->entry_count == entry_max ) + { + PJ_GridCatalogEntry* new_entries; + entry_max = entry_max * 2; + new_entries = (PJ_GridCatalogEntry *) + realloc(catalog->entries, + entry_max * sizeof(PJ_GridCatalogEntry)); + if (new_entries == nullptr ) + { + int i; + for( i = 0; i < catalog->entry_count; i++ ) + free( catalog->entries[i].definition ); + free( catalog->entries ); + free( catalog->catalog_name ); + free( catalog ); + pj_ctx_fclose(ctx, fid); + return nullptr; + } + catalog->entries = new_entries; + } + } + + pj_ctx_fclose(ctx, fid); + + return catalog; +} + +/************************************************************************/ +/* gc_read_csv_line() */ +/* */ +/* Simple csv line splitter with fixed maximum line size and */ +/* token count. */ +/************************************************************************/ + +static int gc_read_csv_line( projCtx ctx, PAFile fid, + char **tokens, int max_tokens ) +{ + char line[302]; + + while( pj_ctx_fgets(ctx, line, sizeof(line)-1, fid) != nullptr ) + { + char *next = line; + int token_count = 0; + + while( isspace(*next) ) + next++; + + /* skip blank and comment lines */ + if( next[0] == '#' || next[0] == '\0' ) + continue; + + while( token_count < max_tokens && *next != '\0' ) + { + const char *start = next; + char* token; + + while( *next != '\0' && *next != ',' ) + next++; + + if( *next == ',' ) + { + *next = '\0'; + next++; + } + + token = pj_strdup(start); + if (!token) { + while (token_count > 0) + free(tokens[--token_count]); + pj_ctx_set_errno(ctx, ENOMEM); + return 0; + } + tokens[token_count++] = token; + } + + return token_count; + } + + return 0; +} + +/************************************************************************/ +/* pj_gc_parsedate() */ +/* */ +/* Parse a date into a floating point year value. Acceptable */ +/* values are "yyyy.fraction" and "yyyy-mm-dd". Anything else */ +/* returns 0.0. */ +/************************************************************************/ + +double pj_gc_parsedate( projCtx ctx, const char *date_string ) +{ + (void) ctx; + + if( strlen(date_string) == 10 + && date_string[4] == '-' && date_string[7] == '-' ) + { + int year = atoi(date_string); + int month = atoi(date_string+5); + int day = atoi(date_string+8); + + /* simplified calculation so we don't need to know all about months */ + return year + ((month-1) * 31 + (day-1)) / 372.0; + } + else + { + return pj_atof(date_string); + } +} + + +/************************************************************************/ +/* gc_readentry() */ +/* */ +/* Read one catalog entry from the file */ +/* */ +/* Format: */ +/* gridname,ll_long,ll_lat,ur_long,ur_lat,priority,date */ +/************************************************************************/ + +static int gc_readentry(projCtx ctx, PAFile fid, PJ_GridCatalogEntry *entry) +{ +#define MAX_TOKENS 30 + char *tokens[MAX_TOKENS]; + int token_count, i; + int error = 0; + + memset( entry, 0, sizeof(PJ_GridCatalogEntry) ); + + token_count = gc_read_csv_line( ctx, fid, tokens, MAX_TOKENS ); + if( token_count < 5 ) + { + error = 1; /* TODO: need real error codes */ + if( token_count != 0 ) + pj_log( ctx, PJ_LOG_ERROR, "Short line in grid catalog." ); + } + else + { + entry->definition = tokens[0]; + tokens[0] = nullptr; /* We take ownership of tokens[0] */ + entry->region.ll_long = dmstor_ctx( ctx, tokens[1], nullptr ); + entry->region.ll_lat = dmstor_ctx( ctx, tokens[2], nullptr ); + entry->region.ur_long = dmstor_ctx( ctx, tokens[3], nullptr ); + entry->region.ur_lat = dmstor_ctx( ctx, tokens[4], nullptr ); + if( token_count > 5 ) + entry->priority = atoi( tokens[5] ); /* defaults to zero */ + if( token_count > 6 ) + entry->date = pj_gc_parsedate( ctx, tokens[6] ); + } + + for( i = 0; i < token_count; i++ ) + free( tokens[i] ); + + return error; +} + + + diff --git a/src/gridcatalog.cpp b/src/gridcatalog.cpp new file mode 100644 index 00000000..fef2df56 --- /dev/null +++ b/src/gridcatalog.cpp @@ -0,0 +1,295 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Code in support of grid catalogs + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2012, 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include +#include +#include + +#include "projects.h" + +static PJ_GridCatalog *grid_catalog_list = nullptr; + +/************************************************************************/ +/* pj_gc_unloadall() */ +/* */ +/* Deallocate all the grid catalogs (but not the referenced */ +/* grids). */ +/************************************************************************/ + +void pj_gc_unloadall( projCtx ctx ) +{ + (void) ctx; + + while( grid_catalog_list != nullptr ) + { + int i; + PJ_GridCatalog *catalog = grid_catalog_list; + grid_catalog_list = grid_catalog_list->next; + + for( i = 0; i < catalog->entry_count; i++ ) + { + /* we don't own gridinfo - do not free here */ + free( catalog->entries[i].definition ); + } + free( catalog->entries ); + free( catalog->catalog_name ); + free( catalog ); + } +} + +/************************************************************************/ +/* pj_gc_findcatalog() */ +/************************************************************************/ + +PJ_GridCatalog *pj_gc_findcatalog( projCtx ctx, const char *name ) + +{ + PJ_GridCatalog *catalog; + + pj_acquire_lock(); + + for( catalog=grid_catalog_list; catalog != nullptr; catalog = catalog->next ) + { + if( strcmp(catalog->catalog_name, name) == 0 ) + { + pj_release_lock(); + return catalog; + } + } + + pj_release_lock(); + + catalog = pj_gc_readcatalog( ctx, name ); + if( catalog == nullptr ) + return nullptr; + + pj_acquire_lock(); + catalog->next = grid_catalog_list; + grid_catalog_list = catalog; + pj_release_lock(); + + return catalog; +} + +/************************************************************************/ +/* pj_gc_apply_gridshift() */ +/************************************************************************/ + +int pj_gc_apply_gridshift( PJ *defn, int inverse, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + int i; + (void) z; + + if( defn->catalog == nullptr ) + { + defn->catalog = pj_gc_findcatalog( defn->ctx, defn->catalog_name ); + if( defn->catalog == nullptr ) + return defn->ctx->last_errno; + } + + defn->ctx->last_errno = 0; + + for( i = 0; i < point_count; i++ ) + { + long io = i * point_offset; + LP input, output_after, output_before; + double mix_ratio; + PJ_GRIDINFO *gi; + + input.phi = y[io]; + input.lam = x[io]; + + /* make sure we have appropriate "after" shift file available */ + if( defn->last_after_grid == nullptr + || input.lam < defn->last_after_region.ll_long + || input.lam > defn->last_after_region.ur_long + || input.phi < defn->last_after_region.ll_lat + || input.phi > defn->last_after_region.ll_lat ) { + defn->last_after_grid = + pj_gc_findgrid( defn->ctx, defn->catalog, + 1, input, defn->datum_date, + &(defn->last_after_region), + &(defn->last_after_date)); + if( defn->last_after_grid == nullptr ) + { + pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return PJD_ERR_FAILED_TO_LOAD_GRID; + } + } + gi = defn->last_after_grid; + assert( gi->child == nullptr ); + + /* load the grid shift info if we don't have it. */ + if( gi->ct->cvs == nullptr && !pj_gridinfo_load( defn->ctx, gi ) ) + { + pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return PJD_ERR_FAILED_TO_LOAD_GRID; + } + + output_after = nad_cvt( input, inverse, gi->ct ); + if( output_after.lam == HUGE_VAL ) + { + if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) + { + pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR, + "pj_apply_gridshift(): failed to find a grid shift table for\n" + " location (%.7fdW,%.7fdN)", + x[io] * RAD_TO_DEG, + y[io] * RAD_TO_DEG ); + } + continue; + } + + if( defn->datum_date == 0.0 ) + { + y[io] = output_after.phi; + x[io] = output_after.lam; + continue; + } + + /* make sure we have appropriate "before" shift file available */ + if( defn->last_before_grid == nullptr + || input.lam < defn->last_before_region.ll_long + || input.lam > defn->last_before_region.ur_long + || input.phi < defn->last_before_region.ll_lat + || input.phi > defn->last_before_region.ll_lat ) { + defn->last_before_grid = + pj_gc_findgrid( defn->ctx, defn->catalog, + 0, input, defn->datum_date, + &(defn->last_before_region), + &(defn->last_before_date)); + if( defn->last_before_grid == nullptr ) + { + pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return PJD_ERR_FAILED_TO_LOAD_GRID; + } + } + + gi = defn->last_before_grid; + assert( gi->child == nullptr ); + + /* load the grid shift info if we don't have it. */ + if( gi->ct->cvs == nullptr && !pj_gridinfo_load( defn->ctx, gi ) ) + { + pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return PJD_ERR_FAILED_TO_LOAD_GRID; + } + + output_before = nad_cvt( input, inverse, gi->ct ); + if( output_before.lam == HUGE_VAL ) + { + if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) + { + pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR, + "pj_apply_gridshift(): failed to find a grid shift table for\n" + " location (%.7fdW,%.7fdN)", + x[io] * RAD_TO_DEG, + y[io] * RAD_TO_DEG ); + } + continue; + } + + mix_ratio = (defn->datum_date - defn->last_before_date) + / (defn->last_after_date - defn->last_before_date); + + y[io] = mix_ratio * output_after.phi + + (1.0-mix_ratio) * output_before.phi; + x[io] = mix_ratio * output_after.lam + + (1.0-mix_ratio) * output_before.lam; + } + + return 0; +} + +/************************************************************************/ +/* pj_c_findgrid() */ +/************************************************************************/ + +PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx, PJ_GridCatalog *catalog, int after, + LP location, double date, + PJ_Region *optional_region, + double *grid_date ) +{ + int iEntry; + PJ_GridCatalogEntry *entry = nullptr; + + for( iEntry = 0; iEntry < catalog->entry_count; iEntry++ ) + { + entry = catalog->entries + iEntry; + + if( (after && entry->date < date) + || (!after && entry->date > date) ) + continue; + + if( location.lam < entry->region.ll_long + || location.lam > entry->region.ur_long + || location.phi < entry->region.ll_lat + || location.phi > entry->region.ur_lat ) + continue; + + if( entry->available == -1 ) + continue; + + break; + } + + if( entry == nullptr ) + { + if( grid_date ) + *grid_date = 0.0; + if( optional_region != nullptr ) + memset( optional_region, 0, sizeof(PJ_Region)); + return nullptr; + } + + if( grid_date ) + *grid_date = entry->date; + + if( optional_region ) + { + + } + + if( entry->gridinfo == nullptr ) + { + PJ_GRIDINFO **gridlist = nullptr; + int grid_count = 0; + gridlist = pj_gridlist_from_nadgrids( ctx, entry->definition, + &grid_count); + if( grid_count == 1 ) + entry->gridinfo = gridlist[0]; + } + + return entry->gridinfo; +} + diff --git a/src/gridinfo.cpp b/src/gridinfo.cpp new file mode 100644 index 00000000..046abfcc --- /dev/null +++ b/src/gridinfo.cpp @@ -0,0 +1,991 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Functions for handling individual PJ_GRIDINFO's. Includes + * loaders for all formats but CTABLE (in nad_init.c). + * 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include +#include +#include +#include +#include + +#include "proj_internal.h" +#include "projects.h" + +/************************************************************************/ +/* swap_words() */ +/* */ +/* Convert the byte order of the given word(s) in place. */ +/************************************************************************/ + +static const int byte_order_test = 1; +#define IS_LSB (1 == ((const unsigned char *) (&byte_order_test))[0]) + +static void swap_words( unsigned char *data, int word_size, int word_count ) + +{ + int word; + + for( word = 0; word < word_count; word++ ) + { + int i; + + for( i = 0; i < word_size/2; i++ ) + { + unsigned char t; + + t = data[i]; + data[i] = data[word_size-i-1]; + data[word_size-i-1] = t; + } + + data += word_size; + } +} + +/************************************************************************/ +/* to_double() */ +/* */ +/* Returns a double from the pointed data. */ +/************************************************************************/ + +static double to_double( unsigned char* data ) +{ + double d; + memcpy(&d, data, sizeof(d)); + return d; +} + +/************************************************************************/ +/* pj_gridinfo_free() */ +/************************************************************************/ + +void pj_gridinfo_free( projCtx ctx, PJ_GRIDINFO *gi ) + +{ + if( gi == nullptr ) + return; + + if( gi->child != nullptr ) + { + PJ_GRIDINFO *child, *next; + + for( child = gi->child; child != nullptr; child=next) + { + next=child->next; + pj_gridinfo_free( ctx, child ); + } + } + + if( gi->ct != nullptr ) + nad_free( gi->ct ); + + free( gi->gridname ); + if( gi->filename != nullptr ) + free( gi->filename ); + + pj_dalloc( gi ); +} + +/************************************************************************/ +/* pj_gridinfo_load() */ +/* */ +/* This function is intended to implement delayed loading of */ +/* the data contents of a grid file. The header and related */ +/* stuff are loaded by pj_gridinfo_init(). */ +/************************************************************************/ + +int pj_gridinfo_load( projCtx ctx, PJ_GRIDINFO *gi ) + +{ + struct CTABLE ct_tmp; + + if( gi == nullptr || gi->ct == nullptr ) + return 0; + + pj_acquire_lock(); + if( gi->ct->cvs != nullptr ) + { + pj_release_lock(); + return 1; + } + + memcpy(&ct_tmp, gi->ct, sizeof(struct CTABLE)); + +/* -------------------------------------------------------------------- */ +/* Original platform specific CTable format. */ +/* -------------------------------------------------------------------- */ + if( strcmp(gi->format,"ctable") == 0 ) + { + PAFile fid; + int result; + + fid = pj_open_lib( ctx, gi->filename, "rb" ); + + if( fid == nullptr ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return 0; + } + + result = nad_ctable_load( ctx, &ct_tmp, fid ); + + pj_ctx_fclose( ctx, fid ); + + gi->ct->cvs = ct_tmp.cvs; + pj_release_lock(); + + return result; + } + +/* -------------------------------------------------------------------- */ +/* CTable2 format. */ +/* -------------------------------------------------------------------- */ + else if( strcmp(gi->format,"ctable2") == 0 ) + { + PAFile fid; + int result; + + fid = pj_open_lib( ctx, gi->filename, "rb" ); + + if( fid == nullptr ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return 0; + } + + result = nad_ctable2_load( ctx, &ct_tmp, fid ); + + pj_ctx_fclose( ctx, fid ); + + gi->ct->cvs = ct_tmp.cvs; + + pj_release_lock(); + return result; + } + +/* -------------------------------------------------------------------- */ +/* NTv1 format. */ +/* We process one line at a time. Note that the array storage */ +/* direction (e-w) is different in the NTv1 file and what */ +/* the CTABLE is supposed to have. The phi/lam are also */ +/* reversed, and we have to be aware of byte swapping. */ +/* -------------------------------------------------------------------- */ + else if( strcmp(gi->format,"ntv1") == 0 ) + { + double *row_buf; + int row; + PAFile fid; + + fid = pj_open_lib( ctx, gi->filename, "rb" ); + + if( fid == nullptr ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return 0; + } + + pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); + + row_buf = (double *) pj_malloc(gi->ct->lim.lam * sizeof(double) * 2); + ct_tmp.cvs = (FLP *) pj_malloc(gi->ct->lim.lam*gi->ct->lim.phi*sizeof(FLP)); + if( row_buf == nullptr || ct_tmp.cvs == nullptr ) + { + pj_dalloc( row_buf ); + pj_dalloc( ct_tmp.cvs ); + pj_ctx_set_errno( ctx, ENOMEM ); + pj_release_lock(); + return 0; + } + + for( row = 0; row < gi->ct->lim.phi; row++ ) + { + int i; + FLP *cvs; + double *diff_seconds; + + if( pj_ctx_fread( ctx, row_buf, + sizeof(double), gi->ct->lim.lam * 2, fid ) + != (size_t)( 2 * gi->ct->lim.lam ) ) + { + pj_dalloc( row_buf ); + pj_dalloc( ct_tmp.cvs ); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return 0; + } + + if( IS_LSB ) + swap_words( (unsigned char *) row_buf, 8, gi->ct->lim.lam*2 ); + + /* convert seconds to radians */ + diff_seconds = row_buf; + + for( i = 0; i < gi->ct->lim.lam; i++ ) + { + cvs = ct_tmp.cvs + (row) * gi->ct->lim.lam + + (gi->ct->lim.lam - i - 1); + + cvs->phi = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); + cvs->lam = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); + } + } + + pj_dalloc( row_buf ); + + pj_ctx_fclose( ctx, fid ); + + gi->ct->cvs = ct_tmp.cvs; + pj_release_lock(); + + return 1; + } + +/* -------------------------------------------------------------------- */ +/* NTv2 format. */ +/* We process one line at a time. Note that the array storage */ +/* direction (e-w) is different in the NTv2 file and what */ +/* the CTABLE is supposed to have. The phi/lam are also */ +/* reversed, and we have to be aware of byte swapping. */ +/* -------------------------------------------------------------------- */ + else if( strcmp(gi->format,"ntv2") == 0 ) + { + float *row_buf; + int row; + PAFile fid; + + pj_log( ctx, PJ_LOG_DEBUG_MINOR, + "NTv2 - loading grid %s", gi->ct->id ); + + fid = pj_open_lib( ctx, gi->filename, "rb" ); + + if( fid == nullptr ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return 0; + } + + pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); + + row_buf = (float *) pj_malloc(gi->ct->lim.lam * sizeof(float) * 4); + ct_tmp.cvs = (FLP *) pj_malloc(gi->ct->lim.lam*gi->ct->lim.phi*sizeof(FLP)); + if( row_buf == nullptr || ct_tmp.cvs == nullptr ) + { + pj_dalloc( row_buf ); + pj_dalloc( ct_tmp.cvs ); + pj_ctx_set_errno( ctx, ENOMEM ); + pj_release_lock(); + return 0; + } + + for( row = 0; row < gi->ct->lim.phi; row++ ) + { + int i; + FLP *cvs; + float *diff_seconds; + + if( pj_ctx_fread( ctx, row_buf, sizeof(float), + gi->ct->lim.lam*4, fid ) + != (size_t)( 4 * gi->ct->lim.lam ) ) + { + pj_dalloc( row_buf ); + pj_dalloc( ct_tmp.cvs ); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return 0; + } + + if( gi->must_swap ) + swap_words( (unsigned char *) row_buf, 4, + gi->ct->lim.lam*4 ); + + /* convert seconds to radians */ + diff_seconds = row_buf; + + for( i = 0; i < gi->ct->lim.lam; i++ ) + { + cvs = ct_tmp.cvs + (row) * gi->ct->lim.lam + + (gi->ct->lim.lam - i - 1); + + cvs->phi = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); + cvs->lam = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); + diff_seconds += 2; /* skip accuracy values */ + } + } + + pj_dalloc( row_buf ); + + pj_ctx_fclose( ctx, fid ); + + gi->ct->cvs = ct_tmp.cvs; + + pj_release_lock(); + return 1; + } + +/* -------------------------------------------------------------------- */ +/* GTX format. */ +/* -------------------------------------------------------------------- */ + else if( strcmp(gi->format,"gtx") == 0 ) + { + int words = gi->ct->lim.lam * gi->ct->lim.phi; + PAFile fid; + + fid = pj_open_lib( ctx, gi->filename, "rb" ); + + if( fid == nullptr ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return 0; + } + + pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); + + ct_tmp.cvs = (FLP *) pj_malloc(words*sizeof(float)); + if( ct_tmp.cvs == nullptr ) + { + pj_ctx_set_errno( ctx, ENOMEM ); + pj_release_lock(); + return 0; + } + + if( pj_ctx_fread( ctx, ct_tmp.cvs, sizeof(float), words, fid ) + != (size_t)words ) + { + pj_dalloc( ct_tmp.cvs ); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return 0; + } + + if( IS_LSB ) + swap_words( (unsigned char *) ct_tmp.cvs, 4, words ); + + pj_ctx_fclose( ctx, fid ); + gi->ct->cvs = ct_tmp.cvs; + pj_release_lock(); + return 1; + } + + else + { + pj_release_lock(); + return 0; + } +} + +/************************************************************************/ +/* gridinfo_parent() */ +/* */ +/* Seek a parent grid file by name from a grid list */ +/************************************************************************/ + +static PJ_GRIDINFO* gridinfo_parent( PJ_GRIDINFO *gilist, + const char *name, int length ) +{ + while( gilist ) + { + if( strncmp(gilist->ct->id,name,length) == 0 ) return gilist; + if( gilist->child ) + { + PJ_GRIDINFO *parent=gridinfo_parent( gilist->child, name, length ); + if( parent ) return parent; + } + gilist=gilist->next; + } + return gilist; +} + +/************************************************************************/ +/* pj_gridinfo_init_ntv2() */ +/* */ +/* Load a ntv2 (.gsb) file. */ +/************************************************************************/ + +static int pj_gridinfo_init_ntv2( projCtx ctx, PAFile fid, PJ_GRIDINFO *gilist ) +{ + unsigned char header[11*16]; + int num_subfiles, subfile; + int must_swap; + + /* cppcheck-suppress sizeofCalculation */ + STATIC_ASSERT( sizeof(pj_int32) == 4 ); + /* cppcheck-suppress sizeofCalculation */ + STATIC_ASSERT( sizeof(double) == 8 ); + +/* -------------------------------------------------------------------- */ +/* Read the overview header. */ +/* -------------------------------------------------------------------- */ + if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return 0; + } + + if( header[8] == 11 ) + must_swap = !IS_LSB; + else + must_swap = IS_LSB; + +/* -------------------------------------------------------------------- */ +/* Byte swap interesting fields if needed. */ +/* -------------------------------------------------------------------- */ + if( must_swap ) + { + swap_words( header+8, 4, 1 ); + swap_words( header+8+16, 4, 1 ); + swap_words( header+8+32, 4, 1 ); + swap_words( header+8+7*16, 8, 1 ); + swap_words( header+8+8*16, 8, 1 ); + swap_words( header+8+9*16, 8, 1 ); + swap_words( header+8+10*16, 8, 1 ); + } + +/* -------------------------------------------------------------------- */ +/* Get the subfile count out ... all we really use for now. */ +/* -------------------------------------------------------------------- */ + memcpy( &num_subfiles, header+8+32, 4 ); + +/* ==================================================================== */ +/* Step through the subfiles, creating a PJ_GRIDINFO for each. */ +/* ==================================================================== */ + for( subfile = 0; subfile < num_subfiles; subfile++ ) + { + struct CTABLE *ct; + LP ur; + int gs_count; + PJ_GRIDINFO *gi; + +/* -------------------------------------------------------------------- */ +/* Read header. */ +/* -------------------------------------------------------------------- */ + if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return 0; + } + + if( strncmp((const char *) header,"SUB_NAME",8) != 0 ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Byte swap interesting fields if needed. */ +/* -------------------------------------------------------------------- */ + if( must_swap ) + { + swap_words( header+8+16*4, 8, 1 ); + swap_words( header+8+16*5, 8, 1 ); + swap_words( header+8+16*6, 8, 1 ); + swap_words( header+8+16*7, 8, 1 ); + swap_words( header+8+16*8, 8, 1 ); + swap_words( header+8+16*9, 8, 1 ); + swap_words( header+8+16*10, 4, 1 ); + } + +/* -------------------------------------------------------------------- */ +/* Initialize a corresponding "ct" structure. */ +/* -------------------------------------------------------------------- */ + ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); + if (!ct) { + pj_ctx_set_errno(ctx, ENOMEM); + return 0; + } + strncpy( ct->id, (const char *) header + 8, 8 ); + ct->id[8] = '\0'; + + ct->ll.lam = - to_double(header+7*16+8); /* W_LONG */ + ct->ll.phi = to_double(header+4*16+8); /* S_LAT */ + + ur.lam = - to_double(header+6*16+8); /* E_LONG */ + ur.phi = to_double(header+5*16+8); /* N_LAT */ + + ct->del.lam = to_double(header+9*16+8); + ct->del.phi = to_double(header+8*16+8); + + ct->lim.lam = (pj_int32) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1; + ct->lim.phi = (pj_int32) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1; + + pj_log( ctx, PJ_LOG_DEBUG_MINOR, + "NTv2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", + ct->id, + ct->lim.lam, ct->lim.phi, + ct->ll.lam/3600.0, ct->ll.phi/3600.0, + ur.lam/3600.0, ur.phi/3600.0 ); + + ct->ll.lam *= DEG_TO_RAD/3600.0; + ct->ll.phi *= DEG_TO_RAD/3600.0; + ct->del.lam *= DEG_TO_RAD/3600.0; + ct->del.phi *= DEG_TO_RAD/3600.0; + + memcpy( &gs_count, header + 8 + 16*10, 4 ); + if( gs_count != ct->lim.lam * ct->lim.phi ) + { + pj_log( ctx, PJ_LOG_ERROR, + "GS_COUNT(%d) does not match expected cells (%dx%d=%d)", + gs_count, ct->lim.lam, ct->lim.phi, + ct->lim.lam * ct->lim.phi ); + pj_dalloc(ct); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return 0; + } + + ct->cvs = nullptr; + +/* -------------------------------------------------------------------- */ +/* Create a new gridinfo for this if we aren't processing the */ +/* 1st subfile, and initialize our grid info. */ +/* -------------------------------------------------------------------- */ + if( subfile == 0 ) + gi = gilist; + else + { + gi = (PJ_GRIDINFO *) pj_calloc(1, sizeof(PJ_GRIDINFO)); + if (!gi) { + pj_dalloc(ct); + pj_gridinfo_free(ctx, gilist); + pj_ctx_set_errno(ctx, ENOMEM); + return 0; + } + + gi->gridname = pj_strdup( gilist->gridname ); + gi->filename = pj_strdup( gilist->filename ); + if (!gi->gridname || !gi->filename) { + pj_gridinfo_free(ctx, gi); + pj_dalloc(ct); + pj_gridinfo_free(ctx, gilist); + pj_ctx_set_errno(ctx, ENOMEM); + return 0; + } + gi->next = nullptr; + } + + gi->must_swap = must_swap; + gi->ct = ct; + gi->format = "ntv2"; + gi->grid_offset = pj_ctx_ftell( ctx, fid ); + +/* -------------------------------------------------------------------- */ +/* Attach to the correct list or sublist. */ +/* -------------------------------------------------------------------- */ + if( strncmp((const char *)header+24,"NONE",4) == 0 ) + { + if( gi != gilist ) + { + PJ_GRIDINFO *lnk; + + for( lnk = gilist; lnk->next != nullptr; lnk = lnk->next ) {} + lnk->next = gi; + } + } + + else + { + PJ_GRIDINFO *lnk; + PJ_GRIDINFO *gp = gridinfo_parent(gilist, + (const char*)header+24,8); + + if( gp == nullptr ) + { + pj_log( ctx, PJ_LOG_ERROR, + "pj_gridinfo_init_ntv2(): " + "failed to find parent %8.8s for %s.", + (const char *) header+24, gi->ct->id ); + + for( lnk = gilist; lnk->next != nullptr; lnk = lnk->next ) {} + lnk->next = gi; + } + else + { + if( gp->child == nullptr ) + { + gp->child = gi; + } + else + { + for( lnk = gp->child; lnk->next != nullptr; lnk = lnk->next ) {} + lnk->next = gi; + } + } + } + +/* -------------------------------------------------------------------- */ +/* Seek past the data. */ +/* -------------------------------------------------------------------- */ + pj_ctx_fseek( ctx, fid, gs_count * 16, SEEK_CUR ); + } + + return 1; +} + +/************************************************************************/ +/* pj_gridinfo_init_ntv1() */ +/* */ +/* Load an NTv1 style Canadian grid shift file. */ +/************************************************************************/ + +static int pj_gridinfo_init_ntv1( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi ) + +{ + unsigned char header[192]; /* 12 records of 16 bytes */ + struct CTABLE *ct; + LP ur; + + /* cppcheck-suppress sizeofCalculation */ + STATIC_ASSERT( sizeof(pj_int32) == 4 ); + /* cppcheck-suppress sizeofCalculation */ + STATIC_ASSERT( sizeof(double) == 8 ); + +/* -------------------------------------------------------------------- */ +/* Read the header. */ +/* -------------------------------------------------------------------- */ + if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Regularize fields of interest. */ +/* -------------------------------------------------------------------- */ + if( IS_LSB ) + { + swap_words( header+8, 4, 1 ); + swap_words( header+24, 8, 1 ); + swap_words( header+40, 8, 1 ); + swap_words( header+56, 8, 1 ); + swap_words( header+72, 8, 1 ); + swap_words( header+88, 8, 1 ); + swap_words( header+104, 8, 1 ); + } + + if( *((int *) (header+8)) != 12 ) + { + pj_log( ctx, PJ_LOG_ERROR, + "NTv1 grid shift file has wrong record count, corrupt?" ); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Fill in CTABLE structure. */ +/* -------------------------------------------------------------------- */ + ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); + if (!ct) { + pj_ctx_set_errno(ctx, ENOMEM); + return 0; + } + strcpy( ct->id, "NTv1 Grid Shift File" ); + + ct->ll.lam = - to_double(header+72); + ct->ll.phi = to_double(header+24); + ur.lam = - to_double(header+56); + ur.phi = to_double(header+40); + ct->del.lam = to_double(header+104); + ct->del.phi = to_double(header+88); + ct->lim.lam = (pj_int32) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1; + ct->lim.phi = (pj_int32) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1; + + pj_log( ctx, PJ_LOG_DEBUG_MINOR, + "NTv1 %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", + ct->lim.lam, ct->lim.phi, + ct->ll.lam, ct->ll.phi, ur.lam, ur.phi ); + + ct->ll.lam *= DEG_TO_RAD; + ct->ll.phi *= DEG_TO_RAD; + ct->del.lam *= DEG_TO_RAD; + ct->del.phi *= DEG_TO_RAD; + ct->cvs = nullptr; + + gi->ct = ct; + gi->grid_offset = (long) sizeof(header); + gi->format = "ntv1"; + + return 1; +} + +/************************************************************************/ +/* pj_gridinfo_init_gtx() */ +/* */ +/* Load a NOAA .gtx vertical datum shift file. */ +/************************************************************************/ + +static int pj_gridinfo_init_gtx( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi ) + +{ + unsigned char header[40]; + struct CTABLE *ct; + double xorigin,yorigin,xstep,ystep; + int rows, columns; + + /* cppcheck-suppress sizeofCalculation */ + STATIC_ASSERT( sizeof(pj_int32) == 4 ); + /* cppcheck-suppress sizeofCalculation */ + STATIC_ASSERT( sizeof(double) == 8 ); + +/* -------------------------------------------------------------------- */ +/* Read the header. */ +/* -------------------------------------------------------------------- */ + if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) + { + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Regularize fields of interest and extract. */ +/* -------------------------------------------------------------------- */ + if( IS_LSB ) + { + swap_words( header+0, 8, 4 ); + swap_words( header+32, 4, 2 ); + } + + memcpy( &yorigin, header+0, 8 ); + memcpy( &xorigin, header+8, 8 ); + memcpy( &ystep, header+16, 8 ); + memcpy( &xstep, header+24, 8 ); + + memcpy( &rows, header+32, 4 ); + memcpy( &columns, header+36, 4 ); + + if( xorigin < -360 || xorigin > 360 + || yorigin < -90 || yorigin > 90 ) + { + pj_log( ctx, PJ_LOG_ERROR, + "gtx file header has invalid extents, corrupt?"); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + return 0; + } + +/* -------------------------------------------------------------------- */ +/* Fill in CTABLE structure. */ +/* -------------------------------------------------------------------- */ + ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); + if (!ct) { + pj_ctx_set_errno(ctx, ENOMEM); + return 0; + } + strcpy( ct->id, "GTX Vertical Grid Shift File" ); + + ct->ll.lam = xorigin; + ct->ll.phi = yorigin; + ct->del.lam = xstep; + ct->del.phi = ystep; + ct->lim.lam = columns; + ct->lim.phi = rows; + + /* some GTX files come in 0-360 and we shift them back into the + expected -180 to 180 range if possible. This does not solve + problems with grids spanning the dateline. */ + if( ct->ll.lam >= 180.0 ) + ct->ll.lam -= 360.0; + + if( ct->ll.lam >= 0.0 && ct->ll.lam + ct->del.lam * ct->lim.lam > 180.0 ) + { + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "This GTX spans the dateline! This will cause problems." ); + } + + pj_log( ctx, PJ_LOG_DEBUG_MINOR, + "GTX %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", + ct->lim.lam, ct->lim.phi, + ct->ll.lam, ct->ll.phi, + ct->ll.lam + (columns-1)*xstep, ct->ll.phi + (rows-1)*ystep); + + ct->ll.lam *= DEG_TO_RAD; + ct->ll.phi *= DEG_TO_RAD; + ct->del.lam *= DEG_TO_RAD; + ct->del.phi *= DEG_TO_RAD; + ct->cvs = nullptr; + + gi->ct = ct; + gi->grid_offset = 40; + gi->format = "gtx"; + + return 1; +} + +/************************************************************************/ +/* pj_gridinfo_init() */ +/* */ +/* Open and parse header details from a datum gridshift file */ +/* returning a list of PJ_GRIDINFOs for the grids in that */ +/* file. This superceeds use of nad_init() for modern */ +/* applications. */ +/************************************************************************/ + +PJ_GRIDINFO *pj_gridinfo_init( projCtx ctx, const char *gridname ) + +{ + char fname[MAX_PATH_FILENAME+1]; + PJ_GRIDINFO *gilist; + PAFile fp; + char header[160]; + size_t header_size = 0; + + errno = pj_errno = 0; + ctx->last_errno = 0; + +/* -------------------------------------------------------------------- */ +/* Initialize a GRIDINFO with stub info we would use if it */ +/* cannot be loaded. */ +/* -------------------------------------------------------------------- */ + gilist = (PJ_GRIDINFO *) pj_calloc(1, sizeof(PJ_GRIDINFO)); + if (!gilist) { + pj_ctx_set_errno(ctx, ENOMEM); + return nullptr; + } + + gilist->gridname = pj_strdup( gridname ); + if (!gilist->gridname) { + pj_dalloc(gilist); + pj_ctx_set_errno(ctx, ENOMEM); + return nullptr; + } + gilist->filename = nullptr; + gilist->format = "missing"; + gilist->grid_offset = 0; + gilist->ct = nullptr; + gilist->next = nullptr; + +/* -------------------------------------------------------------------- */ +/* Open the file using the usual search rules. */ +/* -------------------------------------------------------------------- */ + strcpy(fname, gridname); + if (!(fp = pj_open_lib(ctx, fname, "rb"))) { + ctx->last_errno = 0; /* don't treat as a persistent error */ + return gilist; + } + + gilist->filename = pj_strdup(fname); + if (!gilist->filename) { + pj_dalloc(gilist->gridname); + pj_dalloc(gilist); + pj_ctx_set_errno(ctx, ENOMEM); + return nullptr; + } + +/* -------------------------------------------------------------------- */ +/* Load a header, to determine the file type. */ +/* -------------------------------------------------------------------- */ + if( (header_size = pj_ctx_fread( ctx, header, 1, + sizeof(header), fp ) ) != sizeof(header) ) + { + /* some files may be smaller that sizeof(header), eg 160, so */ + ctx->last_errno = 0; /* don't treat as a persistent error */ + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "pj_gridinfo_init: short header read of %d bytes", + (int)header_size ); + } + + pj_ctx_fseek( ctx, fp, SEEK_SET, 0 ); + +/* -------------------------------------------------------------------- */ +/* Determine file type. */ +/* -------------------------------------------------------------------- */ + if( header_size >= 144 + 16 + && strncmp(header + 0, "HEADER", 6) == 0 + && strncmp(header + 96, "W GRID", 6) == 0 + && strncmp(header + 144, "TO NAD83 ", 16) == 0 ) + { + pj_gridinfo_init_ntv1( ctx, fp, gilist ); + } + + else if( header_size >= 48 + 7 + && strncmp(header + 0, "NUM_OREC", 8) == 0 + && strncmp(header + 48, "GS_TYPE", 7) == 0 ) + { + pj_gridinfo_init_ntv2( ctx, fp, gilist ); + } + + else if( strlen(gridname) > 4 + && (strcmp(gridname+strlen(gridname)-3,"gtx") == 0 + || strcmp(gridname+strlen(gridname)-3,"GTX") == 0) ) + { + pj_gridinfo_init_gtx( ctx, fp, gilist ); + } + + else if( header_size >= 9 && strncmp(header + 0,"CTABLE V2",9) == 0 ) + { + struct CTABLE *ct = nad_ctable2_init( ctx, fp ); + + gilist->format = "ctable2"; + gilist->ct = ct; + + if (ct == nullptr) + { + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "CTABLE V2 ct is NULL."); + } + else + { + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "Ctable2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", + ct->id, + ct->lim.lam, ct->lim.phi, + ct->ll.lam * RAD_TO_DEG, ct->ll.phi * RAD_TO_DEG, + (ct->ll.lam + (ct->lim.lam-1)*ct->del.lam) * RAD_TO_DEG, + (ct->ll.phi + (ct->lim.phi-1)*ct->del.phi) * RAD_TO_DEG ); + } + } + + else + { + struct CTABLE *ct = nad_ctable_init( ctx, fp ); + if (ct == nullptr) + { + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "CTABLE ct is NULL."); + } else + { + gilist->format = "ctable"; + gilist->ct = ct; + + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "Ctable %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", + ct->id, + ct->lim.lam, ct->lim.phi, + ct->ll.lam * RAD_TO_DEG, ct->ll.phi * RAD_TO_DEG, + (ct->ll.lam + (ct->lim.lam-1)*ct->del.lam) * RAD_TO_DEG, + (ct->ll.phi + (ct->lim.phi-1)*ct->del.phi) * RAD_TO_DEG ); + } + } + + pj_ctx_fclose(ctx, fp); + + return gilist; +} diff --git a/src/gridlist.cpp b/src/gridlist.cpp new file mode 100644 index 00000000..169abcb9 --- /dev/null +++ b/src/gridlist.cpp @@ -0,0 +1,219 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Code to manage the list of currently loaded (cached) PJ_GRIDINFOs + * See pj_gridinfo.c for details of loading individual grids. + * 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include +#include + +#include "projects.h" + +static PJ_GRIDINFO *grid_list = nullptr; +#define PJ_MAX_PATH_LENGTH 1024 + +/************************************************************************/ +/* pj_deallocate_grids() */ +/* */ +/* Deallocate all loaded grids. */ +/************************************************************************/ + +void pj_deallocate_grids() + +{ + while( grid_list != nullptr ) + { + PJ_GRIDINFO *item = grid_list; + grid_list = grid_list->next; + item->next = nullptr; + + pj_gridinfo_free( pj_get_default_ctx(), item ); + } +} + +/************************************************************************/ +/* pj_gridlist_merge_grid() */ +/* */ +/* Find/load the named gridfile and merge it into the */ +/* last_nadgrids_list. */ +/************************************************************************/ + +static int pj_gridlist_merge_gridfile( projCtx ctx, + const char *gridname, + PJ_GRIDINFO ***p_gridlist, + int *p_gridcount, + int *p_gridmax ) + +{ + int got_match=0; + PJ_GRIDINFO *this_grid, *tail = nullptr; + +/* -------------------------------------------------------------------- */ +/* Try to find in the existing list of loaded grids. Add all */ +/* matching grids as with NTv2 we can get many grids from one */ +/* file (one shared gridname). */ +/* -------------------------------------------------------------------- */ + for( this_grid = grid_list; this_grid != nullptr; this_grid = this_grid->next) + { + if( strcmp(this_grid->gridname,gridname) == 0 ) + { + got_match = 1; + + /* don't add to the list if it is invalid. */ + if( this_grid->ct == nullptr ) + return 0; + + /* do we need to grow the list? */ + if( *p_gridcount >= *p_gridmax - 2 ) + { + PJ_GRIDINFO **new_list; + int new_max = *p_gridmax + 20; + + new_list = (PJ_GRIDINFO **) pj_calloc(new_max, sizeof(void *)); + if (!new_list) { + pj_ctx_set_errno( ctx, ENOMEM ); + return 0; + } + if( *p_gridlist != nullptr ) + { + memcpy( new_list, *p_gridlist, + sizeof(void *) * (*p_gridmax) ); + pj_dalloc( *p_gridlist ); + } + + *p_gridlist = new_list; + *p_gridmax = new_max; + } + + /* add to the list */ + (*p_gridlist)[(*p_gridcount)++] = this_grid; + (*p_gridlist)[*p_gridcount] = nullptr; + } + + tail = this_grid; + } + + if( got_match ) + return 1; + +/* -------------------------------------------------------------------- */ +/* Try to load the named grid. */ +/* -------------------------------------------------------------------- */ + this_grid = pj_gridinfo_init( ctx, gridname ); + + if( this_grid == nullptr ) + { + return 0; + } + + if( tail != nullptr ) + tail->next = this_grid; + else + grid_list = this_grid; + +/* -------------------------------------------------------------------- */ +/* Recurse to add the grid now that it is loaded. */ +/* -------------------------------------------------------------------- */ + return pj_gridlist_merge_gridfile( ctx, gridname, p_gridlist, + p_gridcount, p_gridmax ); +} + +/************************************************************************/ +/* pj_gridlist_from_nadgrids() */ +/* */ +/* This functions loads the list of grids corresponding to a */ +/* particular nadgrids string into a list, and returns it. The */ +/* list is kept around till a request is made with a different */ +/* string in order to cut down on the string parsing cost, and */ +/* the cost of building the list of tables each time. */ +/************************************************************************/ + +PJ_GRIDINFO **pj_gridlist_from_nadgrids( projCtx ctx, const char *nadgrids, + int *grid_count) + +{ + const char *s; + PJ_GRIDINFO **gridlist = nullptr; + int grid_max = 0; + + pj_errno = 0; + *grid_count = 0; + + pj_acquire_lock(); + +/* -------------------------------------------------------------------- */ +/* Loop processing names out of nadgrids one at a time. */ +/* -------------------------------------------------------------------- */ + for( s = nadgrids; *s != '\0'; ) + { + size_t end_char; + int required = 1; + char name[PJ_MAX_PATH_LENGTH]; + + if( *s == '@' ) + { + required = 0; + s++; + } + + for( end_char = 0; + s[end_char] != '\0' && s[end_char] != ','; + end_char++ ) {} + + if( end_char >= sizeof(name) ) + { + pj_dalloc( gridlist ); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return nullptr; + } + + strncpy( name, s, end_char ); + name[end_char] = '\0'; + + s += end_char; + if( *s == ',' ) + s++; + + if( !pj_gridlist_merge_gridfile( ctx, name, &gridlist, grid_count, + &grid_max) + && required ) + { + pj_dalloc( gridlist ); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); + pj_release_lock(); + return nullptr; + } + else + pj_errno = 0; + } + + pj_release_lock(); + + return gridlist; +} diff --git a/src/init.cpp b/src/init.cpp new file mode 100644 index 00000000..5710031c --- /dev/null +++ b/src/init.cpp @@ -0,0 +1,888 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Initialize projection object from string definition. Includes + * pj_init(), pj_init_plus() and pj_free() function. + * Author: Gerald Evenden, Frank Warmerdam + * + ****************************************************************************** + * Copyright (c) 1995, Gerald Evenden + * Copyright (c) 2002, 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include +#include +#include +#include +#include + +#include "geodesic.h" +#include "proj.h" +#include "proj_internal.h" +#include "proj_math.h" +#include "projects.h" + + +/**************************************************************************************/ +static paralist *string_to_paralist (PJ_CONTEXT *ctx, char *definition) { +/*************************************************************************************** + Convert a string (presumably originating from get_init_string) to a paralist. +***************************************************************************************/ + char *c = definition; + paralist *first = nullptr, *next = nullptr; + + while (*c) { + /* Find start of next substring */ + while (isspace (*c)) + c++; + + /* Keep a handle to the start of the list, so we have something to return */ + if (nullptr==first) + first = next = pj_mkparam_ws (c); + else + next = next->next = pj_mkparam_ws (c); + if (nullptr==next) { + pj_dealloc_params (ctx, first, ENOMEM); + return nullptr; + } + + /* And skip to the end of the substring */ + while ((!isspace(*c)) && 0!=*c) + c++; + } + + if( next == nullptr ) + return nullptr; + + /* Terminate list and return */ + next->next = nullptr; + return first; +} + + + +/**************************************************************************************/ +static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { +/*************************************************************************************** + Read a section of an init file. Return its contents as a plain character string. + It is the duty of the caller to free the memory allocated for the string. +***************************************************************************************/ +#define MAX_LINE_LENGTH 1000 + size_t current_buffer_size = 5 * (MAX_LINE_LENGTH + 1); + char *fname, *section; + const char *key; + char *buffer = nullptr; + char *line = nullptr; + PAFile fid; + size_t n; + + + line = static_cast(pj_malloc (MAX_LINE_LENGTH + 1)); + if (nullptr==line) + return nullptr; + + fname = static_cast(pj_malloc (MAX_PATH_FILENAME+ID_TAG_MAX+3)); + if (nullptr==fname) { + pj_dealloc (line); + return nullptr; + } + + /* Support "init=file:section", "+init=file:section", and "file:section" format */ + key = strstr (name, "init="); + if (nullptr==key) + key = name; + else + key += 5; + if (MAX_PATH_FILENAME + ID_TAG_MAX + 2 < strlen (key)) { + pj_dealloc (fname); + pj_dealloc (line); + return nullptr; + } + memmove (fname, key, strlen (key) + 1); + + /* Locate the name of the section we search for */ + section = strrchr(fname, ':'); + if (nullptr==section) { + proj_context_errno_set (ctx, PJD_ERR_NO_COLON_IN_INIT_STRING); + pj_dealloc (fname); + pj_dealloc (line); + return nullptr; + } + *section = 0; + section++; + n = strlen (section); + pj_log (ctx, PJ_LOG_TRACE, + "get_init_string: searching for section [%s] in init file [%s]", + section, fname); + + fid = pj_open_lib (ctx, fname, "rt"); + if (nullptr==fid) { + pj_dealloc (fname); + pj_dealloc (line); + proj_context_errno_set (ctx, PJD_ERR_NO_OPTION_IN_INIT_FILE); + return nullptr; + } + + /* Search for section in init file */ + for (;;) { + + /* End of file? */ + if (nullptr==pj_ctx_fgets (ctx, line, MAX_LINE_LENGTH, fid)) { + pj_dealloc (buffer); + pj_dealloc (fname); + pj_dealloc (line); + pj_ctx_fclose (ctx, fid); + proj_context_errno_set (ctx, PJD_ERR_NO_OPTION_IN_INIT_FILE); + return nullptr; + } + + /* At start of right section? */ + pj_chomp (line); + if ('<'!=line[0]) + continue; + if (strlen (line) < n + 2) + continue; + if (line[n + 1] != '>') + continue; + if (0==strncmp (line + 1, section, n)) + break; + } + + /* We're at the first line of the right section - copy line to buffer */ + buffer = static_cast(pj_malloc (current_buffer_size)); + if (nullptr==buffer) { + pj_dealloc (fname); + pj_dealloc (line); + pj_ctx_fclose (ctx, fid); + return nullptr; + } + + /* Skip the "
" indicator, and copy the rest of the line over */ + strcpy (buffer, line + strlen (section) + 2); + + /* Copy the remaining lines of the section to buffer */ + for (;;) { + char *end_i_cator; + size_t next_length, buffer_length; + + /* Did the section end somewhere in the most recently read line? */ + end_i_cator = strchr (buffer, '<'); + if (end_i_cator) { + *end_i_cator = 0; + break; + } + + /* End of file? - done! */ + if (nullptr==pj_ctx_fgets (ctx, line, MAX_LINE_LENGTH, fid)) + break; + + /* Otherwise, handle the line. It MAY be the start of the next section, */ + /* but that will be handled at the start of next trip through the loop */ + buffer_length = strlen (buffer); + pj_chomp (line); /* Remove '#' style comments */ + next_length = strlen (line) + buffer_length + 2; + if (next_length > current_buffer_size) { + char *b = static_cast(pj_malloc (2 * current_buffer_size)); + if (nullptr==b) { + pj_dealloc (buffer); + buffer = nullptr; + break; + } + strcpy (b, buffer); + current_buffer_size *= 2; + pj_dealloc (buffer); + buffer = b; + } + buffer[buffer_length] = ' '; + strcpy (buffer + buffer_length + 1, line); + } + + pj_ctx_fclose (ctx, fid); + pj_dealloc (fname); + pj_dealloc (line); + if (nullptr==buffer) + return nullptr; + pj_shrink (buffer); + pj_log (ctx, PJ_LOG_TRACE, "key=%s, value: [%s]", key, buffer); + return buffer; +} + + + +/************************************************************************/ +static paralist *get_init(PJ_CONTEXT *ctx, const char *key, int allow_init_epsg) { +/************************************************************************* +Expand key from buffer or (if not in buffer) from init file +*************************************************************************/ + const char *xkey; + char *definition = nullptr; + paralist *init_items = nullptr; + + /* support "init=file:section", "+init=file:section", and "file:section" format */ + xkey = strstr (key, "init="); + if (nullptr==xkey) + xkey = key; + else + xkey += 5; + pj_log (ctx, PJ_LOG_TRACE, "get_init: searching cache for key: [%s]", xkey); + + /* Is file/key pair already in cache? */ + init_items = pj_search_initcache (xkey); + if (init_items) + return init_items; + + if( (strncmp(xkey, "epsg:", 5) == 0 || strncmp(xkey, "IGNF:", 5) == 0) ) { + char unused[256]; + char initname[5]; + int exists; + + memcpy(initname, xkey, 4); + initname[4] = 0; + + if( strncmp(xkey, "epsg:", 5) == 0 ) { + exists = ctx->epsg_file_exists; + if( exists < 0 ) { + exists = pj_find_file(ctx, initname, unused, sizeof(unused)); + ctx->epsg_file_exists = exists; + } + } else { + exists = pj_find_file(ctx, initname, unused, sizeof(unused)); + } + + if( !exists ) { + const char* const optionsProj4Mode[] = { "USE_PROJ4_INIT_RULES=YES", nullptr }; + char szInitStr[7 + 64]; + PJ_OBJ* src; + const char* proj_string; + + pj_ctx_set_errno( ctx, 0 ); + + if( !allow_init_epsg ) { + pj_log (ctx, PJ_LOG_TRACE, "%s expansion disallowed", xkey); + return nullptr; + } + if( strlen(xkey) > 64 ) { + return nullptr; + } + strcpy(szInitStr, "+init="); + strcat(szInitStr, xkey); + + src = proj_obj_create_from_user_input(ctx, szInitStr, optionsProj4Mode); + if( !src ) { + return nullptr; + } + + proj_string = proj_obj_as_proj_string(ctx, src, PJ_PROJ_4, nullptr); + if( !proj_string ) { + proj_obj_destroy(src); + return nullptr; + } + definition = (char*)calloc(1, strlen(proj_string)+1); + if( definition ) { + strcpy(definition, proj_string); + } + + proj_obj_destroy(src); + } + } + + if( !definition ) { + /* If not, we must read it from file */ + pj_log (ctx, PJ_LOG_TRACE, + "get_init: searching on in init files for [%s]", xkey); + definition = get_init_string (ctx, xkey); + } + + if (nullptr==definition) + return nullptr; + init_items = string_to_paralist (ctx, definition); + if (init_items) + pj_log (ctx, PJ_LOG_TRACE, "get_init: got [%s], paralist[0,1]: [%s,%s]", + definition, + init_items->param, + init_items->next ? init_items->next->param : "(empty)"); + pj_dealloc (definition); + if (nullptr==init_items) + return nullptr; + + /* We found it in file - now insert into the cache, before returning */ + pj_insert_initcache (xkey, init_items); + return init_items; +} + + + +static paralist *append_defaults_to_paralist (PJ_CONTEXT *ctx, paralist *start, const char *key, int allow_init_epsg) { + paralist *defaults, *last = nullptr; + char keystring[ID_TAG_MAX + 20]; + paralist *next, *proj; + int err; + + if (nullptr==start) + return nullptr; + + if (strlen(key) > ID_TAG_MAX) + return nullptr; + + /* Set defaults, unless inhibited (either explicitly through a "no_defs" token */ + /* or implicitly, because we are initializing a pipeline) */ + if (pj_param_exists (start, "no_defs")) + return start; + proj = pj_param_exists (start, "proj"); + if (nullptr==proj) + return start; + if (strlen (proj->param) < 6) + return start; + if (0==strcmp ("pipeline", proj->param + 5)) + return start; + + err = pj_ctx_get_errno (ctx); + pj_ctx_set_errno (ctx, 0); + + /* Locate end of start-list */ + for (last = start; last->next; last = last->next); + + strcpy (keystring, "proj_def.dat:"); + strcat (keystring, key); + defaults = get_init (ctx, keystring, allow_init_epsg); + + /* Defaults are optional - so we don't care if we cannot open the file */ + pj_ctx_set_errno (ctx, err); + + if (!defaults) + return last; + + /* Loop over all default items */ + for (next = defaults; next; next = next->next) { + + /* Don't override existing parameter value of same name */ + if (pj_param_exists (start, next->param)) + continue; + + /* Don't default ellipse if datum, ellps or any ellipsoid information is set */ + if (0==strncmp(next->param,"ellps=", 6)) { + if (pj_param_exists (start, "datum")) continue; + if (pj_param_exists (start, "ellps")) continue; + if (pj_param_exists (start, "a")) continue; + if (pj_param_exists (start, "b")) continue; + if (pj_param_exists (start, "rf")) continue; + if (pj_param_exists (start, "f")) continue; + if (pj_param_exists (start, "e")) continue; + if (pj_param_exists (start, "es")) continue; + } + + /* If we're here, it's OK to append the current default item */ + last = last->next = pj_mkparam(next->param); + } + last->next = nullptr; + + pj_dealloc_params (ctx, defaults, 0); + return last; +} + +/*****************************************************************************/ +static paralist *pj_expand_init_internal(PJ_CONTEXT *ctx, paralist *init, int allow_init_epsg) { +/****************************************************************************** +Append expansion of to the paralist . The expansion is appended, +rather than inserted at 's place, since may contain +overrides to the expansion. These must take precedence, and hence come first +in the expanded list. + +Consider e.g. the key 'foo:bar' which (hypothetically) expands to 'proj=utm +zone=32 ellps=GRS80', i.e. a UTM projection on the GRS80 ellipsoid. + +The expression 'init=foo:bar ellps=intl' will then expand to: + + 'init=foo:bar ellps=intl proj=utm zone=32 ellps=GRS80', + +where 'ellps=intl' precedes 'ellps=GRS80', and hence takes precedence, +turning the expansion into an UTM projection on the Hayford ellipsoid. + +Note that 'init=foo:bar' stays in the list. It is ignored after expansion. + +******************************************************************************/ + paralist *last; + paralist *expn; + + /* Nowhere to start? */ + if (nullptr==init) + return nullptr; + + expn = get_init(ctx, init->param, allow_init_epsg); + + /* Nothing in expansion? */ + if (nullptr==expn) + return nullptr; + + /* Locate the end of the list */ + for (last = init; last && last->next; last = last->next); + + /* Then append and return */ + last->next = expn; + return init; +} + +paralist *pj_expand_init(PJ_CONTEXT *ctx, paralist *init) { + return pj_expand_init_internal(ctx, init, TRUE); +} + + +/************************************************************************/ +/* pj_init_plus() */ +/* */ +/* Same as pj_init() except it takes one argument string with */ +/* individual arguments preceded by '+', such as "+proj=utm */ +/* +zone=11 +ellps=WGS84". */ +/************************************************************************/ + +PJ * +pj_init_plus( const char *definition ) + +{ + return pj_init_plus_ctx( pj_get_default_ctx(), definition ); +} + +PJ * +pj_init_plus_ctx( projCtx ctx, const char *definition ) +{ +#define MAX_ARG 200 + char *argv[MAX_ARG]; + char *defn_copy; + int argc = 0, i, blank_count = 0; + PJ *result = nullptr; + + /* make a copy that we can manipulate */ + defn_copy = (char *) pj_malloc( strlen(definition)+1 ); + if (!defn_copy) + return nullptr; + strcpy( defn_copy, definition ); + + /* split into arguments based on '+' and trim white space */ + + for( i = 0; defn_copy[i] != '\0'; i++ ) + { + switch( defn_copy[i] ) + { + case '+': + if( i == 0 || defn_copy[i-1] == '\0' || blank_count > 0 ) + { + /* trim trailing spaces from the previous param */ + if( blank_count > 0 ) + { + defn_copy[i - blank_count] = '\0'; + blank_count = 0; + } + + if( argc+1 == MAX_ARG ) + { + pj_dalloc( defn_copy ); + pj_ctx_set_errno( ctx, PJD_ERR_UNPARSEABLE_CS_DEF ); + return nullptr; + } + + argv[argc++] = defn_copy + i + 1; + } + break; + + case ' ': + case '\t': + case '\n': + /* trim leading spaces from the current param */ + if( i == 0 || defn_copy[i-1] == '\0' || argc == 0 || argv[argc-1] == defn_copy + i ) + defn_copy[i] = '\0'; + else + blank_count++; + break; + + default: + /* reset blank_count */ + blank_count = 0; + } + } + /* trim trailing spaces from the last param */ + defn_copy[i - blank_count] = '\0'; + + /* perform actual initialization */ + result = pj_init_ctx( ctx, argc, argv ); + + pj_dalloc( defn_copy ); + return result; +} + + + +/************************************************************************/ +/* pj_init() */ +/* */ +/* Main entry point for initialing a PJ projections */ +/* definition. Note that the projection specific function is */ +/* called to do the initial allocation so it can be created */ +/* large enough to hold projection specific parameters. */ +/************************************************************************/ + +PJ * +pj_init(int argc, char **argv) { + return pj_init_ctx( pj_get_default_ctx(), argc, argv ); +} + + +static PJ_CONSTRUCTOR locate_constructor (const char *name) { + int i; + const char *s; + const PJ_OPERATIONS *operations; + operations = proj_list_operations(); + for (i = 0; (s = operations[i].id) && strcmp(name, s) ; ++i) ; + if (nullptr==s) + return nullptr; + return (PJ_CONSTRUCTOR) operations[i].proj; +} + + +PJ * +pj_init_ctx(projCtx ctx, int argc, char **argv) { + /* Legacy interface: allow init=epsg:XXXX syntax by default */ + int allow_init_epsg = proj_context_get_use_proj4_init_rules(ctx, TRUE); + return pj_init_ctx_with_allow_init_epsg(ctx, argc, argv, allow_init_epsg); +} + + +PJ * +pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_init_epsg) { + const char *s; + char *name; + PJ_CONSTRUCTOR proj; + paralist *curr, *init, *start; + int i; + int err; + PJ *PIN = nullptr; + int n_pipelines = 0; + int n_inits = 0; + const PJ_UNITS *units; + const PJ_PRIME_MERIDIANS *prime_meridians; + + if (nullptr==ctx) + ctx = pj_get_default_ctx (); + + ctx->last_errno = 0; + + if (argc <= 0) { + pj_ctx_set_errno (ctx, PJD_ERR_NO_ARGS); + return nullptr; + } + + /* count occurrences of pipelines and inits */ + for (i = 0; i < argc; ++i) { + if (!strcmp (argv[i], "+proj=pipeline") || !strcmp(argv[i], "proj=pipeline") ) + n_pipelines++; + if (!strncmp (argv[i], "+init=", 6) || !strncmp(argv[i], "init=", 5)) + n_inits++; + } + + /* can't have nested pipelines directly */ + if (n_pipelines > 1) { + pj_ctx_set_errno (ctx, PJD_ERR_MALFORMED_PIPELINE); + return nullptr; + } + + /* don't allow more than one +init in non-pipeline operations */ + if (n_pipelines == 0 && n_inits > 1) { + pj_ctx_set_errno (ctx, PJD_ERR_TOO_MANY_INITS); + return nullptr; + } + + + /* put arguments into internal linked list */ + start = curr = pj_mkparam(argv[0]); + if (!curr) { + pj_dealloc_params (ctx, start, ENOMEM); + return nullptr; + } + + for (i = 1; i < argc; ++i) { + curr->next = pj_mkparam(argv[i]); + if (!curr->next) { + pj_dealloc_params (ctx, start, ENOMEM); + return nullptr; + } + curr = curr->next; + } + + + /* Only expand '+init's in non-pipeline operations. '+init's in pipelines are */ + /* expanded in the individual pipeline steps during pipeline initialization. */ + /* Potentially this leads to many nested pipelines, which shouldn't be a */ + /* problem when '+init's are expanded as late as possible. */ + init = pj_param_exists (start, "init"); + if (init && n_pipelines == 0) { + init = pj_expand_init_internal (ctx, init, allow_init_epsg); + if (!init) { + pj_dealloc_params (ctx, start, PJD_ERR_NO_ARGS); + return nullptr; + } + } + if (ctx->last_errno) { + pj_dealloc_params (ctx, start, ctx->last_errno); + return nullptr; + } + + /* Find projection selection */ + curr = pj_param_exists (start, "proj"); + if (nullptr==curr) { + pj_dealloc_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); + return nullptr; + } + name = curr->param; + if (strlen (name) < 6) { + pj_dealloc_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); + return nullptr; + } + name += 5; + + proj = locate_constructor (name); + if (nullptr==proj) { + pj_dealloc_params (ctx, start, PJD_ERR_UNKNOWN_PROJECTION_ID); + return nullptr; + } + + + /* Append general and projection specific defaults to the definition list */ + append_defaults_to_paralist (ctx, start, "general", allow_init_epsg); + append_defaults_to_paralist (ctx, start, name, allow_init_epsg); + + + /* Allocate projection structure */ + PIN = proj(nullptr); + if (nullptr==PIN) { + pj_dealloc_params (ctx, start, ENOMEM); + return nullptr; + } + + + PIN->ctx = ctx; + PIN->params = start; + PIN->is_latlong = 0; + PIN->is_geocent = 0; + PIN->is_long_wrap_set = 0; + PIN->long_wrap_center = 0.0; + strcpy( PIN->axis, "enu" ); + + PIN->gridlist = nullptr; + PIN->gridlist_count = 0; + + PIN->vgridlist_geoid = nullptr; + PIN->vgridlist_geoid_count = 0; + + /* Set datum parameters. Similarly to +init parameters we want to expand */ + /* +datum parameters as late as possible when dealing with pipelines. */ + /* otherwise only the first occurrence of +datum will be expanded and that */ + if (n_pipelines == 0) { + if (pj_datum_set(ctx, start, PIN)) + return pj_default_destructor (PIN, proj_errno(PIN)); + } + + err = pj_ellipsoid (PIN); + + if (err) { + /* Didn't get an ellps, but doesn't need one: Get a free WGS84 */ + if (PIN->need_ellps) { + pj_log (ctx, PJ_LOG_DEBUG_MINOR, "pj_init_ctx: Must specify ellipsoid or sphere"); + return pj_default_destructor (PIN, proj_errno(PIN)); + } + else { + if (PJD_ERR_MAJOR_AXIS_NOT_GIVEN==proj_errno (PIN)) + proj_errno_reset (PIN); + PIN->f = 1.0/298.257223563; + PIN->a_orig = PIN->a = 6378137.0; + PIN->es_orig = PIN->es = PIN->f*(2-PIN->f); + } + } + PIN->a_orig = PIN->a; + PIN->es_orig = PIN->es; + if (pj_calc_ellipsoid_params (PIN, PIN->a, PIN->es)) + return pj_default_destructor (PIN, PJD_ERR_ECCENTRICITY_IS_ONE); + + /* Now that we have ellipse information check for WGS84 datum */ + if( PIN->datum_type == PJD_3PARAM + && PIN->datum_params[0] == 0.0 + && PIN->datum_params[1] == 0.0 + && PIN->datum_params[2] == 0.0 + && PIN->a == 6378137.0 + && ABS(PIN->es - 0.006694379990) < 0.000000000050 )/*WGS84/GRS80*/ + { + PIN->datum_type = PJD_WGS84; + } + + /* Set PIN->geoc coordinate system */ + PIN->geoc = (PIN->es != 0.0 && pj_param(ctx, start, "bgeoc").i); + + /* Over-ranging flag */ + PIN->over = pj_param(ctx, start, "bover").i; + + /* Vertical datum geoid grids */ + PIN->has_geoid_vgrids = pj_param(ctx, start, "tgeoidgrids").i; + if( PIN->has_geoid_vgrids ) /* we need to mark it as used. */ + pj_param(ctx, start, "sgeoidgrids"); + + /* Longitude center for wrapping */ + PIN->is_long_wrap_set = pj_param(ctx, start, "tlon_wrap").i; + if (PIN->is_long_wrap_set) { + PIN->long_wrap_center = pj_param(ctx, start, "rlon_wrap").f; + /* Don't accept excessive values otherwise we might perform badly */ + /* when correcting longitudes around it */ + /* The test is written this way to error on long_wrap_center "=" NaN */ + if( !(fabs(PIN->long_wrap_center) < 10 * M_TWOPI) ) + return pj_default_destructor (PIN, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); + } + + /* Axis orientation */ + if( (pj_param(ctx, start,"saxis").s) != nullptr ) + { + const char *axis_legal = "ewnsud"; + const char *axis_arg = pj_param(ctx, start,"saxis").s; + if( strlen(axis_arg) != 3 ) + return pj_default_destructor (PIN, PJD_ERR_AXIS); + + if( strchr( axis_legal, axis_arg[0] ) == nullptr + || strchr( axis_legal, axis_arg[1] ) == nullptr + || strchr( axis_legal, axis_arg[2] ) == nullptr) + return pj_default_destructor (PIN, PJD_ERR_AXIS); + + /* TODO: it would be nice to validate we don't have on axis repeated */ + strcpy( PIN->axis, axis_arg ); + } + + /* Central meridian */ + PIN->lam0=pj_param(ctx, start, "rlon_0").f; + + /* Central latitude */ + PIN->phi0 = pj_param(ctx, start, "rlat_0").f; + + /* False easting and northing */ + PIN->x0 = pj_param(ctx, start, "dx_0").f; + PIN->y0 = pj_param(ctx, start, "dy_0").f; + PIN->z0 = pj_param(ctx, start, "dz_0").f; + PIN->t0 = pj_param(ctx, start, "dt_0").f; + + /* General scaling factor */ + if (pj_param(ctx, start, "tk_0").i) + PIN->k0 = pj_param(ctx, start, "dk_0").f; + else if (pj_param(ctx, start, "tk").i) + PIN->k0 = pj_param(ctx, start, "dk").f; + else + PIN->k0 = 1.; + if (PIN->k0 <= 0.) + return pj_default_destructor (PIN, PJD_ERR_K_LESS_THAN_ZERO); + + /* Set units */ + units = proj_list_units(); + s = nullptr; + if ((name = pj_param(ctx, start, "sunits").s) != nullptr) { + for (i = 0; (s = units[i].id) && strcmp(name, s) ; ++i) ; + if (!s) + return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_UNIT_ID); + s = units[i].to_meter; + } + if (s || (s = pj_param(ctx, start, "sto_meter").s)) { + double factor; + int ratio = 0; + + /* ratio number? */ + if (strlen (s) > 1 && s[0] == '1' && s[1]=='/') { + ratio = 1; + s += 2; + } + + factor = pj_strtod(s, nullptr); + if ((factor <= 0.0) || (1/factor==0)) + return pj_default_destructor (PIN, PJD_ERR_UNIT_FACTOR_LESS_THAN_0); + + PIN->to_meter = ratio? 1 / factor: factor; + PIN->fr_meter = 1 / PIN->to_meter; + + } else + PIN->to_meter = PIN->fr_meter = 1.; + + /* Set vertical units */ + s = nullptr; + if ((name = pj_param(ctx, start, "svunits").s) != nullptr) { + for (i = 0; (s = units[i].id) && strcmp(name, s) ; ++i) ; + if (!s) + return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_UNIT_ID); + s = units[i].to_meter; + } + if (s || (s = pj_param(ctx, start, "svto_meter").s)) { + PIN->vto_meter = pj_strtod(s, nullptr); + if (*s == '/') /* ratio number */ + PIN->vto_meter /= pj_strtod(++s, nullptr); + if (PIN->vto_meter <= 0.0) + return pj_default_destructor (PIN, PJD_ERR_UNIT_FACTOR_LESS_THAN_0); + PIN->vfr_meter = 1. / PIN->vto_meter; + } else { + PIN->vto_meter = PIN->to_meter; + PIN->vfr_meter = PIN->fr_meter; + } + + /* Prime meridian */ + prime_meridians = proj_list_prime_meridians(); + s = nullptr; + if ((name = pj_param(ctx, start, "spm").s) != nullptr) { + const char *value = nullptr; + char *next_str = nullptr; + + for (i = 0; prime_meridians[i].id != nullptr; ++i ) + { + if( strcmp(name,prime_meridians[i].id) == 0 ) + { + value = prime_meridians[i].defn; + break; + } + } + + if( value == nullptr + && (dmstor_ctx(ctx,name,&next_str) != 0.0 || *name == '0') + && *next_str == '\0' ) + value = name; + + if (!value) + return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_PRIME_MERIDIAN); + PIN->from_greenwich = dmstor_ctx(ctx,value,nullptr); + } + else + PIN->from_greenwich = 0.0; + + /* Private object for the geodesic functions */ + PIN->geod = static_cast(pj_calloc (1, sizeof (struct geod_geodesic))); + if (nullptr==PIN->geod) + return pj_default_destructor (PIN, ENOMEM); + geod_init(PIN->geod, PIN->a, (1 - sqrt (1 - PIN->es))); + + /* Projection specific initialization */ + err = proj_errno_reset (PIN); + PIN = proj(PIN); + if (proj_errno (PIN)) { + pj_free(PIN); + return nullptr; + } + proj_errno_restore (PIN, err); + return PIN; +} diff --git a/src/initcache.cpp b/src/initcache.cpp new file mode 100644 index 00000000..052a016c --- /dev/null +++ b/src/initcache.cpp @@ -0,0 +1,184 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: init file definition cache. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2009, 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. + *****************************************************************************/ + +#include + +#include "projects.h" + +static int cache_count = 0; +static int cache_alloc = 0; +static char **cache_key = nullptr; +static paralist **cache_paralist = nullptr; + +/************************************************************************/ +/* pj_clone_paralist() */ +/* */ +/* Allocate a copy of a parameter list. */ +/************************************************************************/ + +paralist *pj_clone_paralist( const paralist *list) +{ + paralist *list_copy = nullptr, *next_copy = nullptr; + + for( ; list != nullptr; list = list->next ) + { + paralist *newitem = (paralist *) + pj_malloc(sizeof(paralist) + strlen(list->param)); + + newitem->used = 0; + newitem->next = nullptr; + strcpy( newitem->param, list->param ); + + if( list_copy == nullptr ) + list_copy = newitem; + else + next_copy->next = newitem; + + next_copy = newitem; + } + + return list_copy; +} + +/************************************************************************/ +/* pj_clear_initcache() */ +/* */ +/* Clear out all memory held in the init file cache. */ +/************************************************************************/ + +void pj_clear_initcache() +{ + if( cache_alloc > 0 ) + { + int i; + + pj_acquire_lock(); + + for( i = 0; i < cache_count; i++ ) + { + paralist *n, *t = cache_paralist[i]; + + pj_dalloc( cache_key[i] ); + + /* free parameter list elements */ + for (; t != nullptr; t = n) { + n = t->next; + pj_dalloc(t); + } + } + + pj_dalloc( cache_key ); + pj_dalloc( cache_paralist ); + cache_count = 0; + cache_alloc= 0; + cache_key = nullptr; + cache_paralist = nullptr; + + pj_release_lock(); + } +} + +/************************************************************************/ +/* pj_search_initcache() */ +/* */ +/* Search for a matching definition in the init cache. */ +/************************************************************************/ + +paralist *pj_search_initcache( const char *filekey ) + +{ + int i; + paralist *result = nullptr; + + pj_acquire_lock(); + + for( i = 0; result == nullptr && i < cache_count; i++) + { + if( strcmp(filekey,cache_key[i]) == 0 ) + { + result = pj_clone_paralist( cache_paralist[i] ); + } + } + + pj_release_lock(); + + return result; +} + +/************************************************************************/ +/* pj_insert_initcache() */ +/* */ +/* Insert a paralist definition in the init file cache. */ +/************************************************************************/ + +void pj_insert_initcache( const char *filekey, const paralist *list ) + +{ + pj_acquire_lock(); + + /* + ** Grow list if required. + */ + if( cache_count == cache_alloc ) + { + char **cache_key_new; + paralist **cache_paralist_new; + + cache_alloc = cache_alloc * 2 + 15; + + cache_key_new = (char **) pj_malloc(sizeof(char*) * cache_alloc); + if( cache_key && cache_count ) + { + memcpy( cache_key_new, cache_key, sizeof(char*) * cache_count); + } + pj_dalloc( cache_key ); + cache_key = cache_key_new; + + cache_paralist_new = (paralist **) + pj_malloc(sizeof(paralist*) * cache_alloc); + if( cache_paralist && cache_count ) + { + memcpy( cache_paralist_new, cache_paralist, + sizeof(paralist*) * cache_count ); + } + pj_dalloc( cache_paralist ); + cache_paralist = cache_paralist_new; + } + + /* + ** Duplicate the filekey and paralist, and insert in cache. + */ + cache_key[cache_count] = (char *) pj_malloc(strlen(filekey)+1); + strcpy( cache_key[cache_count], filekey ); + + cache_paralist[cache_count] = pj_clone_paralist( list ); + + cache_count++; + + pj_release_lock(); +} + diff --git a/src/internal.cpp b/src/internal.cpp new file mode 100644 index 00000000..3f3d191e --- /dev/null +++ b/src/internal.cpp @@ -0,0 +1,445 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: This is primarily material originating from pj_obs_api.c + * (now proj_4D_api.c), that does not fit into the API + * category. Hence this pile of tubings and fittings for + * PROJ.4 internal plumbing. + * + * Author: Thomas Knudsen, thokn@sdfe.dk, 2017-07-05 + * + ****************************************************************************** + * Copyright (c) 2016, 2017, 2018, Thomas Knudsen/SDFE + * + * 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. + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "geodesic.h" +#include "proj_internal.h" +#include "projects.h" + + +enum pj_io_units pj_left (PJ *P) { + enum pj_io_units u = P->inverted? P->right: P->left; + if (u==PJ_IO_UNITS_CLASSIC) + return PJ_IO_UNITS_PROJECTED; + return u; +} + +enum pj_io_units pj_right (PJ *P) { + enum pj_io_units u = P->inverted? P->left: P->right; + if (u==PJ_IO_UNITS_CLASSIC) + return PJ_IO_UNITS_PROJECTED; + return u; +} + + +/* Work around non-constness of MSVC HUGE_VAL by providing functions rather than constants */ +PJ_COORD proj_coord_error (void) { + PJ_COORD c; + c.v[0] = c.v[1] = c.v[2] = c.v[3] = HUGE_VAL; + return c; +} + + + +/**************************************************************************************/ +PJ_COORD pj_approx_2D_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coo) { +/*************************************************************************************** +Behave mostly as proj_trans, but attempt to use 2D interfaces only. +Used in gie.c, to enforce testing 2D code, and by PJ_pipeline.c to implement +chained calls starting out with a call to its 2D interface. +***************************************************************************************/ + if (nullptr==P) + return coo; + if (P->inverted) + direction = static_cast(-direction); + switch (direction) { + case PJ_FWD: + coo.xy = pj_fwd (coo.lp, P); + return coo; + case PJ_INV: + coo.lp = pj_inv (coo.xy, P); + return coo; + case PJ_IDENT: + return coo; + default: + break; + } + proj_errno_set (P, EINVAL); + return proj_coord_error (); +} + + +/**************************************************************************************/ +PJ_COORD pj_approx_3D_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coo) { +/*************************************************************************************** +Companion to pj_approx_2D_trans. + +Behave mostly as proj_trans, but attempt to use 3D interfaces only. +Used in gie.c, to enforce testing 3D code, and by PJ_pipeline.c to implement +chained calls starting out with a call to its 3D interface. +***************************************************************************************/ + if (nullptr==P) + return coo; + if (P->inverted) + direction = static_cast(-direction); + switch (direction) { + case PJ_FWD: + coo.xyz = pj_fwd3d (coo.lpz, P); + return coo; + case PJ_INV: + coo.lpz = pj_inv3d (coo.xyz, P); + return coo; + case PJ_IDENT: + return coo; + default: + break; + } + proj_errno_set (P, EINVAL); + return proj_coord_error (); +} + +/**************************************************************************************/ +int pj_has_inverse(PJ *P) { +/*************************************************************************************** +Check if a a PJ has an inverse. +***************************************************************************************/ + return ( (P->inverted && (P->fwd || P->fwd3d || P->fwd4d) ) || + ( P->inv || P->inv3d || P->inv4d) ); +} + + +/* Move P to a new context - or to the default context if 0 is specified */ +void proj_context_set (PJ *P, PJ_CONTEXT *ctx) { + if (nullptr==ctx) + ctx = pj_get_default_ctx (); + pj_set_ctx (P, ctx); +} + + +void proj_context_inherit (PJ *parent, PJ *child) { + if (nullptr==parent) + pj_set_ctx (child, pj_get_default_ctx()); + else + pj_set_ctx (child, pj_get_ctx(parent)); +} + + + +/*****************************************************************************/ +char *pj_chomp (char *c) { +/****************************************************************************** +Strip pre- and postfix whitespace. Inline comments (indicated by '#') are +considered whitespace. +******************************************************************************/ + size_t i, n; + char *comment; + char *start = c; + + if (nullptr==c) + return nullptr; + + comment = strchr (c, '#'); + if (comment) + *comment = 0; + + n = strlen (c); + if (0==n) + return c; + + /* Eliminate postfix whitespace */ + for (i = n - 1; (i > 0) && (isspace (c[i]) || ';'==c[i]); i--) + c[i] = 0; + + /* Find start of non-whitespace */ + while (0 != *start && (';'==*start || isspace (*start))) + start++; + + n = strlen (start); + if (0==n) { + c[0] = 0; + return c; + } + + memmove (c, start, n + 1); + return c; +} + + + +/*****************************************************************************/ +char *pj_shrink (char *c) { +/****************************************************************************** +Collapse repeated whitespace. Remove '+' and ';'. Make ',' and '=' greedy, +consuming their surrounding whitespace. +******************************************************************************/ + size_t i, j, n; + + /* Flag showing that a whitespace (ws) has been written after last non-ws */ + size_t ws; + + if (nullptr==c) + return nullptr; + + pj_chomp (c); + n = strlen (c); + + /* First collapse repeated whitespace (including +/;) */ + i = 0; + ws = 0; + for (j = 0; j < n; j++) { + + /* Eliminate prefix '+', only if preceded by whitespace */ + /* (i.e. keep it in 1.23e+08) */ + if ((i > 0) && ('+'==c[j]) && ws) + c[j] = ' '; + if ((i==0) && ('+'==c[j])) + c[j] = ' '; + + if (isspace (c[j]) || ';'==c[j]) { + if (0==ws && (i > 0)) + c[i++] = ' '; + ws = 1; + continue; + } + else { + ws = 0; + c[i++] = c[j]; + } + } + c[i] = 0; + n = strlen(c); + + /* Then make ',' and '=' greedy */ + i = 0; + for (j = 0; j < n; j++) { + if (i==0) { + c[i++] = c[j]; + continue; + } + + /* Skip space before '='/',' */ + if ('='==c[j] || ','==c[j]) { + if (c[i - 1]==' ') + c[i - 1] = c[j]; + else + c[i++] = c[j]; + continue; + } + + if (' '==c[j] && ('='==c[i - 1] || ','==c[i - 1]) ) + continue; + + c[i++] = c[j]; + } + c[i] = 0; + return c; +} + + + +/*****************************************************************************/ +size_t pj_trim_argc (char *args) { +/****************************************************************************** +Trim all unnecessary whitespace (and non-essential syntactic tokens) from the +argument string, args, and count its number of elements. +******************************************************************************/ + size_t i, m, n; + pj_shrink (args); + n = strlen (args); + if (n==0) + return 0; + for (i = m = 0; i < n; i++) { + if (' '==args[i]) { + args[i] = 0; + m++; + } + } + return m + 1; +} + + + +/*****************************************************************************/ +char **pj_trim_argv (size_t argc, char *args) { +/****************************************************************************** +Create an argv-style array from elements placed in the argument string, args. + +args is a trimmed string as returned by pj_trim_argc(), and argc is the number +of trimmed strings found (i.e. the return value of pj_trim_args()). Hence, + int argc = pj_trim_argc (args); + char **argv = pj_trim_argv (argc, args); +will produce a classic style (argc, argv) pair from a string of whitespace +separated args. No new memory is allocated for storing the individual args +(they stay in the args string), but for the pointers to the args a new array +is allocated and returned. + +It is the duty of the caller to free this array. +******************************************************************************/ + size_t i, j; + char **argv; + + if (nullptr==args) + return nullptr; + if (0==argc) + return nullptr; + + + /* turn the input string into an array of strings */ + argv = (char **) calloc (argc, sizeof (char *)); + if (nullptr==argv) + return nullptr; + argv[0] = args; + j = 1; + for (i = 0; ; i++) { + if (0==args[i]) { + argv[j++] = args + (i + 1); + } + if (j==argc) + break; + } + return argv; +} + + + +/*****************************************************************************/ +char *pj_make_args (size_t argc, char **argv) { +/****************************************************************************** +pj_make_args is the inverse of the pj_trim_argc/pj_trim_argv combo: It +converts free format command line input to something proj_create can consume. + +Allocates, and returns, an array of char, large enough to hold a whitespace +separated copy of the args in argv. It is the duty of the caller to free this +array. +******************************************************************************/ + size_t i, n; + char *p; + + for (i = n = 0; i < argc; i++) + n += strlen (argv[i]); + + p = static_cast(pj_calloc (n + argc + 1, sizeof (char))); + if (nullptr==p) + return nullptr; + if (0==argc) + return p; + + for (i = 0; i < argc; i++) { + strcat (p, argv[i]); + strcat (p, " "); + } + return pj_shrink (p); +} + + + +/*****************************************************************************/ +void proj_context_errno_set (PJ_CONTEXT *ctx, int err) { +/****************************************************************************** +Raise an error directly on a context, without going through a PJ belonging +to that context. +******************************************************************************/ + if (nullptr==ctx) + ctx = pj_get_default_ctx(); + pj_ctx_set_errno (ctx, err); +} + +/* logging */ + +/* pj_vlog resides in pj_log.c and relates to pj_log as vsprintf relates to sprintf */ +void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ); + + +/***************************************************************************************/ +PJ_LOG_LEVEL proj_log_level (PJ_CONTEXT *ctx, PJ_LOG_LEVEL log_level) { +/**************************************************************************************** + Set logging level 0-3. Higher number means more debug info. 0 turns it off +****************************************************************************************/ + PJ_LOG_LEVEL previous; + if (nullptr==ctx) + ctx = pj_get_default_ctx(); + if (nullptr==ctx) + return PJ_LOG_TELL; + previous = static_cast(abs (ctx->debug_level)); + if (PJ_LOG_TELL==log_level) + return previous; + ctx->debug_level = log_level; + return previous; +} + + +/*****************************************************************************/ +void proj_log_error (PJ *P, const char *fmt, ...) { +/****************************************************************************** + For reporting the most severe events. +******************************************************************************/ + va_list args; + va_start( args, fmt ); + pj_vlog (pj_get_ctx (P), PJ_LOG_ERROR , fmt, args); + va_end( args ); +} + + +/*****************************************************************************/ +void proj_log_debug (PJ *P, const char *fmt, ...) { +/****************************************************************************** + For reporting debugging information. +******************************************************************************/ + va_list args; + va_start( args, fmt ); + pj_vlog (pj_get_ctx (P), PJ_LOG_DEBUG_MAJOR , fmt, args); + va_end( args ); +} + + +/*****************************************************************************/ +void proj_log_trace (PJ *P, const char *fmt, ...) { +/****************************************************************************** + For reporting embarrasingly detailed debugging information. +******************************************************************************/ + va_list args; + va_start( args, fmt ); + pj_vlog (pj_get_ctx (P), PJ_LOG_DEBUG_MINOR , fmt, args); + va_end( args ); +} + + +/*****************************************************************************/ +void proj_log_func (PJ_CONTEXT *ctx, void *app_data, PJ_LOG_FUNCTION logf) { +/****************************************************************************** + Put a new logging function into P's context. The opaque object app_data is + passed as first arg at each call to the logger +******************************************************************************/ + if (nullptr==ctx) + pj_get_default_ctx (); + if (nullptr==ctx) + return; + ctx->app_data = app_data; + if (nullptr!=logf) + ctx->logger = logf; +} diff --git a/src/inv.cpp b/src/inv.cpp new file mode 100644 index 00000000..ba7e6722 --- /dev/null +++ b/src/inv.cpp @@ -0,0 +1,238 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Inverse operation invocation + * Author: Thomas Knudsen, thokn@sdfe.dk, 2018-01-02 + * Based on material from Gerald Evenden (original pj_inv) + * and Piyush Agram (original pj_inv3d) + * + ****************************************************************************** + * Copyright (c) 2000, Frank Warmerdam + * Copyright (c) 2018, Thomas Knudsen / SDFE + * + * 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. + *****************************************************************************/ +#include +#include + +#include "proj_internal.h" +#include "proj_math.h" +#include "projects.h" + +#define INPUT_UNITS P->right +#define OUTPUT_UNITS P->left + +static PJ_COORD inv_prepare (PJ *P, PJ_COORD coo) { + if (coo.v[0] == HUGE_VAL || coo.v[1] == HUGE_VAL || coo.v[2] == HUGE_VAL) { + proj_errno_set (P, PJD_ERR_INVALID_X_OR_Y); + return proj_coord_error (); + } + + /* The helmert datum shift will choke unless it gets a sensible 4D coordinate */ + if (HUGE_VAL==coo.v[2] && P->helmert) coo.v[2] = 0.0; + if (HUGE_VAL==coo.v[3] && P->helmert) coo.v[3] = 0.0; + + if (P->axisswap) + coo = proj_trans (P->axisswap, PJ_INV, coo); + + /* Handle remaining possible input types */ + switch (INPUT_UNITS) { + case PJ_IO_UNITS_WHATEVER: + return coo; + + /* de-scale and de-offset */ + case PJ_IO_UNITS_CARTESIAN: + coo.xyz.x *= P->to_meter; + coo.xyz.y *= P->to_meter; + coo.xyz.z *= P->to_meter; + if (P->is_geocent) { + coo = proj_trans (P->cart, PJ_INV, coo); + } + + return coo; + + case PJ_IO_UNITS_PROJECTED: + case PJ_IO_UNITS_CLASSIC: + coo.xyz.x = P->to_meter * coo.xyz.x - P->x0; + coo.xyz.y = P->to_meter * coo.xyz.y - P->y0; + coo.xyz.z = P->vto_meter * coo.xyz.z - P->z0; + if (INPUT_UNITS==PJ_IO_UNITS_PROJECTED) + return coo; + + /* Classic proj.4 functions expect plane coordinates in units of the semimajor axis */ + /* Multiplying by ra, rather than dividing by a because the CalCOFI projection */ + /* stomps on a and hence (apparently) depends on this to roundtrip correctly */ + /* (CalCOFI avoids further scaling by stomping - but a better solution is possible) */ + coo.xyz.x *= P->ra; + coo.xyz.y *= P->ra; + return coo; + + case PJ_IO_UNITS_ANGULAR: + coo.lpz.z = P->vto_meter * coo.lpz.z - P->z0; + break; + } + + /* Should not happen, so we could return pj_coord_err here */ + return coo; +} + + + +static PJ_COORD inv_finalize (PJ *P, PJ_COORD coo) { + if (coo.xyz.x == HUGE_VAL) { + proj_errno_set (P, PJD_ERR_INVALID_X_OR_Y); + return proj_coord_error (); + } + + if (OUTPUT_UNITS==PJ_IO_UNITS_ANGULAR) { + + /* Distance from central meridian, taking system zero meridian into account */ + coo.lp.lam = coo.lp.lam + P->from_greenwich + P->lam0; + + /* adjust longitude to central meridian */ + if (0==P->over) + coo.lpz.lam = adjlon(coo.lpz.lam); + + if (P->vgridshift) + coo = proj_trans (P->vgridshift, PJ_INV, coo); /* Go geometric from orthometric */ + if (coo.lp.lam==HUGE_VAL) + return coo; + if (P->hgridshift) + coo = proj_trans (P->hgridshift, PJ_FWD, coo); + else if (P->helmert || (P->cart_wgs84 != nullptr && P->cart != nullptr)) { + coo = proj_trans (P->cart, PJ_FWD, coo); /* Go cartesian in local frame */ + if( P->helmert ) + coo = proj_trans (P->helmert, PJ_FWD, coo); /* Step into WGS84 */ + coo = proj_trans (P->cart_wgs84, PJ_INV, coo); /* Go back to angular using WGS84 ellps */ + } + if (coo.lp.lam==HUGE_VAL) + return coo; + + /* If input latitude was geocentrical, convert back to geocentrical */ + if (P->geoc) + coo = pj_geocentric_latitude (P, PJ_FWD, coo); + } + + return coo; +} + + +static PJ_COORD error_or_coord(PJ *P, PJ_COORD coord, int last_errno) { + if (proj_errno(P)) + return proj_coord_error(); + + proj_errno_restore(P, last_errno); + return coord; +} + + +LP pj_inv(XY xy, PJ *P) { + int last_errno; + PJ_COORD coo = {{0,0,0,0}}; + coo.xy = xy; + + last_errno = proj_errno_reset(P); + + if (!P->skip_inv_prepare) + coo = inv_prepare (P, coo); + if (HUGE_VAL==coo.v[0]) + return proj_coord_error ().lp; + + /* Do the transformation, using the lowest dimensional transformer available */ + if (P->inv) + coo.lp = P->inv(coo.xy, P); + else if (P->inv3d) + coo.lpz = P->inv3d (coo.xyz, P); + else if (P->inv4d) + coo = P->inv4d (coo, P); + else { + proj_errno_set (P, EINVAL); + return proj_coord_error ().lp; + } + if (HUGE_VAL==coo.v[0]) + return proj_coord_error ().lp; + + if (!P->skip_inv_finalize) + coo = inv_finalize (P, coo); + + return error_or_coord(P, coo, last_errno).lp; +} + + + +LPZ pj_inv3d (XYZ xyz, PJ *P) { + int last_errno; + PJ_COORD coo = {{0,0,0,0}}; + coo.xyz = xyz; + + last_errno = proj_errno_reset(P); + + if (!P->skip_inv_prepare) + coo = inv_prepare (P, coo); + if (HUGE_VAL==coo.v[0]) + return proj_coord_error ().lpz; + + /* Do the transformation, using the lowest dimensional transformer feasible */ + if (P->inv3d) + coo.lpz = P->inv3d (coo.xyz, P); + else if (P->inv4d) + coo = P->inv4d (coo, P); + else if (P->inv) + coo.lp = P->inv (coo.xy, P); + else { + proj_errno_set (P, EINVAL); + return proj_coord_error ().lpz; + } + if (HUGE_VAL==coo.v[0]) + return proj_coord_error ().lpz; + + if (!P->skip_inv_finalize) + coo = inv_finalize (P, coo); + + return error_or_coord(P, coo, last_errno).lpz; +} + + + +PJ_COORD pj_inv4d (PJ_COORD coo, PJ *P) { + int last_errno = proj_errno_reset(P); + + if (!P->skip_inv_prepare) + coo = inv_prepare (P, coo); + if (HUGE_VAL==coo.v[0]) + return proj_coord_error (); + + /* Call the highest dimensional converter available */ + if (P->inv4d) + coo = P->inv4d (coo, P); + else if (P->inv3d) + coo.lpz = P->inv3d (coo.xyz, P); + else if (P->inv) + coo.lp = P->inv (coo.xy, P); + else { + proj_errno_set (P, EINVAL); + return proj_coord_error (); + } + if (HUGE_VAL==coo.v[0]) + return proj_coord_error (); + + if (!P->skip_inv_finalize) + coo = inv_finalize (P, coo); + + return error_or_coord(P, coo, last_errno); +} diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index fe3680fb..7f68a579 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -60,8 +60,8 @@ #include "proj_constants.h" -#include "pj_wkt1_parser.h" -#include "pj_wkt2_parser.h" +#include "wkt1_parser.h" +#include "wkt2_parser.h" // PROJ include order is sensitive // clang-format off diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index 237f26ec..0e72d7e4 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -56,132 +56,132 @@ endif() ############################################## SET(SRC_LIBPROJ_PROJECTIONS - projections/PJ_aeqd.cpp - projections/PJ_gnom.cpp - projections/PJ_laea.cpp - projections/PJ_mod_ster.cpp - projections/PJ_nsper.cpp - projections/PJ_nzmg.cpp - projections/PJ_ortho.cpp - projections/PJ_stere.cpp - projections/PJ_sterea.cpp - projections/PJ_aea.cpp - projections/PJ_bipc.cpp - projections/PJ_bonne.cpp - projections/PJ_eqdc.cpp - projections/PJ_isea.cpp - projections/PJ_ccon.cpp - projections/PJ_imw_p.cpp - projections/PJ_krovak.cpp - projections/PJ_lcc.cpp - projections/PJ_poly.cpp - projections/PJ_rpoly.cpp - projections/PJ_sconics.cpp - projections/proj_rouss.cpp - projections/PJ_cass.cpp - projections/PJ_cc.cpp - projections/PJ_cea.cpp - projections/PJ_eqc.cpp - projections/PJ_gall.cpp - projections/PJ_labrd.cpp - projections/PJ_lsat.cpp - projections/PJ_misrsom.cpp - projections/PJ_merc.cpp - projections/PJ_mill.cpp - projections/PJ_ocea.cpp - projections/PJ_omerc.cpp - projections/PJ_somerc.cpp - projections/PJ_tcc.cpp - projections/PJ_tcea.cpp - projections/PJ_times.cpp - projections/PJ_tmerc.cpp - projections/PJ_tobmerc.cpp - projections/PJ_airy.cpp - projections/PJ_aitoff.cpp - projections/PJ_august.cpp - projections/PJ_bacon.cpp - projections/PJ_bertin1953.cpp - projections/PJ_chamb.cpp - projections/PJ_hammer.cpp - projections/PJ_lagrng.cpp - projections/PJ_larr.cpp - projections/PJ_lask.cpp - projections/PJ_latlong.cpp - projections/PJ_nocol.cpp - projections/PJ_ob_tran.cpp - projections/PJ_oea.cpp - projections/PJ_tpeqd.cpp - projections/PJ_vandg.cpp - projections/PJ_vandg2.cpp - projections/PJ_vandg4.cpp - projections/PJ_wag7.cpp - projections/PJ_lcca.cpp - projections/PJ_geos.cpp - projections/proj_etmerc.cpp - projections/PJ_boggs.cpp - projections/PJ_collg.cpp - projections/PJ_comill.cpp - projections/PJ_crast.cpp - projections/PJ_denoy.cpp - projections/PJ_eck1.cpp - projections/PJ_eck2.cpp - projections/PJ_eck3.cpp - projections/PJ_eck4.cpp - projections/PJ_eck5.cpp - projections/PJ_fahey.cpp - projections/PJ_fouc_s.cpp - projections/PJ_gins8.cpp - projections/PJ_gstmerc.cpp - projections/PJ_gn_sinu.cpp - projections/PJ_goode.cpp - projections/PJ_igh.cpp - projections/PJ_hatano.cpp - projections/PJ_loxim.cpp - projections/PJ_mbt_fps.cpp - projections/PJ_mbtfpp.cpp - projections/PJ_mbtfpq.cpp - projections/PJ_moll.cpp - projections/PJ_nell.cpp - projections/PJ_nell_h.cpp - projections/PJ_patterson.cpp - projections/PJ_putp2.cpp - projections/PJ_putp3.cpp - projections/PJ_putp4p.cpp - projections/PJ_putp5.cpp - projections/PJ_putp6.cpp - projections/PJ_qsc.cpp - projections/PJ_robin.cpp - projections/PJ_sch.cpp - projections/PJ_sts.cpp - projections/PJ_urm5.cpp - projections/PJ_urmfps.cpp - projections/PJ_wag2.cpp - projections/PJ_wag3.cpp - projections/PJ_wink1.cpp - projections/PJ_wink2.cpp - projections/PJ_healpix.cpp - projections/PJ_natearth.cpp - projections/PJ_natearth2.cpp - projections/PJ_calcofi.cpp - projections/PJ_eqearth.cpp + projections/aeqd.cpp + projections/gnom.cpp + projections/laea.cpp + projections/mod_ster.cpp + projections/nsper.cpp + projections/nzmg.cpp + projections/ortho.cpp + projections/stere.cpp + projections/sterea.cpp + projections/aea.cpp + projections/bipc.cpp + projections/bonne.cpp + projections/eqdc.cpp + projections/isea.cpp + projections/ccon.cpp + projections/imw_p.cpp + projections/krovak.cpp + projections/lcc.cpp + projections/poly.cpp + projections/rpoly.cpp + projections/sconics.cpp + projections/rouss.cpp + projections/cass.cpp + projections/cc.cpp + projections/cea.cpp + projections/eqc.cpp + projections/gall.cpp + projections/labrd.cpp + projections/lsat.cpp + projections/misrsom.cpp + projections/merc.cpp + projections/mill.cpp + projections/ocea.cpp + projections/omerc.cpp + projections/somerc.cpp + projections/tcc.cpp + projections/tcea.cpp + projections/times.cpp + projections/tmerc.cpp + projections/tobmerc.cpp + projections/airy.cpp + projections/aitoff.cpp + projections/august.cpp + projections/bacon.cpp + projections/bertin1953.cpp + projections/chamb.cpp + projections/hammer.cpp + projections/lagrng.cpp + projections/larr.cpp + projections/lask.cpp + projections/latlong.cpp + projections/nocol.cpp + projections/ob_tran.cpp + projections/oea.cpp + projections/tpeqd.cpp + projections/vandg.cpp + projections/vandg2.cpp + projections/vandg4.cpp + projections/wag7.cpp + projections/lcca.cpp + projections/geos.cpp + projections/etmerc.cpp + projections/boggs.cpp + projections/collg.cpp + projections/comill.cpp + projections/crast.cpp + projections/denoy.cpp + projections/eck1.cpp + projections/eck2.cpp + projections/eck3.cpp + projections/eck4.cpp + projections/eck5.cpp + projections/fahey.cpp + projections/fouc_s.cpp + projections/gins8.cpp + projections/gstmerc.cpp + projections/gn_sinu.cpp + projections/goode.cpp + projections/igh.cpp + projections/hatano.cpp + projections/loxim.cpp + projections/mbt_fps.cpp + projections/mbtfpp.cpp + projections/mbtfpq.cpp + projections/moll.cpp + projections/nell.cpp + projections/nell_h.cpp + projections/patterson.cpp + projections/putp2.cpp + projections/putp3.cpp + projections/putp4p.cpp + projections/putp5.cpp + projections/putp6.cpp + projections/qsc.cpp + projections/robin.cpp + projections/sch.cpp + projections/sts.cpp + projections/urm5.cpp + projections/urmfps.cpp + projections/wag2.cpp + projections/wag3.cpp + projections/wink1.cpp + projections/wink2.cpp + projections/healpix.cpp + projections/natearth.cpp + projections/natearth2.cpp + projections/calcofi.cpp + projections/eqearth.cpp ) SET(SRC_LIBPROJ_CONVERSIONS - conversions/PJ_axisswap.cpp - conversions/PJ_cart.cpp - conversions/PJ_geoc.cpp - conversions/pj_geocent.cpp - conversions/PJ_unitconvert.cpp + conversions/axisswap.cpp + conversions/cart.cpp + conversions/geoc.cpp + conversions/geocent.cpp + conversions/unitconvert.cpp ) SET(SRC_LIBPROJ_TRANSFORMATIONS - transformations/PJ_affine.cpp - transformations/PJ_deformation.cpp - transformations/PJ_helmert.cpp - transformations/PJ_hgridshift.cpp - transformations/PJ_horner.cpp - transformations/PJ_molodensky.cpp - transformations/PJ_vgridshift.cpp + transformations/affine.cpp + transformations/deformation.cpp + transformations/helmert.cpp + transformations/hgridshift.cpp + transformations/horner.cpp + transformations/molodensky.cpp + transformations/vgridshift.cpp ) SET(SRC_LIBPROJ_ISO19111 @@ -202,28 +202,28 @@ SET(SRC_LIBPROJ_ISO19111 SET(SRC_LIBPROJ_CORE pj_list.h proj_internal.h proj_math.h projects.h aasincos.cpp adjlon.cpp bch2bps.cpp bchgen.cpp - biveval.cpp dmstor.cpp mk_cheby.cpp pj_auth.cpp - pj_deriv.cpp pj_ell_set.cpp pj_ellps.cpp pj_errno.cpp - pj_factors.cpp pj_fwd.cpp pj_init.cpp pj_inv.cpp - pj_list.cpp pj_malloc.cpp pj_mlfn.cpp pj_msfn.cpp proj_mdist.cpp - pj_open_lib.cpp pj_param.cpp pj_phi2.cpp pj_pr_list.cpp - pj_qsfn.cpp pj_strerrno.cpp - pj_tsfn.cpp pj_units.cpp pj_ctx.cpp pj_log.cpp pj_zpoly1.cpp rtodms.cpp - vector1.cpp pj_release.cpp pj_gauss.cpp - pj_fileapi.cpp - pj_gc_reader.cpp pj_gridcatalog.cpp + biveval.cpp dmstor.cpp mk_cheby.cpp auth.cpp + deriv.cpp ell_set.cpp ellps.cpp errno.cpp + factors.cpp fwd.cpp init.cpp inv.cpp + list.cpp malloc.cpp mlfn.cpp msfn.cpp proj_mdist.cpp + open_lib.cpp param.cpp phi2.cpp pr_list.cpp + qsfn.cpp strerrno.cpp + tsfn.cpp units.cpp ctx.cpp log.cpp zpoly1.cpp rtodms.cpp + vector1.cpp release.cpp gauss.cpp + fileapi.cpp + gc_reader.cpp gridcatalog.cpp nad_cvt.cpp nad_init.cpp nad_intr.cpp - pj_apply_gridshift.cpp pj_datums.cpp pj_datum_set.cpp pj_transform.cpp - geocent.cpp geocent.h pj_utils.cpp pj_gridinfo.cpp pj_gridlist.cpp - jniproj.cpp pj_mutex.cpp pj_initcache.cpp pj_apply_vgridshift.cpp geodesic.cpp - pj_strtod.cpp pj_math.cpp - proj_4D_api.cpp PJ_pipeline.cpp - pj_internal.cpp - pj_wkt_parser.hpp pj_wkt_parser.cpp - pj_wkt1_parser.h pj_wkt1_parser.cpp - pj_wkt1_generated_parser.h pj_wkt1_generated_parser.c - pj_wkt2_parser.h pj_wkt2_parser.cpp - pj_wkt2_generated_parser.h pj_wkt2_generated_parser.c + apply_gridshift.cpp datums.cpp datum_set.cpp transform.cpp + geocent.cpp geocent.h utils.cpp gridinfo.cpp gridlist.cpp + jniproj.cpp mutex.cpp initcache.cpp apply_vgridshift.cpp geodesic.cpp + strtod.cpp math.cpp + 4D_api.cpp pipeline.cpp + internal.cpp + wkt_parser.hpp wkt_parser.cpp + wkt1_parser.h wkt1_parser.cpp + wkt1_generated_parser.h wkt1_generated_parser.c + wkt2_parser.h wkt2_parser.cpp + wkt2_generated_parser.h wkt2_generated_parser.c ${CMAKE_CURRENT_BINARY_DIR}/proj_config.h ) diff --git a/src/list.cpp b/src/list.cpp new file mode 100644 index 00000000..73ca5f86 --- /dev/null +++ b/src/list.cpp @@ -0,0 +1,32 @@ +/* Projection System: default list of projections +** Use local definition of PJ_LIST_H for subset. +*/ + +#include "proj.h" + +#define USE_PJ_LIST_H 1 +#include "projects.h" + + +/* Generate prototypes for projection functions */ +#define PROJ_HEAD(id, name) extern "C" struct PJconsts *pj_##id(struct PJconsts*); +#include "pj_list.h" +#undef PROJ_HEAD + +/* Generate extern declarations for description strings */ +#define PROJ_HEAD(id, name) extern "C" const char * const pj_s_##id; +#include "pj_list.h" +#undef PROJ_HEAD + +/* Generate the null-terminated list of projection functions with associated mnemonics and descriptions */ +#define PROJ_HEAD(id, name) {#id, pj_##id, &pj_s_##id}, +const struct PJ_LIST pj_list[] = { +#include "pj_list.h" + {nullptr, nullptr, nullptr}, +}; +#undef PROJ_HEAD + + +const PJ_OPERATIONS *proj_list_operations(void) { + return pj_list; +} diff --git a/src/log.cpp b/src/log.cpp new file mode 100644 index 00000000..0f81dc13 --- /dev/null +++ b/src/log.cpp @@ -0,0 +1,98 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of pj_log() function. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2010, 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. + *****************************************************************************/ + +#include +#include +#include +#include + +#include "proj.h" +#include "projects.h" + +/************************************************************************/ +/* pj_stderr_logger() */ +/************************************************************************/ + +void pj_stderr_logger( void *app_data, int level, const char *msg ) + +{ + (void) app_data; + (void) level; + fprintf( stderr, "%s\n", msg ); +} + +/************************************************************************/ +/* pj_vlog() */ +/************************************************************************/ +void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ); +/* Workhorse for the log functions - relates to pj_log as vsprintf relates to sprintf */ +void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ) + +{ + char *msg_buf; + int debug_level = ctx->debug_level; + int shutup_unless_errno_set = debug_level < 0; + + /* For negative debug levels, we first start logging when errno is set */ + if (ctx->last_errno==0 && shutup_unless_errno_set) + return; + + if (debug_level < 0) + debug_level = -debug_level; + + if( level > debug_level ) + return; + + msg_buf = (char *) malloc(100000); + if( msg_buf == nullptr ) + return; + + /* we should use vsnprintf where available once we add configure detect.*/ + vsprintf( msg_buf, fmt, args ); + + ctx->logger( ctx->app_data, level, msg_buf ); + + free( msg_buf ); +} + + +/************************************************************************/ +/* pj_log() */ +/************************************************************************/ + +void pj_log( projCtx ctx, int level, const char *fmt, ... ) + +{ + va_list args; + + if( level > ctx->debug_level ) + return; + + va_start( args, fmt ); + pj_vlog( ctx, level, fmt, args ); + va_end( args ); +} diff --git a/src/malloc.cpp b/src/malloc.cpp new file mode 100644 index 00000000..c8681570 --- /dev/null +++ b/src/malloc.cpp @@ -0,0 +1,240 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Memory management for proj.4. + * This version includes an implementation of generic destructors, + * for memory deallocation for the large majority of PJ-objects + * that do not allocate anything else than the PJ-object itself, + * and its associated opaque object - i.e. no additional malloc'ed + * memory inside the opaque object. + * + * Author: Gerald I. Evenden (Original proj.4 author), + * Frank Warmerdam (2000) pj_malloc? + * Thomas Knudsen (2016) - freeup/dealloc parts + * + ****************************************************************************** + * Copyright (c) 2000, Frank Warmerdam + * Copyright (c) 2016, Thomas Knudsen / SDFE + * + * 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. + *****************************************************************************/ + +/* allocate and deallocate memory */ +/* These routines are used so that applications can readily replace +** projection system memory allocation/deallocation call with custom +** application procedures. */ + +#include +#include +#include +#include + +#include "proj.h" +#include "projects.h" + +/**********************************************************************/ +void *pj_malloc(size_t size) { +/*********************************************************************** +Currently, pj_malloc is a hack to solve an errno problem. +The problem is described in more details at +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=86420. +It seems, that pj_init and similar functions incorrectly +(under debian/glibs-2.3.2) assume that pj_malloc resets +errno after success. pj_malloc tries to mimic this. + +NOTE (2017-09-29): The problem described at the bugzilla page +referred to above, is most likely a case of someone not +understanding the proper usage of errno. We should review +whether "the problem is actually a problem" in PROJ.4 code. + +Library specific allocators can be useful, and improve +interoperability, if properly used. That is, by making them +run/initialization time switchable, somewhat like the file i/o +interface. + +But as things stand, we are more likely to get benefit +from reviewing the code for proper errno usage, which is hard, +due to the presence of context local and global pj_errnos. + +Probably, these were introduced in order to support incomplete +implementations of thread local errnos at an early phase of the +implementation of multithreading support in PROJ.4). + +It is likely too late to get rid of contexts, but we can still +benefit from a better usage of errno. +***********************************************************************/ + int old_errno = errno; + void *res = malloc(size); + if ( res && !old_errno ) + errno = 0; + return res; +} + + +/**********************************************************************/ +void *pj_calloc (size_t n, size_t size) { +/*********************************************************************** +pj_calloc is the pj-equivalent of calloc(). + +It allocates space for an array of elements of size . +The array is initialized to zeros. +***********************************************************************/ + void *res = pj_malloc (n*size); + if (nullptr==res) + return nullptr; + memset (res, 0, n*size); + return res; +} + + +/**********************************************************************/ +void pj_dalloc(void *ptr) { +/**********************************************************************/ + free(ptr); +} + + +/**********************************************************************/ +void *pj_dealloc (void *ptr) { +/*********************************************************************** +pj_dealloc supports the common use case of "clean up and return a null +pointer" to signal an error in a multi level allocation: + + struct foo { int bar; int *baz; }; + + struct foo *p = pj_calloc (1, sizeof (struct foo)); + if (0==p) + return 0; + + p->baz = pj_calloc (10, sizeof(int)); + if (0==p->baz) + return pj_dealloc (p); // clean up + signal error by 0-return + + return p; // success + +***********************************************************************/ + if (nullptr==ptr) + return nullptr; + pj_dalloc (ptr); + return nullptr; +} + +/**********************************************************************/ +char *pj_strdup(const char *str) +/**********************************************************************/ +{ + size_t len = strlen(str) + 1; + char *dup = static_cast(pj_malloc(len)); + if (dup) + memcpy(dup, str, len); + return dup; +} + + +/*****************************************************************************/ +void *pj_dealloc_params (PJ_CONTEXT *ctx, paralist *start, int errlev) { +/***************************************************************************** + Companion to pj_default_destructor (below). Deallocates a linked list + of "+proj=xxx" initialization parameters. + + Also called from pj_init_ctx when encountering errors before the PJ + proper is allocated. +******************************************************************************/ + paralist *t, *n; + for (t = start; t; t = n) { + n = t->next; + pj_dealloc(t); + } + pj_ctx_set_errno (ctx, errlev); + return (void *) nullptr; +} + + + + +/************************************************************************/ +/* pj_free() */ +/* */ +/* This is the application callable entry point for destroying */ +/* a projection definition. It does work generic to all */ +/* projection types, and then calls the projection specific */ +/* free function, P->destructor(), to do local work. */ +/* In most cases P->destructor()==pj_default_destructor. */ +/************************************************************************/ + +void pj_free(PJ *P) { + if (nullptr==P) + return; + /* free projection parameters - all the hard work is done by */ + /* pj_default_destructor, which is supposed */ + /* to be called as the last step of the local destructor */ + /* pointed to by P->destructor. In most cases, */ + /* pj_default_destructor actually *is* what is pointed to */ + P->destructor (P, proj_errno(P)); +} + + + + +/*****************************************************************************/ +PJ *pj_default_destructor (PJ *P, int errlev) { /* Destructor */ +/***************************************************************************** + Does memory deallocation for "plain" PJ objects, i.e. that vast majority + of PJs where the opaque object does not contain any additionally + allocated memory below the P->opaque level. +******************************************************************************/ + + /* Even if P==0, we set the errlev on pj_error and the default context */ + /* Note that both, in the multithreaded case, may then contain undefined */ + /* values. This is expected behaviour. For MT have one ctx per thread */ + if (0!=errlev) + pj_ctx_set_errno (pj_get_ctx(P), errlev); + + if (nullptr==P) + return nullptr; + + /* free grid lists */ + pj_dealloc( P->gridlist ); + pj_dealloc( P->vgridlist_geoid ); + pj_dealloc( P->catalog_name ); + + /* We used to call pj_dalloc( P->catalog ), but this will leak */ + /* memory. The safe way to clear catalog and grid is to call */ + /* pj_gc_unloadall(pj_get_default_ctx()); and pj_deallocate_grids(); */ + /* TODO: we should probably have a public pj_cleanup() method to do all */ + /* that */ + + /* free the interface to Charles Karney's geodesic library */ + pj_dealloc( P->geod ); + + /* free parameter list elements */ + pj_dealloc_params (pj_get_ctx(P), P->params, errlev); + pj_dealloc (P->def_full); + + /* free the cs2cs emulation elements */ + pj_free (P->axisswap); + pj_free (P->helmert); + pj_free (P->cart); + pj_free (P->cart_wgs84); + pj_free (P->hgridshift); + pj_free (P->vgridshift); + + pj_dealloc (static_cast(P->opaque)); + pj_dealloc(P); + return nullptr; +} diff --git a/src/math.cpp b/src/math.cpp new file mode 100644 index 00000000..540ab9eb --- /dev/null +++ b/src/math.cpp @@ -0,0 +1,108 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: Make C99 math functions available on C89 systems + * Author: Kristian Evers + * + ****************************************************************************** + * Copyright (c) 2018, 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. + *****************************************************************************/ + +#include "proj_math.h" + +/* pj_isnan is used in gie.c which means that is has to */ +/* be exported in the Windows DLL and therefore needs */ +/* to be declared even though we have isnan() on the */ +/* system. */ + +#ifdef HAVE_C99_MATH +int pj_isnan (double x); +#endif + +/* Returns 0 if not a NaN and non-zero if val is a NaN */ +int pj_isnan (double x) { + /* cppcheck-suppress duplicateExpression */ + return x != x; +} + +#if !(defined(HAVE_C99_MATH) && HAVE_C99_MATH) + +/* Compute hypotenuse */ +double pj_hypot(double x, double y) { + x = fabs(x); + y = fabs(y); + if ( x < y ) { + x /= y; + return ( y * sqrt( 1. + x * x ) ); + } else { + y /= (x != 0.0 ? x : 1.0); + return ( x * sqrt( 1. + y * y ) ); + } +} + +/* Compute log(1+x) accurately */ +double pj_log1p(double x) { + volatile double + y = 1 + x, + z = y - 1; + /* Here's the explanation for this magic: y = 1 + z, exactly, and z + * approx x, thus log(y)/z (which is nearly constant near z = 0) returns + * a good approximation to the true log(1 + x)/x. The multiplication x * + * (log(y)/z) introduces little additional error. */ + return z == 0 ? x : x * log(y) / z; +} + +/* Compute asinh(x) accurately */ +double pj_asinh(double x) { + double y = fabs(x); /* Enforce odd parity */ + y = log1p(y * (1 + y/(hypot(1.0, y) + 1))); + return x > 0 ? y : (x < 0 ? -y : x); +} + +double pj_round(double x) { + /* The handling of corner cases is copied from boost; see + * https://github.com/boostorg/math/pull/8 + * with improvements to return -0.0 when appropriate */ + double t; + if (x == 0) + return x; /* Retain sign of 0 */ + else if (0 < x && x < 0.5) + return +0.0; + else if (0 > x && x > -0.5) + return -0.0; + else if (x > 0) { + t = ceil(x); + return 0.5 < t - x ? t - 1 : t; + } else { /* Includes NaN */ + t = floor(x); + return 0.5 < x - t ? t + 1 : t; + } +} + +long pj_lround(double x) { + /* Default value for overflow + NaN + (x == LONG_MIN) */ + long r = LONG_MIN; + x = round(x); + if (fabs(x) < -(double)LONG_MIN) /* Assume (double)LONG_MIN is exact */ + r = (int)x; + return r; +} + +#endif /* !(defined(HAVE_C99_MATH) && HAVE_C99_MATH) */ diff --git a/src/mlfn.cpp b/src/mlfn.cpp new file mode 100644 index 00000000..e032e642 --- /dev/null +++ b/src/mlfn.cpp @@ -0,0 +1,64 @@ +#include + +#include "projects.h" + +/* meridional distance for ellipsoid and inverse +** 8th degree - accurate to < 1e-5 meters when used in conjunction +** with typical major axis values. +** Inverse determines phi to EPS (1e-11) radians, about 1e-6 seconds. +*/ +#define C00 1. +#define C02 .25 +#define C04 .046875 +#define C06 .01953125 +#define C08 .01068115234375 +#define C22 .75 +#define C44 .46875 +#define C46 .01302083333333333333 +#define C48 .00712076822916666666 +#define C66 .36458333333333333333 +#define C68 .00569661458333333333 +#define C88 .3076171875 +#define EPS 1e-11 +#define MAX_ITER 10 +#define EN_SIZE 5 + +double *pj_enfn(double es) { + double t, *en; + + en = (double *) pj_malloc(EN_SIZE * sizeof (double)); + if (nullptr==en) + return nullptr; + + en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08))); + en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08))); + en[2] = (t = es * es) * (C44 - es * (C46 + es * C48)); + en[3] = (t *= es) * (C66 - es * C68); + en[4] = t * es * C88; + + return en; +} + + double +pj_mlfn(double phi, double sphi, double cphi, double *en) { + cphi *= sphi; + sphi *= sphi; + return(en[0] * phi - cphi * (en[1] + sphi*(en[2] + + sphi*(en[3] + sphi*en[4])))); +} + double +pj_inv_mlfn(projCtx ctx, double arg, double es, double *en) { + double s, t, phi, k = 1./(1.-es); + int i; + + phi = arg; + for (i = MAX_ITER; i ; --i) { /* rarely goes over 2 iterations */ + s = sin(phi); + t = 1. - es * s * s; + phi -= t = (pj_mlfn(phi, s, cos(phi), en) - arg) * (t * sqrt(t)) * k; + if (fabs(t) < EPS) + return phi; + } + pj_ctx_set_errno( ctx, PJD_ERR_NON_CONV_INV_MERI_DIST ); + return phi; +} diff --git a/src/msfn.cpp b/src/msfn.cpp new file mode 100644 index 00000000..999e73a7 --- /dev/null +++ b/src/msfn.cpp @@ -0,0 +1,7 @@ +/* determine constant small m */ +#include +#include "projects.h" + double +pj_msfn(double sinphi, double cosphi, double es) { + return (cosphi / sqrt (1. - es * sinphi * sinphi)); +} diff --git a/src/mutex.cpp b/src/mutex.cpp new file mode 100644 index 00000000..3752324c --- /dev/null +++ b/src/mutex.cpp @@ -0,0 +1,270 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Mutex (thread lock) functions. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2009, 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. + *****************************************************************************/ + + +/* projects.h and windows.h conflict - avoid this! */ + +#if defined(MUTEX_pthread) && !defined(_XOPEN_SOURCE) && !defined(__sun) +/* For pthread_mutexattr_settype */ +#define _XOPEN_SOURCE 500 +#endif + +/* For PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifndef _WIN32 +#include "proj_config.h" +#include "projects.h" +#else +#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H +#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H +#endif +#include "proj_api.h" +#endif + +/* on win32 we always use win32 mutexes, even if pthreads are available */ +#if defined(_WIN32) && !defined(MUTEX_stub) +#ifndef MUTEX_win32 +# define MUTEX_win32 +#endif +# undef MUTEX_pthread +#endif + +#if !defined(MUTEX_stub) && !defined(MUTEX_pthread) && !defined(MUTEX_win32) +# define MUTEX_stub +#endif + +/************************************************************************/ +/* ==================================================================== */ +/* stub mutex implementation */ +/* ==================================================================== */ +/************************************************************************/ + +#ifdef MUTEX_stub + +/************************************************************************/ +/* pj_acquire_lock() */ +/* */ +/* Acquire the PROJ.4 lock. */ +/************************************************************************/ + +void pj_acquire_lock() +{ +} + +/************************************************************************/ +/* pj_release_lock() */ +/* */ +/* Release the PROJ.4 lock. */ +/************************************************************************/ + +void pj_release_lock() +{ +} + +/************************************************************************/ +/* pj_cleanup_lock() */ +/************************************************************************/ +void pj_cleanup_lock() +{ +} + +#endif /* def MUTEX_stub */ + +/************************************************************************/ +/* ==================================================================== */ +/* pthread mutex implementation */ +/* ==================================================================== */ +/************************************************************************/ + +#ifdef MUTEX_pthread + +#include "pthread.h" + +#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +static pthread_mutex_t core_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#else +static pthread_mutex_t core_lock; + +/************************************************************************/ +/* pj_create_lock() */ +/************************************************************************/ + +static void pj_create_lock() +{ + /* + ** We need to ensure the core mutex is created in recursive mode + */ + pthread_mutexattr_t mutex_attr; + + pthread_mutexattr_init(&mutex_attr); +#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE + pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); +#else + pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE_NP); +#endif + pthread_mutex_init(&core_lock, &mutex_attr); +} + +#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ + +/************************************************************************/ +/* pj_acquire_lock() */ +/* */ +/* Acquire the PROJ.4 lock. */ +/************************************************************************/ + +void pj_acquire_lock() +{ + +#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP + static pthread_once_t sOnceKey = PTHREAD_ONCE_INIT; + if( pthread_once(&sOnceKey, pj_create_lock) != 0 ) + { + fprintf(stderr, "pthread_once() failed in pj_acquire_lock().\n"); + } +#endif + + pthread_mutex_lock( &core_lock); +} + +/************************************************************************/ +/* pj_release_lock() */ +/* */ +/* Release the PROJ.4 lock. */ +/************************************************************************/ + +void pj_release_lock() +{ + pthread_mutex_unlock( &core_lock ); +} + +/************************************************************************/ +/* pj_cleanup_lock() */ +/************************************************************************/ +void pj_cleanup_lock() +{ +} + +#endif /* def MUTEX_pthread */ + +/************************************************************************/ +/* ==================================================================== */ +/* win32 mutex implementation */ +/* ==================================================================== */ +/************************************************************************/ + +#ifdef MUTEX_win32 + +#include + +static HANDLE mutex_lock = NULL; + +#if _WIN32_WINNT >= 0x0600 + +/************************************************************************/ +/* pj_create_lock() */ +/************************************************************************/ + +static BOOL CALLBACK pj_create_lock(PINIT_ONCE InitOnce, + PVOID Parameter, + PVOID *Context) +{ + (void)InitOnce; + (void)Parameter; + (void)Context; + mutex_lock = CreateMutex( NULL, FALSE, NULL ); + return TRUE; +} +#endif + +/************************************************************************/ +/* pj_init_lock() */ +/************************************************************************/ + +static void pj_init_lock() + +{ +#if _WIN32_WINNT >= 0x0600 + static INIT_ONCE sInitOnce = INIT_ONCE_STATIC_INIT; + InitOnceExecuteOnce( &sInitOnce, pj_create_lock, NULL, NULL ); +#else + if( mutex_lock == NULL ) + mutex_lock = CreateMutex( NULL, FALSE, NULL ); +#endif +} + +/************************************************************************/ +/* pj_acquire_lock() */ +/* */ +/* Acquire the PROJ.4 lock. */ +/************************************************************************/ + +void pj_acquire_lock() +{ + if( mutex_lock == NULL ) + pj_init_lock(); + + WaitForSingleObject( mutex_lock, INFINITE ); +} + +/************************************************************************/ +/* pj_release_lock() */ +/* */ +/* Release the PROJ.4 lock. */ +/************************************************************************/ + +void pj_release_lock() +{ + if( mutex_lock == NULL ) + pj_init_lock(); + else + ReleaseMutex( mutex_lock ); +} + +/************************************************************************/ +/* pj_cleanup_lock() */ +/************************************************************************/ +void pj_cleanup_lock() +{ + if( mutex_lock != NULL ) + { + CloseHandle( mutex_lock ); + mutex_lock = NULL; + } +} + +#endif /* def MUTEX_win32 */ diff --git a/src/open_lib.cpp b/src/open_lib.cpp new file mode 100644 index 00000000..c75b4af6 --- /dev/null +++ b/src/open_lib.cpp @@ -0,0 +1,247 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Implementation of pj_open_lib(), and pj_set_finder(). These + * provide a standard interface for opening projections support + * data files. + * Author: Gerald Evenden, Frank Warmerdam + * + ****************************************************************************** + * Copyright (c) 1995, Gerald Evenden + * Copyright (c) 2002, 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include +#include +#include +#include + +#include "proj_internal.h" +#include "projects.h" + +static const char *(*pj_finder)(const char *) = nullptr; +static int path_count = 0; +static char **search_path = nullptr; +static const char * proj_lib_name = +#ifdef PROJ_LIB +PROJ_LIB; +#else +nullptr; +#endif + +/************************************************************************/ +/* pj_set_finder() */ +/************************************************************************/ + +void pj_set_finder( const char *(*new_finder)(const char *) ) + +{ + pj_finder = new_finder; +} + +/************************************************************************/ +/* pj_set_searchpath() */ +/* */ +/* Path control for callers that can't practically provide */ +/* pj_set_finder() style callbacks. Call with (0,NULL) as args */ +/* to clear the searchpath set. */ +/************************************************************************/ + +void pj_set_searchpath ( int count, const char **path ) +{ + int i; + + if (path_count > 0 && search_path != nullptr) + { + for (i = 0; i < path_count; i++) + { + pj_dalloc(search_path[i]); + } + pj_dalloc(search_path); + path_count = 0; + search_path = nullptr; + } + + if( count > 0 ) + { + search_path = static_cast(pj_malloc(sizeof *search_path * count)); + for (i = 0; i < count; i++) + { + search_path[i] = static_cast(pj_malloc(strlen(path[i]) + 1)); + strcpy(search_path[i], path[i]); + } + } + + path_count = count; +} + +/* just a couple of helper functions that lets other functions + access the otherwise private search path */ +const char * const *proj_get_searchpath(void) { + return (const char * const *)search_path; +} + +int proj_get_path_count(void) { + return path_count; +} +/************************************************************************/ +/* pj_open_lib_ex() */ +/************************************************************************/ + +static PAFile +pj_open_lib_ex(projCtx ctx, const char *name, const char *mode, + char* out_full_filename, size_t out_full_filename_size) { + char fname[MAX_PATH_FILENAME+1]; + const char *sysname; + PAFile fid; + int n = 0; + int i; +#ifdef WIN32 + static const char dir_chars[] = "/\\"; +#else + static const char dir_chars[] = "/"; +#endif + + if( out_full_filename != nullptr && out_full_filename_size > 0 ) + out_full_filename[0] = '\0'; + + /* check if ~/name */ + if (*name == '~' && strchr(dir_chars,name[1]) ) + if ((sysname = getenv("HOME")) != nullptr) { + if( strlen(sysname) + 1 + strlen(name) + 1 > sizeof(fname) ) + { + return nullptr; + } + (void)strcpy(fname, sysname); + fname[n = (int)strlen(fname)] = DIR_CHAR; + fname[++n] = '\0'; + (void)strcpy(fname+n, name + 1); + sysname = fname; + } else + return nullptr; + + /* or fixed path: /name, ./name or ../name */ + else if (strchr(dir_chars,*name) + || (*name == '.' && strchr(dir_chars,name[1])) + || (!strncmp(name, "..", 2) && strchr(dir_chars,name[2])) + || (name[1] == ':' && strchr(dir_chars,name[2])) ) + sysname = name; + + /* or try to use application provided file finder */ + else if( pj_finder != nullptr && pj_finder( name ) != nullptr ) + sysname = pj_finder( name ); + + /* or is environment PROJ_LIB defined */ + else if ((sysname = getenv("PROJ_LIB")) || (sysname = proj_lib_name)) { + if( strlen(sysname) + 1 + strlen(name) + 1 > sizeof(fname) ) + { + return nullptr; + } + (void)strcpy(fname, sysname); + fname[n = (int)strlen(fname)] = DIR_CHAR; + fname[++n] = '\0'; + (void)strcpy(fname+n, name); + sysname = fname; + } else /* just try it bare bones */ + sysname = name; + + if ((fid = pj_ctx_fopen(ctx, sysname, mode)) != nullptr) + { + if( out_full_filename != nullptr && out_full_filename_size > 0 ) + { + strncpy(out_full_filename, sysname, out_full_filename_size); + out_full_filename[out_full_filename_size-1] = '\0'; + } + errno = 0; + } + + /* If none of those work and we have a search path, try it */ + if (!fid && path_count > 0) + { + for (i = 0; fid == nullptr && i < path_count; i++) + { + if( strlen(search_path[i]) + 1 + strlen(name) + 1 <= sizeof(fname) ) + { + sprintf(fname, "%s%c%s", search_path[i], DIR_CHAR, name); + sysname = fname; + fid = pj_ctx_fopen(ctx, sysname, mode); + } + } + if (fid) + { + if( out_full_filename != nullptr && out_full_filename_size > 0 ) + { + strncpy(out_full_filename, sysname, out_full_filename_size); + out_full_filename[out_full_filename_size-1] = '\0'; + } + errno = 0; + } + } + + if( ctx->last_errno == 0 && errno != 0 ) + pj_ctx_set_errno( ctx, errno ); + + pj_log( ctx, PJ_LOG_DEBUG_MAJOR, + "pj_open_lib(%s): call fopen(%s) - %s", + name, sysname, + fid == nullptr ? "failed" : "succeeded" ); + + return(fid); +} + +/************************************************************************/ +/* pj_open_lib() */ +/************************************************************************/ + +PAFile +pj_open_lib(projCtx ctx, const char *name, const char *mode) { + return pj_open_lib_ex(ctx, name, mode, nullptr, 0); +} + +/************************************************************************/ +/* pj_find_file() */ +/************************************************************************/ + +/** Returns the full filename corresponding to a proj resource file specified + * as a short filename. + * + * @param ctx context. + * @param short_filename short filename (e.g. egm96_15.gtx) + * @param out_full_filename output buffer, of size out_full_filename_size, that + * will receive the full filename on success. + * Will be zero-terminated. + * @param out_full_filename_size size of out_full_filename. + * @return 1 if the file was found, 0 otherwise. + */ +int pj_find_file(projCtx ctx, const char *short_filename, + char* out_full_filename, size_t out_full_filename_size) +{ + PAFile f = pj_open_lib_ex(ctx, short_filename, "rb", out_full_filename, + out_full_filename_size); + if( f != nullptr ) + { + pj_ctx_fclose(ctx, f); + return 1; + } + return 0; +} diff --git a/src/param.cpp b/src/param.cpp new file mode 100644 index 00000000..74247b72 --- /dev/null +++ b/src/param.cpp @@ -0,0 +1,189 @@ +/* put parameters in linked list and retrieve */ + +#include +#include +#include +#include +#include + +#include "projects.h" + +/* create parameter list entry */ +paralist *pj_mkparam(const char *str) { + paralist *newitem; + + if((newitem = (paralist *)pj_malloc(sizeof(paralist) + strlen(str))) != nullptr) { + newitem->used = 0; + newitem->next = nullptr; + if (*str == '+') + ++str; + (void)strcpy(newitem->param, str); + } + return newitem; +} + + +/* As pj_mkparam, but payload ends at first whitespace, rather than at end of */ +paralist *pj_mkparam_ws (const char *str) { + paralist *newitem; + size_t len = 0; + + if (nullptr==str) + return nullptr; + + /* Find start and length of string */ + while (isspace (*str)) + str++; + while ((!isspace(str[len])) && 0!=str[len]) + len++; + if (*str == '+') { + str++; + len--; + } + + /* Use calloc to automagically 0-terminate the copy */ + newitem = (paralist *) pj_calloc (1, sizeof(paralist) + len + 1); + if (nullptr==newitem) + return nullptr; + memmove(newitem->param, str, len); + + newitem->used = 0; + newitem->next = nullptr; + + return newitem; +} + +/**************************************************************************************/ +paralist *pj_param_exists (paralist *list, const char *parameter) { +/*************************************************************************************** + Determine whether a given parameter exists in a paralist. If it does, return + a pointer to the corresponding list element - otherwise return 0. + + In support of the pipeline syntax, the search is terminated once a "+step" list + element is reached, in which case a 0 is returned, unless the parameter + searched for is actually "step", in which case a pointer to the "step" list + element is returned. + + This function is equivalent to the pj_param (...) call with the "opt" argument + set to the parameter name preceeeded by a 't'. But by using this one, one avoids + writing the code allocating memory for a new copy of parameter name, and prepending + the t (for compile time known names, this is obviously not an issue). +***************************************************************************************/ + paralist *next = list; + const char *c = strchr (parameter, '='); + size_t len = strlen (parameter); + if (c) + len = c - parameter; + if (list==nullptr) + return nullptr; + + for (next = list; next; next = next->next) { + if (0==strncmp (parameter, next->param, len) && (next->param[len]=='=' || next->param[len]==0)) { + next->used = 1; + return next; + } + if (0==strcmp (parameter, "step")) + return nullptr; + } + + return nullptr; +} + + +/************************************************************************/ +/* pj_param() */ +/* */ +/* Test for presence or get parameter value. The first */ +/* character in `opt' is a parameter type which can take the */ +/* values: */ +/* */ +/* `t' - test for presence, return TRUE/FALSE in PROJVALUE.i */ +/* `i' - integer value returned in PROJVALUE.i */ +/* `d' - simple valued real input returned in PROJVALUE.f */ +/* `r' - degrees (DMS translation applied), returned as */ +/* radians in PROJVALUE.f */ +/* `s' - string returned in PROJVALUE.s */ +/* `b' - test for t/T/f/F, return in PROJVALUE.i */ +/* */ +/* Search is terminated when "step" is found, in which case */ +/* 0 is returned, unless "step" was the target searched for. */ +/* */ +/************************************************************************/ + +PROJVALUE pj_param (projCtx ctx, paralist *pl, const char *opt) { + + int type; + unsigned l; + PROJVALUE value = {0}; + + if ( ctx == nullptr ) + ctx = pj_get_default_ctx(); + + type = *opt++; + + if (nullptr==strchr ("tbirds", type)) { + fprintf(stderr, "invalid request to pj_param, fatal\n"); + exit(1); + } + + pl = pj_param_exists (pl, opt); + if (type == 't') { + value.i = pl != nullptr; + return value; + } + + /* Not found */ + if (nullptr==pl) { + /* Return value after the switch, so that the return path is */ + /* taken in all cases */ + switch (type) { + case 'b': case 'i': + value.i = 0; + break; + case 'd': case 'r': + value.f = 0.; + break; + case 's': + value.s = nullptr; + break; + } + return value; + } + + /* Found parameter - now find its value */ + pl->used |= 1; + l = (int) strlen(opt); + opt = pl->param + l; + if (*opt == '=') + ++opt; + + switch (type) { + case 'i': /* integer input */ + value.i = atoi(opt); + break; + case 'd': /* simple real input */ + value.f = pj_atof(opt); + break; + case 'r': /* degrees input */ + value.f = dmstor_ctx(ctx, opt, nullptr); + break; + case 's': /* char string */ + value.s = (char *) opt; + break; + case 'b': /* boolean */ + switch (*opt) { + case 'F': case 'f': + value.i = 0; + break; + case '\0': case 'T': case 't': + value.i = 1; + break; + default: + pj_ctx_set_errno (ctx, PJD_ERR_INVALID_BOOLEAN_PARAM); + value.i = 0; + break; + } + break; + } + return value; +} diff --git a/src/phi2.cpp b/src/phi2.cpp new file mode 100644 index 00000000..a83302e6 --- /dev/null +++ b/src/phi2.cpp @@ -0,0 +1,46 @@ +/* Determine latitude angle phi-2. */ + +#include + +#include "projects.h" + +static const double TOL = 1.0e-10; +static const int N_ITER = 15; + +/*****************************************************************************/ +double pj_phi2(projCtx ctx, double ts, double e) { +/****************************************************************************** +Determine latitude angle phi-2. +Inputs: + ts = exp(-psi) where psi is the isometric latitude (dimensionless) + e = eccentricity of the ellipsoid (dimensionless) +Output: + phi = geographic latitude (radians) +Here isometric latitude is defined by + psi = log( tan(pi/4 + phi/2) * + ( (1 - e*sin(phi)) / (1 + e*sin(phi)) )^(e/2) ) + = asinh(tan(phi)) - e * atanh(e * sin(phi)) +This routine inverts this relation using the iterative scheme given +by Snyder (1987), Eqs. (7-9) - (7-11) +*******************************************************************************/ + double eccnth = .5 * e; + double Phi = M_HALFPI - 2. * atan(ts); + double con; + int i = N_ITER; + + for(;;) { + double dphi; + con = e * sin(Phi); + dphi = M_HALFPI - 2. * atan(ts * pow((1. - con) / + (1. + con), eccnth)) - Phi; + + Phi += dphi; + + if (fabs(dphi) > TOL && --i) + continue; + break; + } + if (i <= 0) + pj_ctx_set_errno(ctx, PJD_ERR_NON_CON_INV_PHI2); + return Phi; +} diff --git a/src/pipeline.cpp b/src/pipeline.cpp new file mode 100644 index 00000000..76fc58a5 --- /dev/null +++ b/src/pipeline.cpp @@ -0,0 +1,503 @@ +/******************************************************************************* + + Transformation pipeline manager + + Thomas Knudsen, 2016-05-20/2016-11-20 + +******************************************************************************** + + Geodetic transformations are typically organized in a number of + steps. For example, a datum shift could be carried out through + these steps: + + 1. Convert (latitude, longitude, ellipsoidal height) to + 3D geocentric cartesian coordinates (X, Y, Z) + 2. Transform the (X, Y, Z) coordinates to the new datum, using a + 7 parameter Helmert transformation. + 3. Convert (X, Y, Z) back to (latitude, longitude, ellipsoidal height) + + If the height system used is orthometric, rather than ellipsoidal, + another step is needed at each end of the process: + + 1. Add the local geoid undulation (N) to the orthometric height + to obtain the ellipsoidal (i.e. geometric) height. + 2. Convert (latitude, longitude, ellipsoidal height) to + 3D geocentric cartesian coordinates (X, Y, Z) + 3. Transform the (X, Y, Z) coordinates to the new datum, using a + 7 parameter Helmert transformation. + 4. Convert (X, Y, Z) back to (latitude, longitude, ellipsoidal height) + 5. Subtract the local geoid undulation (N) from the ellipsoidal height + to obtain the orthometric height. + + Additional steps can be added for e.g. change of vertical datum, so the + list can grow fairly long. None of the steps are, however, particularly + complex, and data flow is strictly from top to bottom. + + Hence, in principle, the first example above could be implemented using + Unix pipelines: + + cat my_coordinates | geographic_to_xyz | helmert | xyz_to_geographic > my_transformed_coordinates + + in the grand tradition of Software Tools [1]. + + The proj pipeline driver implements a similar concept: Stringing together + a number of steps, feeding the output of one step to the input of the next. + + It is a very powerful concept, that increases the range of relevance of the + proj.4 system substantially. It is, however, not a particularly intrusive + addition to the PROJ.4 code base: The implementation is by and large completed + by adding an extra projection called "pipeline" (i.e. this file), which + handles all business, and a small amount of added functionality in the + pj_init code, implementing support for multilevel, embedded pipelines. + + Syntactically, the pipeline system introduces the "+step" keyword (which + indicates the start of each transformation step), and reintroduces the +inv + keyword (indicating that a given transformation step should run in reverse, i.e. + forward, when the pipeline is executed in inverse direction, and vice versa). + + Hence, the first transformation example above, can be implemented as: + + +proj=pipeline +step proj=cart +step proj=helmert +step proj=cart +inv + + Where indicate the Helmert arguments: 3 translations (+x=..., +y=..., + +z=...), 3 rotations (+rx=..., +ry=..., +rz=...) and a scale factor (+s=...). + Following geodetic conventions, the rotations are given in arcseconds, + and the scale factor is given as parts-per-million. + + [1] B. W. Kernighan & P. J. Plauger: Software tools. + Reading, Massachusetts, Addison-Wesley, 1976, 338 pp. + +******************************************************************************** + +Thomas Knudsen, thokn@sdfe.dk, 2016-05-20 + +******************************************************************************** +* Copyright (c) 2016, 2017, 2018 Thomas Knudsen / SDFE +* +* 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 + +#include "geodesic.h" +#include "proj.h" +#include "proj_internal.h" +#include "projects.h" + +PROJ_HEAD(pipeline, "Transformation pipeline manager"); + +/* Projection specific elements for the PJ object */ +namespace { // anonymous namespace +struct pj_opaque { + int steps; + char **argv; + char **current_argv; + PJ **pipeline; +}; +} // anonymous namespace + + + +static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P); +static PJ_COORD pipeline_reverse_4d (PJ_COORD point, PJ *P); +static XYZ pipeline_forward_3d (LPZ lpz, PJ *P); +static LPZ pipeline_reverse_3d (XYZ xyz, PJ *P); +static XY pipeline_forward (LP lp, PJ *P); +static LP pipeline_reverse (XY xy, PJ *P); + + + + +static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P) { + int i, first_step, last_step; + + first_step = 1; + last_step = static_cast(P->opaque)->steps + 1; + + for (i = first_step; i != last_step; i++) + point = proj_trans (static_cast(P->opaque)->pipeline[i], PJ_FWD, point); + + return point; +} + + +static PJ_COORD pipeline_reverse_4d (PJ_COORD point, PJ *P) { + int i, first_step, last_step; + + first_step = static_cast(P->opaque)->steps; + last_step = 0; + + for (i = first_step; i != last_step; i--) + point = proj_trans (static_cast(P->opaque)->pipeline[i], PJ_INV, point); + + return point; +} + + + + +static XYZ pipeline_forward_3d (LPZ lpz, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + int i; + point.lpz = lpz; + + for (i = 1; i <= static_cast(P->opaque)->steps; i++) + point = pj_approx_3D_trans (static_cast(P->opaque)->pipeline[i], PJ_FWD, point); + + return point.xyz; +} + + +static LPZ pipeline_reverse_3d (XYZ xyz, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + int i; + point.xyz = xyz; + + for (i = static_cast(P->opaque)->steps; i > 0 ; i--) + point = pj_approx_3D_trans (static_cast(P->opaque)->pipeline[i], PJ_INV, point); + + return point.lpz; +} + + + + +static XY pipeline_forward (LP lp, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + int i; + point.lp = lp; + + for (i = 1; i <= static_cast(P->opaque)->steps; i++) + point = pj_approx_2D_trans (static_cast(P->opaque)->pipeline[i], PJ_FWD, point); + + return point.xy; +} + + +static LP pipeline_reverse (XY xy, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + int i; + point.xy = xy; + for (i = static_cast(P->opaque)->steps; i > 0 ; i--) + point = pj_approx_2D_trans (static_cast(P->opaque)->pipeline[i], PJ_INV, point); + + return point.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); + + /* Deallocate each pipeine step, then pipeline array */ + if (nullptr!=static_cast(P->opaque)->pipeline) + for (i = 0; i < static_cast(P->opaque)->steps; i++) + proj_destroy (static_cast(P->opaque)->pipeline[i+1]); + pj_dealloc (static_cast(P->opaque)->pipeline); + + pj_dealloc (static_cast(P->opaque)->argv); + pj_dealloc (static_cast(P->opaque)->current_argv); + + return pj_default_destructor(P, errlev); +} + + +static PJ *pj_create_pipeline (PJ *P, size_t steps) { + + /* Room for the pipeline: An array of PJ * with room for sentinels at both ends */ + static_cast(P->opaque)->pipeline = static_cast(pj_calloc (steps + 2, sizeof(PJ *))); + if (nullptr==static_cast(P->opaque)->pipeline) + return nullptr; + + static_cast(P->opaque)->steps = (int)steps; + + return P; +} + + + + +/* count the number of args in pipeline definition, and mark all args as used */ +static size_t argc_params (paralist *params) { + size_t argc = 0; + for (; params != nullptr; params = params->next) { + argc++; + params->used = 1; + } + return ++argc; /* one extra for the sentinel */ +} + +/* Sentinel for argument list */ +static const char *argv_sentinel = "step"; + +/* turn paralist into argc/argv style argument list */ +static char **argv_params (paralist *params, size_t argc) { + char **argv; + size_t i = 0; + argv = static_cast(pj_calloc (argc, sizeof (char *))); + if (nullptr==argv) + return nullptr; + for (; params != nullptr; params = params->next) + argv[i++] = params->param; + argv[i++] = const_cast(argv_sentinel); + return argv; +} + + + + +/* Being the special operator that the pipeline is, we have to handle the */ +/* ellipsoid differently than usual. In general, the pipeline operation does */ +/* not need an ellipsoid, but in some cases it is beneficial nonetheless. */ +/* Unfortunately we can't use the normal ellipsoid setter in pj_init, since */ +/* it adds a +ellps parameter to the global args if nothing else is specified*/ +/* This is problematic since that ellipsoid spec is then passed on to the */ +/* pipeline children. This is rarely what we want, so here we implement our */ +/* own logic instead. If an ellipsoid is set in the global args, it is used */ +/* as the pipeline ellipsoid. Otherwise we use WGS84 parameters as default. */ +/* At last we calculate the rest of the ellipsoid parameters and */ +/* re-initialize P->geod. */ +static void set_ellipsoid(PJ *P) { + paralist *cur, *attachment; + int err = proj_errno_reset (P); + + /* Break the linked list after the global args */ + attachment = nullptr; + for (cur = P->params; cur != nullptr; cur = cur->next) + /* cur->next will always be non 0 given argv_sentinel presence, */ + /* but this is far from being obvious for a static analyzer */ + if (cur->next != nullptr && strcmp(argv_sentinel, cur->next->param) == 0) { + attachment = cur->next; + cur->next = nullptr; + break; + } + + /* Check if there's any ellipsoid specification in the global params. */ + /* If not, use WGS84 as default */ + if (0 != pj_ellipsoid (P)) { + P->a = 6378137.0; + P->es = .00669438002290341575; + + /* reset an "unerror": In this special use case, the errno is */ + /* not an error signal, but just a reply from pj_ellipsoid, */ + /* telling us that "No - there was no ellipsoid definition in */ + /* the PJ you provided". */ + proj_errno_reset (P); + } + P->a_orig = P->a; + P->es_orig = P->es; + + pj_calc_ellipsoid_params (P, P->a, P->es); + + geod_init(P->geod, P->a, (1 - sqrt (1 - P->es))); + + /* Re-attach the dangling list */ + /* Note: cur will always be non 0 given argv_sentinel presence, */ + /* but this is far from being obvious for a static analyzer */ + if( cur != nullptr ) + cur->next = attachment; + proj_errno_restore (P, err); +} + + + + +PJ *OPERATION(pipeline,0) { + int i, nsteps = 0, argc; + int i_pipeline = -1, i_first_step = -1, i_current_step; + char **argv, **current_argv; + + P->fwd4d = pipeline_forward_4d; + P->inv4d = pipeline_reverse_4d; + P->fwd3d = pipeline_forward_3d; + P->inv3d = pipeline_reverse_3d; + P->fwd = pipeline_forward; + P->inv = pipeline_reverse; + P->destructor = destructor; + P->is_pipeline = 1; + + /* Currently, the pipeline driver is a raw bit mover, enabling other operations */ + /* to collaborate efficiently. All prep/fin stuff is done at the step levels. */ + P->skip_fwd_prepare = 1; + P->skip_fwd_finalize = 1; + P->skip_inv_prepare = 1; + P->skip_inv_finalize = 1; + + + P->opaque = static_cast(pj_calloc (1, sizeof(struct pj_opaque))); + if (nullptr==P->opaque) + return destructor(P, ENOMEM); + + argc = (int)argc_params (P->params); + static_cast(P->opaque)->argv = argv = argv_params (P->params, argc); + if (nullptr==argv) + return destructor (P, ENOMEM); + + static_cast(P->opaque)->current_argv = current_argv = static_cast(pj_calloc (argc, sizeof (char *))); + if (nullptr==current_argv) + return destructor (P, ENOMEM); + + /* Do some syntactical sanity checking */ + for (i = 0; i < argc; i++) { + if (0==strcmp (argv_sentinel, argv[i])) { + if (-1==i_pipeline) { + proj_log_error (P, "Pipeline: +step before +proj=pipeline"); + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); + } + if (0==nsteps) + i_first_step = i; + nsteps++; + continue; + } + + if (0==strcmp ("proj=pipeline", argv[i])) { + if (-1 != i_pipeline) { + proj_log_error (P, "Pipeline: Nesting only allowed when child pipelines are wrapped in '+init's"); + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: nested pipelines */ + } + i_pipeline = i; + } + } + nsteps--; /* Last instance of +step is just a sentinel */ + static_cast(P->opaque)->steps = nsteps; + + if (-1==i_pipeline) + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: no pipeline def */ + + if (0==nsteps) + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: no pipeline def */ + + /* Make room for the pipeline and execution indicators */ + if (nullptr==pj_create_pipeline (P, nsteps)) + return destructor (P, ENOMEM); + + set_ellipsoid(P); + + /* Now loop over all steps, building a new set of arguments for each init */ + i_current_step = i_first_step; + for (i = 0; i < nsteps; i++) { + int j; + int current_argc = 0; + int err; + PJ *next_step = nullptr; + + /* Build a set of setup args for the current step */ + proj_log_trace (P, "Pipeline: Building arg list for step no. %d", i); + + /* First add the step specific args */ + for (j = i_current_step + 1; 0 != strcmp ("step", argv[j]); j++) + current_argv[current_argc++] = argv[j]; + + i_current_step = j; + + /* Then add the global args */ + for (j = i_pipeline + 1; 0 != strcmp ("step", argv[j]); j++) + current_argv[current_argc++] = argv[j]; + + proj_log_trace (P, "Pipeline: init - %s, %d", current_argv[0], current_argc); + for (j = 1; j < current_argc; j++) + proj_log_trace (P, " %s", current_argv[j]); + + err = proj_errno_reset (P); + + next_step = proj_create_argv (P->ctx, current_argc, current_argv); + proj_log_trace (P, "Pipeline: Step %d (%s) at %p", i, current_argv[0], next_step); + + if (nullptr==next_step) { + /* The step init failed, but possibly without setting errno. If so, we say "malformed" */ + int err_to_report = proj_errno(P); + if (0==err_to_report) + err_to_report = PJD_ERR_MALFORMED_PIPELINE; + proj_log_error (P, "Pipeline: Bad step definition: %s (%s)", current_argv[0], pj_strerrno (err_to_report)); + return destructor (P, err_to_report); /* ERROR: bad pipeline def */ + } + + proj_errno_restore (P, err); + + /* Is this step inverted? */ + for (j = 0; j < current_argc; j++) + if (0==strcmp("inv", current_argv[j])) { + /* if +inv exists in both global and local args the forward operation should be used */ + next_step->inverted = next_step->inverted == 0 ? 1 : 0; + } + + static_cast(P->opaque)->pipeline[i+1] = next_step; + + proj_log_trace (P, "Pipeline at [%p]: step at [%p] (%s) done", P, next_step, current_argv[0]); + } + + /* Require a forward path through the pipeline */ + for (i = 1; i <= nsteps; i++) { + PJ *Q = static_cast(P->opaque)->pipeline[i]; + if ( ( Q->inverted && (Q->inv || Q->inv3d || Q->fwd4d) ) || + (!Q->inverted && (Q->fwd || Q->fwd3d || Q->fwd4d) ) ) { + continue; + } else { + proj_log_error (P, "Pipeline: A forward operation couldn't be constructed"); + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); + } + } + + /* determine if an inverse operation is possible */ + for (i = 1; i <= nsteps; i++) { + PJ *Q = static_cast(P->opaque)->pipeline[i]; + if ( pj_has_inverse(Q) ) { + continue; + } else { + P->inv = nullptr; + P->inv3d = nullptr; + P->inv4d = nullptr; + break; + } + } + + /* Check that output units from step i are compatible with expected units in step i+1 */ + for (i = 1; i < nsteps; i++) { + enum pj_io_units unit_returned = pj_right (static_cast(P->opaque)->pipeline[i]); + enum pj_io_units unit_expected = pj_left (static_cast(P->opaque)->pipeline[i+1]); + + if ( unit_returned == PJ_IO_UNITS_WHATEVER || unit_expected == PJ_IO_UNITS_WHATEVER ) + continue; + if ( unit_returned != unit_expected ) { + proj_log_error (P, "Pipeline: Mismatched units between step %d and %d", i, i+1); + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); + } + } + + proj_log_trace (P, "Pipeline: %d steps built. Determining i/o characteristics", nsteps); + + /* Determine forward input (= reverse output) data type */ + P->left = pj_left (static_cast(P->opaque)->pipeline[1]); + + /* Now, correspondingly determine forward output (= reverse input) data type */ + P->right = pj_right (static_cast(P->opaque)->pipeline[nsteps]); + return P; +} diff --git a/src/pj_apply_gridshift.cpp b/src/pj_apply_gridshift.cpp deleted file mode 100644 index 4c8115cc..00000000 --- a/src/pj_apply_gridshift.cpp +++ /dev/null @@ -1,356 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Apply datum shifts based on grid shift files (normally NAD27 to - * NAD83 or the reverse). This module is responsible for keeping - * a list of loaded grids, and calling with each one that is - * allowed for a given datum (expressed as the nadgrids= parameter). - * 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include -#include - -#include "proj_internal.h" -#include "projects.h" - -/************************************************************************/ -/* pj_apply_gridshift() */ -/* */ -/* This is the externally callable interface - part of the */ -/* public API - though it is not used internally any more and I */ -/* doubt it is used by any other applications. But we preserve */ -/* it to honour our public api. */ -/************************************************************************/ - -int pj_apply_gridshift( projCtx ctx, const char *nadgrids, int inverse, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - PJ_GRIDINFO **gridlist; - int grid_count; - int ret; - - gridlist = pj_gridlist_from_nadgrids( ctx, nadgrids, &grid_count ); - - if( gridlist == nullptr || grid_count == 0 ) - return ctx->last_errno; - - ret = pj_apply_gridshift_3( ctx, gridlist, grid_count, inverse, - point_count, point_offset, x, y, z ); - - /* - ** Note this frees the array of grid list pointers, but not the grids - ** which is as intended. The grids themselves live on. - */ - pj_dalloc( gridlist ); - - return ret; -} - -/************************************************************************/ -/* pj_apply_gridshift_2() */ -/* */ -/* This implementation uses the gridlist from a coordinate */ -/* system definition. If the gridlist has not yet been */ -/* populated in the coordinate system definition we set it up */ -/* now. */ -/************************************************************************/ - -int pj_apply_gridshift_2( PJ *defn, int inverse, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - if( defn->catalog_name != nullptr ) - return pj_gc_apply_gridshift( defn, inverse, point_count, point_offset, - x, y, z ); - - if( defn->gridlist == nullptr ) - { - defn->gridlist = - pj_gridlist_from_nadgrids( pj_get_ctx( defn ), - pj_param(defn->ctx, defn->params,"snadgrids").s, - &(defn->gridlist_count) ); - - if( defn->gridlist == nullptr || defn->gridlist_count == 0 ) - return defn->ctx->last_errno; - } - - return pj_apply_gridshift_3( pj_get_ctx( defn ), - defn->gridlist, defn->gridlist_count, inverse, - point_count, point_offset, x, y, z ); -} - -/************************************************************************/ -/* find_ctable() */ -/* */ -/* Determine which grid is the correct given an input coordinate. */ -/************************************************************************/ - -static struct CTABLE* find_ctable(projCtx ctx, LP input, int grid_count, PJ_GRIDINFO **tables) { - int itable; - - /* keep trying till we find a table that works */ - for( itable = 0; itable < grid_count; itable++ ) - { - - PJ_GRIDINFO *gi = tables[itable]; - struct CTABLE *ct = gi->ct; - double epsilon = (fabs(ct->del.phi)+fabs(ct->del.lam))/10000.0; - /* skip tables that don't match our point at all. */ - if ( ct->ll.phi - epsilon > input.phi - || ct->ll.lam - epsilon > input.lam - || (ct->ll.phi + (ct->lim.phi-1) * ct->del.phi + epsilon < input.phi) - || (ct->ll.lam + (ct->lim.lam-1) * ct->del.lam + epsilon < input.lam) ) { - continue; - } - - /* If we have child nodes, check to see if any of them apply. */ - while( gi->child ) - { - PJ_GRIDINFO *child; - - for( child = gi->child; child != nullptr; child = child->next ) - { - struct CTABLE *ct1 = child->ct; - epsilon = (fabs(ct1->del.phi)+fabs(ct1->del.lam))/10000.0; - - if( ct1->ll.phi - epsilon > input.phi - || ct1->ll.lam - epsilon > input.lam - || (ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi + epsilon < input.phi) - || (ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam + epsilon < input.lam) ) { - continue; - } - break; - } - - /* If we didn't find a child then nothing more to do */ - if( child == nullptr ) break; - - /* Otherwise use the child, first checking it's children */ - gi = child; - ct = child->ct; - } - /* load the grid shift info if we don't have it. */ - if( ct->cvs == nullptr) { - if (!pj_gridinfo_load( ctx, gi ) ) { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return nullptr; - } - } - /* if we get this far we have found a suitable grid */ - return ct; - } - - return nullptr; -} - -/************************************************************************/ -/* pj_apply_gridshift_3() */ -/* */ -/* This is the real workhorse, given a gridlist. */ -/************************************************************************/ - -int pj_apply_gridshift_3( projCtx ctx, PJ_GRIDINFO **gridlist, int gridlist_count, - int inverse, long point_count, int point_offset, - double *x, double *y, double *z ) -{ - int i; - struct CTABLE *ct; - static int debug_count = 0; - (void) z; - - if( gridlist== nullptr || gridlist_count == 0 ) - { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); - return PJD_ERR_FAILED_TO_LOAD_GRID; - } - - ctx->last_errno = 0; - - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - LP input, output; - int itable; - - input.phi = y[io]; - input.lam = x[io]; - output.phi = HUGE_VAL; - output.lam = HUGE_VAL; - - ct = find_ctable(ctx, input, gridlist_count, gridlist); - if( ct != nullptr ) - { - output = nad_cvt( input, inverse, ct ); - - if ( output.lam != HUGE_VAL && debug_count++ < 20 ) - pj_log( ctx, PJ_LOG_DEBUG_MINOR, "pj_apply_gridshift(): used %s", ct->id ); - } - - if ( output.lam == HUGE_VAL ) - { - if( ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) - { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "pj_apply_gridshift(): failed to find a grid shift table for\n" - " location (%.7fdW,%.7fdN)", - x[io] * RAD_TO_DEG, - y[io] * RAD_TO_DEG ); - for( itable = 0; itable < gridlist_count; itable++ ) - { - PJ_GRIDINFO *gi = gridlist[itable]; - if( itable == 0 ) - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, " tried: %s", gi->gridname ); - else - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, ",%s", gi->gridname ); - } - } - - /* - * We don't actually have any machinery currently to set the - * following macro, so this is mostly kept here to make it clear - * how we ought to operate if we wanted to make it super clear - * that an error has occurred when points are outside our available - * datum shift areas. But if this is on, we will find that "low - * value" points on the fringes of some datasets will completely - * fail causing lots of problems when it is more or less ok to - * just not apply a datum shift. So rather than deal with - * that we just fallback to no shift. (see also bug #45). - */ -#ifdef ERR_GRID_AREA_TRANSIENT_SEVERE - y[io] = HUGE_VAL; - x[io] = HUGE_VAL; -#else - /* leave x/y unshifted. */ -#endif - } - else - { - y[io] = output.phi; - x[io] = output.lam; - } - } - - return 0; -} - -/**********************************************/ -int proj_hgrid_init(PJ* P, const char *grids) { -/********************************************** - - Initizalize and populate list of horizontal - grids. - - Takes a PJ-object and the plus-parameter - name that is used in the proj-string to - specify the grids to load, e.g. "+grids". - The + should be left out here. - - Returns the number of loaded grids. - -***********************************************/ - - /* prepend "s" to the "grids" string to allow usage with pj_param */ - char *sgrids = (char *) pj_malloc( (strlen(grids)+1+1) *sizeof(char) ); - sprintf(sgrids, "%s%s", "s", grids); - - if (P->gridlist == nullptr) { - P->gridlist = pj_gridlist_from_nadgrids( - P->ctx, - pj_param(P->ctx, P->params, sgrids).s, - &(P->gridlist_count) - ); - - if( P->gridlist == nullptr || P->gridlist_count == 0 ) { - pj_dealloc(sgrids); - return 0; - } - } - - if (P->gridlist_count == 0) { - proj_errno_set(P, PJD_ERR_FAILED_TO_LOAD_GRID); - } - - pj_dealloc(sgrids); - return P->gridlist_count; -} - -/********************************************/ -/* proj_hgrid_value() */ -/* */ -/* Return coordinate offset in grid */ -/********************************************/ -LP proj_hgrid_value(PJ *P, LP lp) { - struct CTABLE *ct; - LP out = proj_coord_error().lp; - - ct = find_ctable(P->ctx, lp, P->gridlist_count, P->gridlist); - if (ct == nullptr) { - pj_ctx_set_errno( P->ctx, PJD_ERR_GRID_AREA); - return out; - } - - /* normalize input to ll origin */ - lp.lam -= ct->ll.lam; - lp.phi -= ct->ll.phi; - - lp.lam = adjlon(lp.lam - M_PI) + M_PI; - - out = nad_intr(lp, ct); - - if (out.lam == HUGE_VAL || out.phi == HUGE_VAL) { - pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA); - } - - return out; -} - -LP proj_hgrid_apply(PJ *P, LP lp, PJ_DIRECTION direction) { - struct CTABLE *ct; - int inverse; - LP out; - - out.lam = HUGE_VAL; out.phi = HUGE_VAL; - - ct = find_ctable(P->ctx, lp, P->gridlist_count, P->gridlist); - - if (ct == nullptr || ct->cvs == nullptr) { - pj_ctx_set_errno( P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return out; - } - - inverse = direction == PJ_FWD ? 0 : 1; - out = nad_cvt(lp, inverse, ct); - - if (out.lam == HUGE_VAL || out.phi == HUGE_VAL) - pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA); - - return out; - -} diff --git a/src/pj_apply_vgridshift.cpp b/src/pj_apply_vgridshift.cpp deleted file mode 100644 index 1facfed6..00000000 --- a/src/pj_apply_vgridshift.cpp +++ /dev/null @@ -1,331 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Apply vertical datum shifts based on grid shift files, normally - * geoid grids mapping WGS84 to NAVD88 or something similar. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2010, 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include - -#include "proj_math.h" -#include "proj_internal.h" -#include "projects.h" - -static int is_nodata(float value) -{ - /* nodata? */ - /* GTX official nodata value if -88.88880f, but some grids also */ - /* use other big values for nodata (e.g naptrans2008.gtx has */ - /* nodata values like -2147479936), so test them too */ - return value > 1000 || value < -1000 || value == -88.88880f; -} - -static double read_vgrid_value( PJ *defn, LP input, int *gridlist_count_p, PJ_GRIDINFO **tables, struct CTABLE *ct) { - int itable = 0; - double value = HUGE_VAL; - double grid_x, grid_y; - long grid_ix, grid_iy; - long grid_ix2, grid_iy2; - float *cvs; - /* do not deal with NaN coordinates */ - /* cppcheck-suppress duplicateExpression */ - if( isnan(input.phi) || isnan(input.lam) ) - itable = *gridlist_count_p; - - /* keep trying till we find a table that works */ - for ( ; itable < *gridlist_count_p; itable++ ) - { - PJ_GRIDINFO *gi = tables[itable]; - - ct = gi->ct; - - /* skip tables that don't match our point at all. */ - if( ct->ll.phi > input.phi || ct->ll.lam > input.lam - || ct->ll.phi + (ct->lim.phi-1) * ct->del.phi < input.phi - || ct->ll.lam + (ct->lim.lam-1) * ct->del.lam < input.lam ) - continue; - - /* If we have child nodes, check to see if any of them apply. */ - while( gi->child != nullptr ) - { - PJ_GRIDINFO *child; - - for( child = gi->child; child != nullptr; child = child->next ) - { - struct CTABLE *ct1 = child->ct; - - if( ct1->ll.phi > input.phi || ct1->ll.lam > input.lam - || ct1->ll.phi+(ct1->lim.phi-1)*ct1->del.phi < input.phi - || ct1->ll.lam+(ct1->lim.lam-1)*ct1->del.lam < input.lam) - continue; - - break; - } - - /* we didn't find a more refined child node to use, so go with current grid */ - if( child == nullptr ) - { - break; - } - - /* Otherwise let's try for childrens children .. */ - gi = child; - ct = child->ct; - } - - /* load the grid shift info if we don't have it. */ - if( ct->cvs == nullptr && !pj_gridinfo_load( pj_get_ctx(defn), gi ) ) - { - pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return PJD_ERR_FAILED_TO_LOAD_GRID; - } - - - /* Interpolation a location within the grid */ - grid_x = (input.lam - ct->ll.lam) / ct->del.lam; - grid_y = (input.phi - ct->ll.phi) / ct->del.phi; - grid_ix = lround(floor(grid_x)); - grid_iy = lround(floor(grid_y)); - grid_x -= grid_ix; - grid_y -= grid_iy; - - grid_ix2 = grid_ix + 1; - if( grid_ix2 >= ct->lim.lam ) - grid_ix2 = ct->lim.lam - 1; - grid_iy2 = grid_iy + 1; - if( grid_iy2 >= ct->lim.phi ) - grid_iy2 = ct->lim.phi - 1; - - cvs = (float *) ct->cvs; - { - float value_a = cvs[grid_ix + grid_iy * ct->lim.lam]; - float value_b = cvs[grid_ix2 + grid_iy * ct->lim.lam]; - float value_c = cvs[grid_ix + grid_iy2 * ct->lim.lam]; - float value_d = cvs[grid_ix2 + grid_iy2 * ct->lim.lam]; - double total_weight = 0.0; - int n_weights = 0; - value = 0.0f; - if( !is_nodata(value_a) ) - { - double weight = (1.0-grid_x) * (1.0-grid_y); - value += value_a * weight; - total_weight += weight; - n_weights ++; - } - if( !is_nodata(value_b) ) - { - double weight = (grid_x) * (1.0-grid_y); - value += value_b * weight; - total_weight += weight; - n_weights ++; - } - if( !is_nodata(value_c) ) - { - double weight = (1.0-grid_x) * (grid_y); - value += value_c * weight; - total_weight += weight; - n_weights ++; - } - if( !is_nodata(value_d) ) - { - double weight = (grid_x) * (grid_y); - value += value_d * weight; - total_weight += weight; - n_weights ++; - } - if( n_weights == 0 ) - value = HUGE_VAL; - else if( n_weights != 4 ) - value /= total_weight; - } - - } - - return value; -} - -/************************************************************************/ -/* pj_apply_vgridshift() */ -/* */ -/* This implementation takes uses the gridlist from a coordinate */ -/* system definition. If the gridlist has not yet been */ -/* populated in the coordinate system definition we set it up */ -/* now. */ -/************************************************************************/ -int pj_apply_vgridshift( PJ *defn, const char *listname, - PJ_GRIDINFO ***gridlist_p, - int *gridlist_count_p, - int inverse, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - int i; - static int debug_count = 0; - PJ_GRIDINFO **tables; - struct CTABLE ct; - - if( *gridlist_p == nullptr ) - { - *gridlist_p = - pj_gridlist_from_nadgrids( pj_get_ctx(defn), - pj_param(defn->ctx,defn->params,listname).s, - gridlist_count_p ); - - if( *gridlist_p == nullptr || *gridlist_count_p == 0 ) - return defn->ctx->last_errno; - } - - if( *gridlist_count_p == 0 ) - { - pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); - return PJD_ERR_FAILED_TO_LOAD_GRID; - } - - tables = *gridlist_p; - defn->ctx->last_errno = 0; - - for( i = 0; i < point_count; i++ ) - { - double value; - long io = i * point_offset; - LP input; - - input.phi = y[io]; - input.lam = x[io]; - - value = read_vgrid_value(defn, input, gridlist_count_p, tables, &ct); - - if( inverse ) - z[io] -= value; - else - z[io] += value; - if( value != HUGE_VAL ) - { - if( debug_count++ < 20 ) { - proj_log_trace(defn, "pj_apply_gridshift(): used %s", ct.id); - break; - } - } - - if( value == HUGE_VAL ) - { - int itable; - char gridlist[3000]; - - proj_log_debug(defn, - "pj_apply_vgridshift(): failed to find a grid shift table for\n" - " location (%.7fdW,%.7fdN)", - x[io] * RAD_TO_DEG, - y[io] * RAD_TO_DEG ); - - gridlist[0] = '\0'; - for( itable = 0; itable < *gridlist_count_p; itable++ ) - { - PJ_GRIDINFO *gi = tables[itable]; - if( strlen(gridlist) + strlen(gi->gridname) > sizeof(gridlist)-100 ) - { - strcat( gridlist, "..." ); - break; - } - - if( itable == 0 ) - sprintf( gridlist, " tried: %s", gi->gridname ); - else - sprintf( gridlist+strlen(gridlist), ",%s", gi->gridname ); - } - - proj_log_debug(defn, "%s", gridlist); - pj_ctx_set_errno( defn->ctx, PJD_ERR_GRID_AREA ); - - return PJD_ERR_GRID_AREA; - } - } - - return 0; -} - -/**********************************************/ -int proj_vgrid_init(PJ* P, const char *grids) { -/********************************************** - - Initizalize and populate gridlist. - - Takes a PJ-object and the plus-parameter - name that is used in the proj-string to - specify the grids to load, e.g. "+grids". - The + should be left out here. - - Returns the number of loaded grids. - -***********************************************/ - - /* prepend "s" to the "grids" string to allow usage with pj_param */ - char *sgrids = (char *) pj_malloc( (strlen(grids)+1+1) *sizeof(char) ); - sprintf(sgrids, "%s%s", "s", grids); - - if (P->vgridlist_geoid == nullptr) { - P->vgridlist_geoid = pj_gridlist_from_nadgrids( - P->ctx, - pj_param(P->ctx, P->params, sgrids).s, - &(P->vgridlist_geoid_count) - ); - - if( P->vgridlist_geoid == nullptr || P->vgridlist_geoid_count == 0 ) { - pj_dealloc(sgrids); - return 0; - } - } - - if (P->vgridlist_geoid_count == 0) { - proj_errno_set(P, PJD_ERR_FAILED_TO_LOAD_GRID); - } - - pj_dealloc(sgrids); - return P->vgridlist_geoid_count; -} - -/***********************************************/ -double proj_vgrid_value(PJ *P, LP lp){ -/*********************************************** - - Read grid value at position lp in grids loaded - with proj_grid_init. - - Returns the grid value of the given coordinate. - -************************************************/ - - struct CTABLE used_grid; - double value; - memset(&used_grid, 0, sizeof(struct CTABLE)); - - value = read_vgrid_value(P, lp, &(P->vgridlist_geoid_count), P->vgridlist_geoid, &used_grid); - proj_log_trace(P, "proj_vgrid_value: (%f, %f) = %f", lp.lam*RAD_TO_DEG, lp.phi*RAD_TO_DEG, value); - - return value; -} diff --git a/src/pj_auth.cpp b/src/pj_auth.cpp deleted file mode 100644 index cde60a29..00000000 --- a/src/pj_auth.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* determine latitude from authalic latitude */ - -#include -#include - -#include "projects.h" - -# define P00 .33333333333333333333 /* 1 / 3 */ -# define P01 .17222222222222222222 /* 31 / 180 */ -# define P02 .10257936507936507937 /* 517 / 5040 */ -# define P10 .06388888888888888888 /* 23 / 360 */ -# define P11 .06640211640211640212 /* 251 / 3780 */ -# define P20 .01677689594356261023 /* 761 / 45360 */ -#define APA_SIZE 3 - - double * -pj_authset(double es) { - double t, *APA; - - if ((APA = (double *)pj_malloc(APA_SIZE * sizeof(double))) != nullptr) { - APA[0] = es * P00; - t = es * es; - APA[0] += t * P01; - APA[1] = t * P10; - t *= es; - APA[0] += t * P02; - APA[1] += t * P11; - APA[2] = t * P20; - } - return APA; -} - double -pj_authlat(double beta, double *APA) { - double t = beta+beta; - return(beta + APA[0] * sin(t) + APA[1] * sin(t+t) + APA[2] * sin(t+t+t)); -} diff --git a/src/pj_ctx.cpp b/src/pj_ctx.cpp deleted file mode 100644 index ab51d6c1..00000000 --- a/src/pj_ctx.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the projCtx thread context object. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2010, 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. - *****************************************************************************/ - -#include -#include -#include - -#include "proj_internal.h" -#include "projects.h" - -static projCtx_t default_context; -static volatile int default_context_initialized = 0; - -/************************************************************************/ -/* pj_get_ctx() */ -/************************************************************************/ - -projCtx pj_get_ctx( projPJ pj ) - -{ - if (nullptr==pj) - return pj_get_default_ctx (); - if (nullptr==pj->ctx) - return pj_get_default_ctx (); - return pj->ctx; -} - -/************************************************************************/ -/* pj_set_ctx() */ -/* */ -/* Note we do not deallocate the old context! */ -/************************************************************************/ - -void pj_set_ctx( projPJ pj, projCtx ctx ) - -{ - if (pj==nullptr) - return; - pj->ctx = ctx; -} - -/************************************************************************/ -/* pj_get_default_ctx() */ -/************************************************************************/ - -projCtx pj_get_default_ctx() - -{ - /* If already initialized, don't bother locking */ - if( default_context_initialized ) - return &default_context; - - pj_acquire_lock(); - - /* Ask again, since it may have been initialized in another thread */ - if( !default_context_initialized ) - { - default_context.last_errno = 0; - default_context.debug_level = PJ_LOG_NONE; - default_context.logger = pj_stderr_logger; - default_context.app_data = nullptr; - default_context.fileapi = pj_get_default_fileapi(); - default_context.cpp_context = nullptr; - default_context.use_proj4_init_rules = -1; - default_context.epsg_file_exists = -1; - - if( getenv("PROJ_DEBUG") != nullptr ) - { - if( atoi(getenv("PROJ_DEBUG")) >= -PJ_LOG_DEBUG_MINOR ) - default_context.debug_level = atoi(getenv("PROJ_DEBUG")); - else - default_context.debug_level = PJ_LOG_DEBUG_MINOR; - } - default_context_initialized = 1; - } - - pj_release_lock(); - - return &default_context; -} - -/************************************************************************/ -/* pj_ctx_alloc() */ -/************************************************************************/ - -projCtx pj_ctx_alloc() - -{ - projCtx ctx = (projCtx_t *) malloc(sizeof(projCtx_t)); - if (nullptr==ctx) - return nullptr; - memcpy( ctx, pj_get_default_ctx(), sizeof(projCtx_t) ); - ctx->last_errno = 0; - ctx->cpp_context = nullptr; - ctx->use_proj4_init_rules = -1; - - return ctx; -} - -/************************************************************************/ -/* pj_ctx_free() */ -/************************************************************************/ - -void pj_ctx_free( projCtx ctx ) - -{ - proj_context_delete_cpp_context( ctx->cpp_context ); - pj_dealloc( ctx ); -} - -/************************************************************************/ -/* pj_ctx_get_errno() */ -/************************************************************************/ - -int pj_ctx_get_errno( projCtx ctx ) - -{ - if (nullptr==ctx) - return pj_get_default_ctx ()->last_errno; - return ctx->last_errno; -} - -/************************************************************************/ -/* pj_ctx_set_errno() */ -/* */ -/* Also sets the global errno */ -/************************************************************************/ - -void pj_ctx_set_errno( projCtx ctx, int new_errno ) - -{ - ctx->last_errno = new_errno; - if( new_errno == 0 ) - return; - errno = new_errno; - pj_errno = new_errno; -} - -/************************************************************************/ -/* pj_ctx_set_debug() */ -/************************************************************************/ - -void pj_ctx_set_debug( projCtx ctx, int new_debug ) - -{ - if (nullptr==ctx) - return; - ctx->debug_level = new_debug; -} - -/************************************************************************/ -/* pj_ctx_set_logger() */ -/************************************************************************/ - -void pj_ctx_set_logger( projCtx ctx, void (*new_logger)(void*,int,const char*) ) - -{ - if (nullptr==ctx) - return; - ctx->logger = new_logger; -} - -/************************************************************************/ -/* pj_ctx_set_app_data() */ -/************************************************************************/ - -void pj_ctx_set_app_data( projCtx ctx, void *new_app_data ) - -{ - if (nullptr==ctx) - return; - ctx->app_data = new_app_data; -} - -/************************************************************************/ -/* pj_ctx_get_app_data() */ -/************************************************************************/ - -void *pj_ctx_get_app_data( projCtx ctx ) - -{ - if (nullptr==ctx) - return nullptr; - return ctx->app_data; -} - -/************************************************************************/ -/* pj_ctx_set_fileapi() */ -/************************************************************************/ - -void pj_ctx_set_fileapi( projCtx ctx, projFileAPI *fileapi ) - -{ - if (nullptr==ctx) - return; - ctx->fileapi = fileapi; -} - -/************************************************************************/ -/* pj_ctx_get_fileapi() */ -/************************************************************************/ - -projFileAPI *pj_ctx_get_fileapi( projCtx ctx ) - -{ - if (nullptr==ctx) - return nullptr; - return ctx->fileapi; -} diff --git a/src/pj_datum_set.cpp b/src/pj_datum_set.cpp deleted file mode 100644 index c9dfdb80..00000000 --- a/src/pj_datum_set.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Apply datum definition to PJ structure from initialization string. - * Author: Frank Warmerdam, warmerda@home.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. - *****************************************************************************/ - -#include -#include - -#include "projects.h" - -/* SEC_TO_RAD = Pi/180/3600 */ -#define SEC_TO_RAD 4.84813681109535993589914102357e-6 - -/************************************************************************/ -/* pj_datum_set() */ -/************************************************************************/ - -int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef) - -{ - const char *name, *towgs84, *nadgrids, *catalog; - - projdef->datum_type = PJD_UNKNOWN; - -/* -------------------------------------------------------------------- */ -/* Is there a datum definition in the parameters list? If so, */ -/* add the defining values to the parameter list. Note that */ -/* this will append the ellipse definition as well as the */ -/* towgs84= and related parameters. It should also be pointed */ -/* out that the addition is permanent rather than temporary */ -/* like most other keyword expansion so that the ellipse */ -/* definition will last into the pj_ell_set() function called */ -/* after this one. */ -/* -------------------------------------------------------------------- */ - if( (name = pj_param(ctx, pl,"sdatum").s) != nullptr ) - { - paralist *curr; - const char *s; - int i; - - /* find the end of the list, so we can add to it */ - for (curr = pl; curr && curr->next ; curr = curr->next) {} - - /* cannot happen in practice, but makes static analyzers happy */ - if( !curr ) return -1; - - /* find the datum definition */ - for (i = 0; (s = pj_datums[i].id) && strcmp(name, s) ; ++i) {} - - if (!s) { - pj_ctx_set_errno(ctx, PJD_ERR_UNKNOWN_ELLP_PARAM); - return 1; - } - - if( pj_datums[i].ellipse_id && strlen(pj_datums[i].ellipse_id) > 0 ) - { - char entry[100]; - - strcpy( entry, "ellps=" ); - strncpy( entry + strlen(entry), pj_datums[i].ellipse_id, - sizeof(entry) - 1 - strlen(entry) ); - entry[ sizeof(entry) - 1 ] = '\0'; - - curr = curr->next = pj_mkparam(entry); - } - - if( pj_datums[i].defn && strlen(pj_datums[i].defn) > 0 ) - curr = curr->next = pj_mkparam(pj_datums[i].defn); - - (void)curr; /* make clang static analyzer happy */ - } - -/* -------------------------------------------------------------------- */ -/* Check for nadgrids parameter. */ -/* -------------------------------------------------------------------- */ - nadgrids = pj_param(ctx, pl,"snadgrids").s; - if( nadgrids != nullptr ) - { - /* We don't actually save the value separately. It will continue - to exist int he param list for use in pj_apply_gridshift.c */ - - projdef->datum_type = PJD_GRIDSHIFT; - } - -/* -------------------------------------------------------------------- */ -/* Check for grid catalog parameter, and optional date. */ -/* -------------------------------------------------------------------- */ - else if( (catalog = pj_param(ctx, pl,"scatalog").s) != nullptr ) - { - const char *date; - - projdef->datum_type = PJD_GRIDSHIFT; - projdef->catalog_name = pj_strdup(catalog); - if (!projdef->catalog_name) { - pj_ctx_set_errno(ctx, ENOMEM); - return 1; - } - - date = pj_param(ctx, pl, "sdate").s; - if( date != nullptr) - projdef->datum_date = pj_gc_parsedate( ctx, date); - } - -/* -------------------------------------------------------------------- */ -/* Check for towgs84 parameter. */ -/* -------------------------------------------------------------------- */ - else if( (towgs84 = pj_param(ctx, pl,"stowgs84").s) != nullptr ) - { - int parm_count = 0; - const char *s; - - memset( projdef->datum_params, 0, sizeof(double) * 7); - - /* parse out the parameters */ - for( s = towgs84; *s != '\0' && parm_count < 7; ) - { - projdef->datum_params[parm_count++] = pj_atof(s); - while( *s != '\0' && *s != ',' ) - s++; - if( *s == ',' ) - s++; - } - - if( projdef->datum_params[3] != 0.0 - || projdef->datum_params[4] != 0.0 - || projdef->datum_params[5] != 0.0 - || projdef->datum_params[6] != 0.0 ) - { - projdef->datum_type = PJD_7PARAM; - - /* transform from arc seconds to radians */ - projdef->datum_params[3] *= SEC_TO_RAD; - projdef->datum_params[4] *= SEC_TO_RAD; - projdef->datum_params[5] *= SEC_TO_RAD; - /* transform from parts per million to scaling factor */ - projdef->datum_params[6] = - (projdef->datum_params[6]/1000000.0) + 1; - } - else - projdef->datum_type = PJD_3PARAM; - - /* Note that pj_init() will later switch datum_type to - PJD_WGS84 if shifts are all zero, and ellipsoid is WGS84 or GRS80 */ - } - - return 0; -} diff --git a/src/pj_datums.cpp b/src/pj_datums.cpp deleted file mode 100644 index acbe12f7..00000000 --- a/src/pj_datums.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Built in datum list. - * Author: Frank Warmerdam, warmerda@home.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. - *****************************************************************************/ - -#include - -#include "proj.h" - -#define PJ_DATUMS__ -#include "projects.h" - -/* - * The ellipse code must match one from pj_ellps.c. The datum id should - * be kept to 12 characters or less if possible. Use the official OGC - * datum name for the comments if available. - */ - -C_NAMESPACE_VAR const struct PJ_DATUMS pj_datums[] = { -/* id definition ellipse comments */ -/* -- ---------- ------- -------- */ -{"WGS84", "towgs84=0,0,0", "WGS84", ""}, -{"GGRS87", "towgs84=-199.87,74.79,246.62", "GRS80", - "Greek_Geodetic_Reference_System_1987"}, -{"NAD83", "towgs84=0,0,0", "GRS80", - "North_American_Datum_1983"}, -{"NAD27", "nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat", - "clrk66", - "North_American_Datum_1927"}, -{"potsdam", /*"towgs84=598.1,73.7,418.2,0.202,0.045,-2.455,6.7",*/ - "nadgrids=@BETA2007.gsb", - "bessel", - "Potsdam Rauenberg 1950 DHDN"}, -{"carthage","towgs84=-263.0,6.0,431.0", "clrk80ign", - "Carthage 1934 Tunisia"}, -{"hermannskogel", "towgs84=577.326,90.129,463.919,5.137,1.474,5.297,2.4232", - "bessel", - "Hermannskogel"}, -{"ire65", "towgs84=482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15", - "mod_airy", - "Ireland 1965"}, -{"nzgd49", "towgs84=59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993", - "intl", "New Zealand Geodetic Datum 1949"}, -{"OSGB36", "towgs84=446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894", - "airy", "Airy 1830"}, -{nullptr, nullptr, nullptr, nullptr} -}; - -struct PJ_DATUMS *pj_get_datums_ref() -{ - return (struct PJ_DATUMS *)pj_datums; -} - -static const struct PJ_PRIME_MERIDIANS pj_prime_meridians[] = { - /* id definition */ - /* -- ---------- */ - {"greenwich", "0dE"}, - {"lisbon", "9d07'54.862\"W"}, - {"paris", "2d20'14.025\"E"}, - {"bogota", "74d04'51.3\"W"}, - {"madrid", "3d41'16.58\"W"}, - {"rome", "12d27'8.4\"E"}, - {"bern", "7d26'22.5\"E"}, - {"jakarta", "106d48'27.79\"E"}, - {"ferro", "17d40'W"}, - {"brussels", "4d22'4.71\"E"}, - {"stockholm", "18d3'29.8\"E"}, - {"athens", "23d42'58.815\"E"}, - {"oslo", "10d43'22.5\"E"}, - {"copenhagen","12d34'40.35\"E"}, - {nullptr, nullptr} -}; - -const PJ_PRIME_MERIDIANS *proj_list_prime_meridians(void) -{ - return pj_prime_meridians; -} diff --git a/src/pj_deriv.cpp b/src/pj_deriv.cpp deleted file mode 100644 index 0e285265..00000000 --- a/src/pj_deriv.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* dervative of (*P->fwd) projection */ -#define PJ_LIB__ - -#include - -#include "projects.h" - -int pj_deriv(LP lp, double h, const PJ *P, struct DERIVS *der) { - XY t; - /* get rid of constness until we can do it for real */ - PJ *Q = (PJ *) P; - if (nullptr==Q->fwd) - return 1; - - lp.lam += h; - lp.phi += h; - if (fabs(lp.phi) > M_HALFPI) - return 1; - - h += h; - t = (*Q->fwd)(lp, Q); - if (t.x == HUGE_VAL) - return 1; - - der->x_l = t.x; - der->y_p = t.y; - der->x_p = t.x; - der->y_l = t.y; - - lp.phi -= h; - if (fabs(lp.phi) > M_HALFPI) - return 1; - - t = (*Q->fwd)(lp, Q); - if (t.x == HUGE_VAL) - return 1; - - der->x_l += t.x; - der->y_p -= t.y; - der->x_p -= t.x; - der->y_l += t.y; - - lp.lam -= h; - t = (*Q->fwd)(lp, Q); - if (t.x == HUGE_VAL) - return 1; - - der->x_l -= t.x; - der->y_p -= t.y; - der->x_p -= t.x; - der->y_l -= t.y; - - lp.phi += h; - t = (*Q->fwd)(lp, Q); - if (t.x == HUGE_VAL) - return 1; - - der->x_l -= t.x; - der->y_p += t.y; - der->x_p += t.x; - der->y_l -= t.y; - - h += h; - der->x_l /= h; - der->y_p /= h; - der->x_p /= h; - der->y_l /= h; - - return 0; -} diff --git a/src/pj_ell_set.cpp b/src/pj_ell_set.cpp deleted file mode 100644 index 486230a5..00000000 --- a/src/pj_ell_set.cpp +++ /dev/null @@ -1,727 +0,0 @@ -/* set ellipsoid parameters a and es */ - -#include -#include -#include - -#include "proj.h" -#include "proj_internal.h" -#include "projects.h" - - -/* Prototypes of the pj_ellipsoid helper functions */ -static int ellps_ellps (PJ *P); -static int ellps_size (PJ *P); -static int ellps_shape (PJ *P); -static int ellps_spherification (PJ *P); - -static paralist *pj_get_param (paralist *list, const char *key); -static char *pj_param_value (paralist *list); -static const PJ_ELLPS *pj_find_ellps (const char *name); - - -/***************************************************************************************/ -int pj_ellipsoid (PJ *P) { -/**************************************************************************************** - This is a replacement for the classic PROJ pj_ell_set function. The main difference - is that pj_ellipsoid augments the PJ object with a copy of the exact tags used to - define its related ellipsoid. - - This makes it possible to let a new PJ object inherit the geometrical properties - of an existing one. - - A complete ellipsoid definition comprises a size (primary) and a shape (secondary) - parameter. - - Size parameters supported are: - R, defining the radius of a spherical planet - a, defining the semimajor axis of an ellipsoidal planet - - Shape parameters supported are: - rf, the reverse flattening of the ellipsoid - f, the flattening of the ellipsoid - es, the eccentricity squared - e, the eccentricity - b, the semiminor axis - - The ellps=xxx parameter provides both size and shape for a number of built in - ellipsoid definitions. - - The ellipsoid definition may be augmented with a spherification flag, turning - the ellipsoid into a sphere with features defined by the ellipsoid. - - Spherification parameters supported are: - R_A, which gives a sphere with the same surface area as the ellipsoid - R_A, which gives a sphere with the same volume as the ellipsoid - - R_a, which gives a sphere with R = (a + b)/2 (arithmetic mean) - R_g, which gives a sphere with R = sqrt(a*b) (geometric mean) - R_h, which gives a sphere with R = 2*a*b/(a+b) (harmonic mean) - - R_lat_a=phi, which gives a sphere with R being the arithmetic mean of - of the corresponding ellipsoid at latitude phi. - R_lat_g=phi, which gives a sphere with R being the geometric mean of - of the corresponding ellipsoid at latitude phi. - - If R is given as size parameter, any shape and spherification parameters - given are ignored. - - If size and shape are given as ellps=xxx, later shape and size parameters - are are taken into account as modifiers for the built in ellipsoid definition. - - While this may seem strange, it is in accordance with historical PROJ - behaviour. It can e.g. be used to define coordinates on the ellipsoid - scaled to unit semimajor axis by specifying "+ellps=xxx +a=1" - -****************************************************************************************/ - int err = proj_errno_reset (P); - const char *empty = {""}; - - P->def_size = P->def_shape = P->def_spherification = P->def_ellps = nullptr; - - /* Specifying R overrules everything */ - if (pj_get_param (P->params, "R")) { - ellps_size (P); - pj_calc_ellipsoid_params (P, P->a, 0); - if (proj_errno (P)) - return 1; - return proj_errno_restore (P, err); - } - - - /* If an ellps argument is specified, start by using that */ - if (0 != ellps_ellps (P)) - return 1; - - /* We may overwrite the size */ - if (0 != ellps_size (P)) - return 2; - - /* We may also overwrite the shape */ - if (0 != ellps_shape (P)) - return 3; - - /* When we're done with it, we compute all related ellipsoid parameters */ - pj_calc_ellipsoid_params (P, P->a, P->es); - - /* And finally, we may turn it into a sphere */ - if (0 != ellps_spherification (P)) - return 4; - - proj_log_debug (P, "pj_ellipsoid - final: a=%.3f f=1/%7.3f, errno=%d", - P->a, P->f!=0? 1/P->f: 0, proj_errno (P)); - proj_log_debug (P, "pj_ellipsoid - final: %s %s %s %s", - P->def_size? P->def_size: empty, - P->def_shape? P->def_shape: empty, - P->def_spherification? P->def_spherification: empty, - P->def_ellps? P->def_ellps: empty ); - - if (proj_errno (P)) - return 5; - - /* success */ - return proj_errno_restore (P, err); -} - - -/***************************************************************************************/ -static int ellps_ellps (PJ *P) { -/***************************************************************************************/ - PJ B; - const PJ_ELLPS *ellps; - paralist *par = nullptr; - char *name; - int err; - - /* Sail home if ellps=xxx is not specified */ - par = pj_get_param (P->params, "ellps"); - if (nullptr==par) - return 0; - - /* Otherwise produce a fake PJ to make ellps_size/ellps_shape do the hard work for us */ - - /* First move B into P's context to get error messages onto the right channel */ - B.ctx = P->ctx; - - /* Then look up the right size and shape parameters from the builtin list */ - if (strlen (par->param) < 7) - return proj_errno_set (P, PJD_ERR_INVALID_ARG); - name = par->param + 6; - ellps = pj_find_ellps (name); - if (nullptr==ellps) - return proj_errno_set (P, PJD_ERR_UNKNOWN_ELLP_PARAM); - - /* Now, get things ready for ellps_size/ellps_shape, make them do their thing, and clean up */ - err = proj_errno_reset (P); - B = *P; - pj_erase_ellipsoid_def (&B); - B.params = pj_mkparam (ellps->major); - B.params->next = pj_mkparam (ellps->ell); - - ellps_size (&B); - ellps_shape (&B); - - pj_dealloc (B.params->next); - pj_dealloc (B.params); - if (proj_errno (&B)) - return proj_errno (&B); - - /* Finally update P and sail home */ - pj_inherit_ellipsoid_def (&B, P); - P->def_ellps = par->param; - par->used = 1; - - return proj_errno_restore (P, err); -} - - -/***************************************************************************************/ -static int ellps_size (PJ *P) { -/***************************************************************************************/ - paralist *par = nullptr; - int a_was_set = 0; - - /* A size parameter *must* be given, but may have been given as ellps prior */ - if (P->a != 0) - a_was_set = 1; - - /* Check which size key is specified */ - par = pj_get_param (P->params, "R"); - if (nullptr==par) - par = pj_get_param (P->params, "a"); - if (nullptr==par) - return a_was_set? 0: proj_errno_set (P, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); - - P->def_size = par->param; - par->used = 1; - P->a = pj_atof (pj_param_value (par)); - if (P->a <= 0) - return proj_errno_set (P, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); - if (HUGE_VAL==P->a) - return proj_errno_set (P, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); - - if ('R'==par->param[0]) { - P->es = P->f = P->e = P->rf = 0; - P->b = P->a; - } - return 0; -} - - -/***************************************************************************************/ -static int ellps_shape (PJ *P) { -/***************************************************************************************/ - const char *keys[] = {"rf", "f", "es", "e", "b"}; - paralist *par = nullptr; - char *def = nullptr; - size_t i, len; - - par = nullptr; - len = sizeof (keys) / sizeof (char *); - - /* Check which shape key is specified */ - for (i = 0; i < len; i++) { - par = pj_get_param (P->params, keys[i]); - if (par) - break; - } - - /* Not giving a shape parameter means selecting a sphere, unless shape */ - /* has been selected previously via ellps=xxx */ - if (nullptr==par && P->es != 0) - return 0; - if (nullptr==par && P->es==0) { - P->es = P->f = 0; - P->b = P->a; - return 0; - } - - P->def_shape = def = par->param; - par->used = 1; - P->es = P->f = P->b = P->e = P->rf = 0; - - switch (i) { - - /* reverse flattening, rf */ - case 0: - P->rf = pj_atof (pj_param_value (par)); - if (HUGE_VAL==P->rf) - return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (0==P->rf) - return proj_errno_set (P, PJD_ERR_REV_FLATTENING_IS_ZERO); - P->f = 1 / P->rf; - P->es = 2*P->f - P->f*P->f; - break; - - /* flattening, f */ - case 1: - P->f = pj_atof (pj_param_value (par)); - if (HUGE_VAL==P->f) - return proj_errno_set (P, PJD_ERR_INVALID_ARG); - - P->rf = P->f != 0.0 ? 1.0/P->f: HUGE_VAL; - P->es = 2*P->f - P->f*P->f; - break; - - /* eccentricity squared, es */ - case 2: - P->es = pj_atof (pj_param_value (par)); - if (HUGE_VAL==P->es) - return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (1==P->es) - return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); - break; - - /* eccentricity, e */ - case 3: - P->e = pj_atof (pj_param_value (par)); - if (HUGE_VAL==P->e) - return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (0==P->e) - return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (1==P->e) - return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); - P->es = P->e * P->e; - break; - - /* semiminor axis, b */ - case 4: - P->b = pj_atof (pj_param_value (par)); - if (HUGE_VAL==P->b) - return proj_errno_set (P, PJD_ERR_INVALID_ARG); - if (0==P->b) - return proj_errno_set (P, PJD_ERR_ECCENTRICITY_IS_ONE); - if (P->b==P->a) - break; - P->f = (P->a - P->b) / P->a; - P->es = 2*P->f - P->f*P->f; - break; - default: - return PJD_ERR_INVALID_ARG; - - } - - if (P->es < 0) - return proj_errno_set (P, PJD_ERR_ES_LESS_THAN_ZERO); - return 0; -} - - -/* series coefficients for calculating ellipsoid-equivalent spheres */ -static const double SIXTH = 1/6.; -static const double RA4 = 17/360.; -static const double RA6 = 67/3024.; -static const double RV4 = 5/72.; -static const double RV6 = 55/1296.; - -/***************************************************************************************/ -static int ellps_spherification (PJ *P) { -/***************************************************************************************/ - const char *keys[] = {"R_A", "R_V", "R_a", "R_g", "R_h", "R_lat_a", "R_lat_g"}; - size_t len, i; - paralist *par = nullptr; - char *def = nullptr; - - double t; - char *v, *endp; - - len = sizeof (keys) / sizeof (char *); - P->def_spherification = nullptr; - - /* Check which spherification key is specified */ - for (i = 0; i < len; i++) { - par = pj_get_param (P->params, keys[i]); - if (par) - break; - } - - /* No spherification specified? Then we're done */ - if (i==len) - return 0; - - /* Store definition */ - P->def_spherification = def = par->param; - par->used = 1; - - switch (i) { - - /* R_A - a sphere with same area as ellipsoid */ - case 0: - P->a *= 1. - P->es * (SIXTH + P->es * (RA4 + P->es * RA6)); - break; - - /* R_V - a sphere with same volume as ellipsoid */ - case 1: - P->a *= 1. - P->es * (SIXTH + P->es * (RV4 + P->es * RV6)); - break; - - /* R_a - a sphere with R = the arithmetic mean of the ellipsoid */ - case 2: - P->a = (P->a + P->b) / 2; - break; - - /* R_g - a sphere with R = the geometric mean of the ellipsoid */ - case 3: - P->a = sqrt (P->a * P->b); - break; - - /* R_h - a sphere with R = the harmonic mean of the ellipsoid */ - case 4: - if (P->a + P->b == 0) - return proj_errno_set (P, PJD_ERR_TOLERANCE_CONDITION); - P->a = (2*P->a * P->b) / (P->a + P->b); - break; - - /* R_lat_a - a sphere with R = the arithmetic mean of the ellipsoid at given latitude */ - case 5: - /* R_lat_g - a sphere with R = the geometric mean of the ellipsoid at given latitude */ - case 6: - v = pj_param_value (par); - t = proj_dmstor (v, &endp); - if (fabs (t) > M_HALFPI) - return proj_errno_set (P, PJD_ERR_REF_RAD_LARGER_THAN_90); - t = sin (t); - t = 1 - P->es * t * t; - if (i==5) /* arithmetic */ - P->a *= (1. - P->es + t) / (2 * t * sqrt(t)); - else /* geometric */ - P->a *= sqrt (1 - P->es) / t; - break; - } - - /* Clean up the ellipsoidal parameters to reflect the sphere */ - P->es = P->e = P->f = 0; - P->rf = HUGE_VAL; - P->b = P->a; - pj_calc_ellipsoid_params (P, P->a, 0); - - return 0; -} - - -/* locate parameter in list */ -static paralist *pj_get_param (paralist *list, const char *key) { - size_t l = strlen(key); - while (list && !(0==strncmp(list->param, key, l) && (0==list->param[l] || list->param[l] == '=') ) ) - list = list->next; - return list; -} - - -static char *pj_param_value (paralist *list) { - char *key, *value; - if (nullptr==list) - return nullptr; - - key = list->param; - value = strchr (key, '='); - - /* a flag (i.e. a key without value) has its own name (key) as value */ - return value? value + 1: key; -} - - -static const PJ_ELLPS *pj_find_ellps (const char *name) { - int i; - const char *s; - const PJ_ELLPS *ellps; - - if (nullptr==name) - return nullptr; - - ellps = proj_list_ellps(); - - /* Search through internal ellipsoid list for name */ - for (i = 0; (s = ellps[i].id) && strcmp(name, s) ; ++i); - if (nullptr==s) - return nullptr; - return ellps + i; -} - - -/**************************************************************************************/ -void pj_erase_ellipsoid_def (PJ *P) { -/*************************************************************************************** - Erase all ellipsoidal parameters in P -***************************************************************************************/ - PJ B; - - /* Make a blank PJ to copy from */ - memset (&B, 0, sizeof (B)); - - /* And use it to overwrite all existing ellipsoid defs */ - pj_inherit_ellipsoid_def (&B, P); -} - - -/**************************************************************************************/ -void pj_inherit_ellipsoid_def (const PJ *src, PJ *dst) { -/*************************************************************************************** - Brute force copy the ellipsoidal parameters from src to dst. This code was - written before the actual ellipsoid setup parameters were kept available in - the PJ->def_xxx elements. -***************************************************************************************/ - - /* The linear parameters */ - dst->a = src->a; - dst->b = src->b; - dst->ra = src->ra; - dst->rb = src->rb; - - /* The eccentricities */ - dst->alpha = src->alpha; - dst->e = src->e; - dst->es = src->es; - dst->e2 = src->e2; - dst->e2s = src->e2s; - dst->e3 = src->e3; - dst->e3s = src->e3s; - dst->one_es = src->one_es; - dst->rone_es = src->rone_es; - - /* The flattenings */ - dst->f = src->f; - dst->f2 = src->f2; - dst->n = src->n; - dst->rf = src->rf; - dst->rf2 = src->rf2; - dst->rn = src->rn; - - /* This one's for GRS80 */ - dst->J = src->J; - - /* es and a before any +proj related adjustment */ - dst->es_orig = src->es_orig; - dst->a_orig = src->a_orig; -} - - -/***************************************************************************************/ -int pj_calc_ellipsoid_params (PJ *P, double a, double es) { -/**************************************************************************************** - Calculate a large number of ancillary ellipsoidal parameters, in addition to - the two traditional PROJ defining parameters: Semimajor axis, a, and the - eccentricity squared, es. - - Most of these parameters are fairly cheap to compute in comparison to the overall - effort involved in initializing a PJ object. They may, however, take a substantial - part of the time taken in computing an individual point transformation. - - So by providing them up front, we can amortize the (already modest) cost over all - transformations carried out over the entire lifetime of a PJ object, rather than - incur that cost for every single transformation. - - Most of the parameter calculations here are based on the "angular eccentricity", - i.e. the angle, measured from the semiminor axis, of a line going from the north - pole to one of the foci of the ellipsoid - or in other words: The arc sine of the - eccentricity. - - The formulae used are mostly taken from: - - Richard H. Rapp: Geometric Geodesy, Part I, (178 pp, 1991). - Columbus, Ohio: Dept. of Geodetic Science - and Surveying, Ohio State University. - -****************************************************************************************/ - - P->a = a; - P->es = es; - - /* Compute some ancillary ellipsoidal parameters */ - if (P->e==0) - P->e = sqrt(P->es); /* eccentricity */ - P->alpha = asin (P->e); /* angular eccentricity */ - - /* second eccentricity */ - P->e2 = tan (P->alpha); - P->e2s = P->e2 * P->e2; - - /* third eccentricity */ - P->e3 = (0!=P->alpha)? sin (P->alpha) / sqrt(2 - sin (P->alpha)*sin (P->alpha)): 0; - P->e3s = P->e3 * P->e3; - - /* flattening */ - if (0==P->f) - P->f = 1 - cos (P->alpha); /* = 1 - sqrt (1 - PIN->es); */ - P->rf = P->f != 0.0 ? 1.0/P->f: HUGE_VAL; - - /* second flattening */ - P->f2 = (cos(P->alpha)!=0)? 1/cos (P->alpha) - 1: 0; - P->rf2 = P->f2 != 0.0 ? 1/P->f2: HUGE_VAL; - - /* third flattening */ - P->n = pow (tan (P->alpha/2), 2); - P->rn = P->n != 0.0 ? 1/P->n: HUGE_VAL; - - /* ...and a few more */ - if (0==P->b) - P->b = (1 - P->f)*P->a; - P->rb = 1. / P->b; - P->ra = 1. / P->a; - - P->one_es = 1. - P->es; - if (P->one_es == 0.) { - pj_ctx_set_errno( P->ctx, PJD_ERR_ECCENTRICITY_IS_ONE); - return PJD_ERR_ECCENTRICITY_IS_ONE; - } - - P->rone_es = 1./P->one_es; - - return 0; -} - - - -#ifndef KEEP_ORIGINAL_PJ_ELL_SET -/**************************************************************************************/ -int pj_ell_set (PJ_CONTEXT *ctx, paralist *pl, double *a, double *es) { -/*************************************************************************************** - Initialize ellipsoidal parameters by emulating the original ellipsoid setup - function by Gerald Evenden, through a call to pj_ellipsoid -***************************************************************************************/ - PJ B; - int ret; - - memset (&B, 0, sizeof (B)); - B.ctx = ctx; - B.params = pl; - - ret = pj_ellipsoid (&B); - if (ret) - return ret; - - *a = B.a; - *es = B.es; - return 0; -} -#else - - -/**************************************************************************************/ -int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { -/*************************************************************************************** - Initialize ellipsoidal parameters: This is the original ellipsoid setup - function by Gerald Evenden - significantly more compact than pj_ellipsoid and - its many helper functions, and still quite readable. - - It is, however, also so tight that it is hard to modify and add functionality, - and equally hard to find the right place to add further commentary for improved - future maintainability. - - Hence, when the need to store in the PJ object, the parameters actually used to - define the ellipsoid came up, rather than modifying this little gem of - "economy of expression", a much more verbose reimplementation, pj_ellipsoid, - was written. -***************************************************************************************/ - int i; - double b=0.0, e; - char *name; - paralist *start = 0; - - /* clear any previous error */ - pj_ctx_set_errno(ctx,0); - - /* check for varying forms of ellipsoid input */ - *a = *es = 0.; - - /* R takes precedence */ - if (pj_param(ctx, pl, "tR").i) - *a = pj_param(ctx,pl, "dR").f; - - /* probable elliptical figure */ - else { - /* check if ellps present and temporarily append its values to pl */ - if ((name = pj_param(ctx,pl, "sellps").s) != NULL) { - char *s; - - for (start = pl; start && start->next ; start = start->next) ; - for (i = 0; (s = pj_ellps[i].id) && strcmp(name, s) ; ++i) ; - if (!s) { - pj_ctx_set_errno( ctx, PJD_ERR_UNKNOWN_ELLP_PARAM); - return 1; - } - start->next = pj_mkparam(pj_ellps[i].major); - start->next->next = pj_mkparam(pj_ellps[i].ell); - } - - *a = pj_param(ctx,pl, "da").f; - - if (pj_param(ctx,pl, "tes").i) /* eccentricity squared */ - *es = pj_param(ctx,pl, "des").f; - else if (pj_param(ctx,pl, "te").i) { /* eccentricity */ - e = pj_param(ctx,pl, "de").f; - *es = e * e; - } else if (pj_param(ctx,pl, "trf").i) { /* recip flattening */ - *es = pj_param(ctx,pl, "drf").f; - if (*es == 0.0) { - pj_ctx_set_errno(ctx, PJD_ERR_REV_FLATTENING_IS_ZERO); - goto bomb; - } - *es = 1./ *es; - *es = *es * (2. - *es); - } else if (pj_param(ctx,pl, "tf").i) { /* flattening */ - *es = pj_param(ctx,pl, "df").f; - *es = *es * (2. - *es); - } else if (pj_param(ctx,pl, "tb").i) { /* minor axis */ - b = pj_param(ctx,pl, "db").f; - *es = 1. - (b * b) / (*a * *a); - } /* else *es == 0. and sphere of radius *a */ - if (b == 0.0) - b = *a * sqrt(1. - *es); - - - /* following options turn ellipsoid into equivalent sphere */ - if (pj_param(ctx,pl, "bR_A").i) { /* sphere--area of ellipsoid */ - *a *= 1. - *es * (SIXTH + *es * (RA4 + *es * RA6)); - *es = 0.; - } else if (pj_param(ctx,pl, "bR_V").i) { /* sphere--vol. of ellipsoid */ - *a *= 1. - *es * (SIXTH + *es * (RV4 + *es * RV6)); - *es = 0.; - } else if (pj_param(ctx,pl, "bR_a").i) { /* sphere--arithmetic mean */ - *a = .5 * (*a + b); - *es = 0.; - } else if (pj_param(ctx,pl, "bR_g").i) { /* sphere--geometric mean */ - *a = sqrt(*a * b); - *es = 0.; - } else if (pj_param(ctx,pl, "bR_h").i) { /* sphere--harmonic mean */ - if ( (*a + b) == 0.0) { - pj_ctx_set_errno(ctx, PJD_ERR_TOLERANCE_CONDITION); - goto bomb; - } - *a = 2. * *a * b / (*a + b); - *es = 0.; - } else if ((i = pj_param(ctx,pl, "tR_lat_a").i) || /* sphere--arith. */ - pj_param(ctx,pl, "tR_lat_g").i) { /* or geom. mean at latitude */ - double tmp; - - tmp = sin(pj_param(ctx,pl, i ? "rR_lat_a" : "rR_lat_g").f); - if (fabs(tmp) > M_HALFPI) { - pj_ctx_set_errno(ctx, PJD_ERR_REF_RAD_LARGER_THAN_90); - goto bomb; - } - tmp = 1. - *es * tmp * tmp; - *a *= i ? .5 * (1. - *es + tmp) / ( tmp * sqrt(tmp)) : - sqrt(1. - *es) / tmp; - *es = 0.; - } -bomb: - if (start) { /* clean up temporary extension of list */ - pj_dalloc(start->next->next); - pj_dalloc(start->next); - start->next = 0; - } - if (ctx->last_errno) - return 1; - } - /* some remaining checks */ - if (*es < 0.) { - pj_ctx_set_errno(ctx, PJD_ERR_ES_LESS_THAN_ZERO); - return 1; - } - if (*a <= 0.) { - pj_ctx_set_errno(ctx, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); - return 1; - } - return 0; -} -#endif diff --git a/src/pj_ellps.cpp b/src/pj_ellps.cpp deleted file mode 100644 index f548d30d..00000000 --- a/src/pj_ellps.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* definition of standard geoids */ - -#include - -#include "proj.h" -#include "projects.h" - -static const struct PJ_ELLPS -pj_ellps[] = { -{"MERIT", "a=6378137.0", "rf=298.257", "MERIT 1983"}, -{"SGS85", "a=6378136.0", "rf=298.257", "Soviet Geodetic System 85"}, -{"GRS80", "a=6378137.0", "rf=298.257222101", "GRS 1980(IUGG, 1980)"}, -{"IAU76", "a=6378140.0", "rf=298.257", "IAU 1976"}, -{"airy", "a=6377563.396", "rf=299.3249646", "Airy 1830"}, -{"APL4.9", "a=6378137.0", "rf=298.25", "Appl. Physics. 1965"}, -{"NWL9D", "a=6378145.0", "rf=298.25", "Naval Weapons Lab., 1965"}, -{"mod_airy", "a=6377340.189", "b=6356034.446", "Modified Airy"}, -{"andrae", "a=6377104.43", "rf=300.0", "Andrae 1876 (Den., Iclnd.)"}, -{"danish", "a=6377019.2563", "rf=300.0", "Andrae 1876 (Denmark, Iceland)"}, -{"aust_SA", "a=6378160.0", "rf=298.25", "Australian Natl & S. Amer. 1969"}, -{"GRS67", "a=6378160.0", "rf=298.2471674270", "GRS 67(IUGG 1967)"}, -{"GSK2011", "a=6378136.5", "rf=298.2564151", "GSK-2011"}, -{"bessel", "a=6377397.155", "rf=299.1528128", "Bessel 1841"}, -{"bess_nam", "a=6377483.865", "rf=299.1528128", "Bessel 1841 (Namibia)"}, -{"clrk66", "a=6378206.4", "b=6356583.8", "Clarke 1866"}, -{"clrk80", "a=6378249.145", "rf=293.4663", "Clarke 1880 mod."}, -{"clrk80ign", "a=6378249.2", "rf=293.4660212936269", "Clarke 1880 (IGN)."}, -{"CPM", "a=6375738.7", "rf=334.29", "Comm. des Poids et Mesures 1799"}, -{"delmbr", "a=6376428.", "rf=311.5", "Delambre 1810 (Belgium)"}, -{"engelis", "a=6378136.05", "rf=298.2566", "Engelis 1985"}, -{"evrst30", "a=6377276.345", "rf=300.8017", "Everest 1830"}, -{"evrst48", "a=6377304.063", "rf=300.8017", "Everest 1948"}, -{"evrst56", "a=6377301.243", "rf=300.8017", "Everest 1956"}, -{"evrst69", "a=6377295.664", "rf=300.8017", "Everest 1969"}, -{"evrstSS", "a=6377298.556", "rf=300.8017", "Everest (Sabah & Sarawak)"}, -{"fschr60", "a=6378166.", "rf=298.3", "Fischer (Mercury Datum) 1960"}, -{"fschr60m", "a=6378155.", "rf=298.3", "Modified Fischer 1960"}, -{"fschr68", "a=6378150.", "rf=298.3", "Fischer 1968"}, -{"helmert", "a=6378200.", "rf=298.3", "Helmert 1906"}, -{"hough", "a=6378270.0", "rf=297.", "Hough"}, -{"intl", "a=6378388.0", "rf=297.", "International 1909 (Hayford)"}, -{"krass", "a=6378245.0", "rf=298.3", "Krassovsky, 1942"}, -{"kaula", "a=6378163.", "rf=298.24", "Kaula 1961"}, -{"lerch", "a=6378139.", "rf=298.257", "Lerch 1979"}, -{"mprts", "a=6397300.", "rf=191.", "Maupertius 1738"}, -{"new_intl", "a=6378157.5", "b=6356772.2", "New International 1967"}, -{"plessis", "a=6376523.", "b=6355863.", "Plessis 1817 (France)"}, -{"PZ90", "a=6378136.0", "rf=298.25784", "PZ-90"}, -{"SEasia", "a=6378155.0", "b=6356773.3205", "Southeast Asia"}, -{"walbeck", "a=6376896.0", "b=6355834.8467", "Walbeck"}, -{"WGS60", "a=6378165.0", "rf=298.3", "WGS 60"}, -{"WGS66", "a=6378145.0", "rf=298.25", "WGS 66"}, -{"WGS72", "a=6378135.0", "rf=298.26", "WGS 72"}, -{"WGS84", "a=6378137.0", "rf=298.257223563", "WGS 84"}, -{"sphere", "a=6370997.0", "b=6370997.0", "Normal Sphere (r=6370997)"}, -{nullptr, nullptr, nullptr, nullptr} -}; - -const PJ_ELLPS *proj_list_ellps(void) -{ - return pj_ellps; -} diff --git a/src/pj_errno.cpp b/src/pj_errno.cpp deleted file mode 100644 index f6ea9bfc..00000000 --- a/src/pj_errno.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* For full ANSI compliance of global variable */ - -#include "projects.h" - -int pj_errno = 0; - -/************************************************************************/ -/* pj_get_errno_ref() */ -/************************************************************************/ - -int *pj_get_errno_ref() - -{ - return &pj_errno; -} - -/* end */ diff --git a/src/pj_factors.cpp b/src/pj_factors.cpp deleted file mode 100644 index 768bf585..00000000 --- a/src/pj_factors.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* projection scale factors */ -#define PJ_LIB__ -#include "proj.h" -#include "proj_internal.h" -#include "proj_math.h" -#include "projects.h" - -#include - -#ifndef DEFAULT_H -#define DEFAULT_H 1e-5 /* radian default for numeric h */ -#endif - -#define EPS 1.0e-12 - -int pj_factors(LP lp, const PJ *P, double h, struct FACTORS *fac) { - double cosphi, t, n, r; - int err; - PJ_COORD coo = {{0, 0, 0, 0}}; - coo.lp = lp; - - /* Failing the 3 initial checks will most likely be due to */ - /* earlier errors, so we leave errno alone */ - if (nullptr==fac) - return 1; - - if (nullptr==P) - return 1; - - if (HUGE_VAL==lp.lam) - return 1; - - /* But from here, we're ready to make our own mistakes */ - err = proj_errno_reset (P); - - /* Indicate that all factors are numerical approximations */ - fac->code = 0; - - /* Check for latitude or longitude overange */ - if ((fabs (lp.phi)-M_HALFPI) > EPS || fabs (lp.lam) > 10.) { - proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); - return 1; - } - - /* Set a reasonable step size for the numerical derivatives */ - h = fabs (h); - if (h < EPS) - h = DEFAULT_H; - - /* If input latitudes are geocentric, convert to geographic */ - if (P->geoc) - lp = pj_geocentric_latitude (P, PJ_INV, coo).lp; - - /* If latitude + one step overshoots the pole, move it slightly inside, */ - /* so the numerical derivative still exists */ - if (fabs (lp.phi) > (M_HALFPI - h)) - lp.phi = lp.phi < 0. ? -(M_HALFPI-h) : (M_HALFPI-h); - - /* Longitudinal distance from central meridian */ - lp.lam -= P->lam0; - if (!P->over) - lp.lam = adjlon(lp.lam); - - /* Derivatives */ - if (pj_deriv (lp, h, P, &(fac->der))) { - proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); - return 1; - } - - /* Scale factors */ - cosphi = cos (lp.phi); - fac->h = hypot (fac->der.x_p, fac->der.y_p); - fac->k = hypot (fac->der.x_l, fac->der.y_l) / cosphi; - - if (P->es != 0.0) { - t = sin(lp.phi); - t = 1. - P->es * t * t; - n = sqrt(t); - fac->h *= t * n / P->one_es; - fac->k *= n; - r = t * t / P->one_es; - } else - r = 1.; - - /* Convergence */ - fac->conv = -atan2 (fac->der.x_p, fac->der.y_p); - - /* Areal scale factor */ - fac->s = (fac->der.y_p * fac->der.x_l - fac->der.x_p * fac->der.y_l) * r / cosphi; - - /* Meridian-parallel angle (theta prime) */ - fac->thetap = aasin(P->ctx,fac->s / (fac->h * fac->k)); - - /* Tissot ellipse axis */ - t = fac->k * fac->k + fac->h * fac->h; - fac->a = sqrt(t + 2. * fac->s); - t = t - 2. * fac->s; - t = t > 0? sqrt(t): 0; - fac->b = 0.5 * (fac->a - t); - fac->a = 0.5 * (fac->a + t); - - /* Angular distortion */ - fac->omega = 2. * aasin(P->ctx, (fac->a - fac->b) / (fac->a + fac->b) ); - - proj_errno_restore (P, err); - return 0; -} diff --git a/src/pj_fileapi.cpp b/src/pj_fileapi.cpp deleted file mode 100644 index 3df73236..00000000 --- a/src/pj_fileapi.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the pj_ctx_* file api, and the default stdio - * based implementation. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2013, 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. - *****************************************************************************/ - -#include -#include -#include -#include -#include - -#include "projects.h" - -static PAFile stdio_fopen(projCtx ctx, const char *filename, - const char *access); -static size_t stdio_fread(void *buffer, size_t size, size_t nmemb, - PAFile file); -static int stdio_fseek(PAFile file, long offset, int whence); -static long stdio_ftell(PAFile file); -static void stdio_fclose(PAFile file); - -static projFileAPI default_fileapi = { - stdio_fopen, - stdio_fread, - stdio_fseek, - stdio_ftell, - stdio_fclose -}; - -typedef struct { - projCtx ctx; - FILE *fp; -} stdio_pafile; - -/************************************************************************/ -/* pj_get_default_fileapi() */ -/************************************************************************/ - -projFileAPI *pj_get_default_fileapi(void) -{ - return &default_fileapi; -} - -/************************************************************************/ -/* stdio_fopen() */ -/************************************************************************/ - -static PAFile stdio_fopen(projCtx ctx, const char *filename, - const char *access) -{ - stdio_pafile *pafile; - FILE *fp; - - fp = fopen(filename, access); - if (fp == nullptr) - { - return nullptr; - } - - pafile = (stdio_pafile *) malloc(sizeof(stdio_pafile)); - if (!pafile) - { - pj_ctx_set_errno(ctx, ENOMEM); - fclose(fp); - return nullptr; - } - - pafile->fp = fp; - pafile->ctx = ctx; - return (PAFile) pafile; -} - -/************************************************************************/ -/* stdio_fread() */ -/************************************************************************/ - -static size_t stdio_fread(void *buffer, size_t size, size_t nmemb, - PAFile file) -{ - stdio_pafile *pafile = (stdio_pafile *) file; - return fread(buffer, size, nmemb, pafile->fp); -} - -/************************************************************************/ -/* stdio_fseek() */ -/************************************************************************/ -static int stdio_fseek(PAFile file, long offset, int whence) -{ - stdio_pafile *pafile = (stdio_pafile *) file; - return fseek(pafile->fp, offset, whence); -} - -/************************************************************************/ -/* stdio_ftell() */ -/************************************************************************/ -static long stdio_ftell(PAFile file) -{ - stdio_pafile *pafile = (stdio_pafile *) file; - return ftell(pafile->fp); -} - -/************************************************************************/ -/* stdio_fclose() */ -/************************************************************************/ -static void stdio_fclose(PAFile file) -{ - stdio_pafile *pafile = (stdio_pafile *) file; - fclose(pafile->fp); - free(pafile); -} - -/************************************************************************/ -/* pj_ctx_fopen() */ -/* */ -/* Open a file using the provided file io hooks. */ -/************************************************************************/ - -PAFile pj_ctx_fopen(projCtx ctx, const char *filename, const char *access) -{ - return ctx->fileapi->FOpen(ctx, filename, access); -} - -/************************************************************************/ -/* pj_ctx_fread() */ -/************************************************************************/ -size_t pj_ctx_fread(projCtx ctx, void *buffer, size_t size, size_t nmemb, PAFile file) -{ - return ctx->fileapi->FRead(buffer, size, nmemb, file); -} - -/************************************************************************/ -/* pj_ctx_fseek() */ -/************************************************************************/ -int pj_ctx_fseek(projCtx ctx, PAFile file, long offset, int whence) -{ - return ctx->fileapi->FSeek(file, offset, whence); -} - -/************************************************************************/ -/* pj_ctx_ftell() */ -/************************************************************************/ -long pj_ctx_ftell(projCtx ctx, PAFile file) -{ - return ctx->fileapi->FTell(file); -} - -/************************************************************************/ -/* pj_ctx_fclose() */ -/************************************************************************/ -void pj_ctx_fclose(projCtx ctx, PAFile file) -{ - ctx->fileapi->FClose(file); -} - -/************************************************************************/ -/* pj_ctx_fgets() */ -/* */ -/* A not very optimal implementation of fgets on top of */ -/* fread(). If we end up using this a lot more care should be */ -/* taken. */ -/************************************************************************/ - -char *pj_ctx_fgets(projCtx ctx, char *line, int size, PAFile file) -{ - long start = pj_ctx_ftell(ctx, file); - size_t bytes_read; - int i; - int max_size; - - line[size-1] = '\0'; - bytes_read = pj_ctx_fread(ctx, line, 1, size-1, file); - if(bytes_read == 0) - return nullptr; - if(bytes_read < (size_t)size) - { - line[bytes_read] = '\0'; - } - - max_size = (int)MIN(bytes_read, (size_t)(size > 2 ? size - 2 : 0)); - for( i = 0; i < max_size; i++) - { - if (line[i] == '\n') - { - line[i+1] = '\0'; - pj_ctx_fseek(ctx, file, start + i + 1, SEEK_SET); - break; - } - } - return line; -} diff --git a/src/pj_fwd.cpp b/src/pj_fwd.cpp deleted file mode 100644 index e8f73999..00000000 --- a/src/pj_fwd.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Forward operation invocation - * Author: Thomas Knudsen, thokn@sdfe.dk, 2018-01-02 - * Based on material from Gerald Evenden (original pj_fwd) - * and Piyush Agram (original pj_fwd3d) - * - ****************************************************************************** - * Copyright (c) 2000, Frank Warmerdam - * Copyright (c) 2018, Thomas Knudsen / SDFE - * - * 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. - *****************************************************************************/ - -#include -#include - -#include "proj_internal.h" -#include "proj_math.h" -#include "projects.h" - -#define INPUT_UNITS P->left -#define OUTPUT_UNITS P->right - - -static PJ_COORD fwd_prepare (PJ *P, PJ_COORD coo) { - if (HUGE_VAL==coo.v[0] || HUGE_VAL==coo.v[1] || HUGE_VAL==coo.v[2]) - return proj_coord_error (); - - /* The helmert datum shift will choke unless it gets a sensible 4D coordinate */ - if (HUGE_VAL==coo.v[2] && P->helmert) coo.v[2] = 0.0; - if (HUGE_VAL==coo.v[3] && P->helmert) coo.v[3] = 0.0; - - /* Check validity of angular input coordinates */ - if (INPUT_UNITS==PJ_IO_UNITS_ANGULAR) { - double t; - - /* check for latitude or longitude over-range */ - t = (coo.lp.phi < 0 ? -coo.lp.phi : coo.lp.phi) - M_HALFPI; - if (t > PJ_EPS_LAT || coo.lp.lam > 10 || coo.lp.lam < -10) { - proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); - return proj_coord_error (); - } - - /* Clamp latitude to -90..90 degree range */ - if (coo.lp.phi > M_HALFPI) - coo.lp.phi = M_HALFPI; - if (coo.lp.phi < -M_HALFPI) - coo.lp.phi = -M_HALFPI; - - /* If input latitude is geocentrical, convert to geographical */ - if (P->geoc) - coo = pj_geocentric_latitude (P, PJ_INV, coo); - - /* Ensure longitude is in the -pi:pi range */ - if (0==P->over) - coo.lp.lam = adjlon(coo.lp.lam); - - if (P->hgridshift) - coo = proj_trans (P->hgridshift, PJ_INV, coo); - else if (P->helmert || (P->cart_wgs84 != nullptr && P->cart != nullptr)) { - coo = proj_trans (P->cart_wgs84, PJ_FWD, coo); /* Go cartesian in WGS84 frame */ - if( P->helmert ) - coo = proj_trans (P->helmert, PJ_INV, coo); /* Step into local frame */ - coo = proj_trans (P->cart, PJ_INV, coo); /* Go back to angular using local ellps */ - } - if (coo.lp.lam==HUGE_VAL) - return coo; - if (P->vgridshift) - coo = proj_trans (P->vgridshift, PJ_FWD, coo); /* Go orthometric from geometric */ - - /* Distance from central meridian, taking system zero meridian into account */ - coo.lp.lam = (coo.lp.lam - P->from_greenwich) - P->lam0; - - /* Ensure longitude is in the -pi:pi range */ - if (0==P->over) - coo.lp.lam = adjlon(coo.lp.lam); - - return coo; - } - - - /* We do not support gridshifts on cartesian input */ - if (INPUT_UNITS==PJ_IO_UNITS_CARTESIAN && P->helmert) - return proj_trans (P->helmert, PJ_INV, coo); - return coo; -} - - -static PJ_COORD fwd_finalize (PJ *P, PJ_COORD coo) { - - switch (OUTPUT_UNITS) { - - /* Handle false eastings/northings and non-metric linear units */ - case PJ_IO_UNITS_CARTESIAN: - - if (P->is_geocent) { - coo = proj_trans (P->cart, PJ_FWD, coo); - } - coo.xyz.x *= P->fr_meter; - coo.xyz.y *= P->fr_meter; - coo.xyz.z *= P->fr_meter; - - break; - - /* Classic proj.4 functions return plane coordinates in units of the semimajor axis */ - case PJ_IO_UNITS_CLASSIC: - coo.xy.x *= P->a; - coo.xy.y *= P->a; - - /* Falls through */ /* (<-- GCC warning silencer) */ - /* to continue processing in common with PJ_IO_UNITS_PROJECTED */ - case PJ_IO_UNITS_PROJECTED: - coo.xyz.x = P->fr_meter * (coo.xyz.x + P->x0); - coo.xyz.y = P->fr_meter * (coo.xyz.y + P->y0); - coo.xyz.z = P->vfr_meter * (coo.xyz.z + P->z0); - break; - - case PJ_IO_UNITS_WHATEVER: - break; - - case PJ_IO_UNITS_ANGULAR: - coo.lpz.z = P->vfr_meter * (coo.lpz.z + P->z0); - - if( P->is_long_wrap_set ) { - if( coo.lpz.lam != HUGE_VAL ) { - coo.lpz.lam = P->long_wrap_center + - adjlon(coo.lpz.lam - P->long_wrap_center); - } - } - - break; - } - - if (P->axisswap) - coo = proj_trans (P->axisswap, PJ_FWD, coo); - - return coo; -} - - -static PJ_COORD error_or_coord(PJ *P, PJ_COORD coord, int last_errno) { - if (proj_errno(P)) - return proj_coord_error(); - - proj_errno_restore(P, last_errno); - return coord; -} - - -XY pj_fwd(LP lp, PJ *P) { - int last_errno; - PJ_COORD coo = {{0,0,0,0}}; - coo.lp = lp; - - last_errno = proj_errno_reset(P); - - if (!P->skip_fwd_prepare) - coo = fwd_prepare (P, coo); - if (HUGE_VAL==coo.v[0] || HUGE_VAL==coo.v[1]) - return proj_coord_error ().xy; - - /* Do the transformation, using the lowest dimensional transformer available */ - if (P->fwd) - coo.xy = P->fwd(coo.lp, P); - else if (P->fwd3d) - coo.xyz = P->fwd3d (coo.lpz, P); - else if (P->fwd4d) - coo = P->fwd4d (coo, P); - else { - proj_errno_set (P, EINVAL); - return proj_coord_error ().xy; - } - if (HUGE_VAL==coo.v[0]) - return proj_coord_error ().xy; - - if (!P->skip_fwd_finalize) - coo = fwd_finalize (P, coo); - - return error_or_coord(P, coo, last_errno).xy; -} - - - -XYZ pj_fwd3d(LPZ lpz, PJ *P) { - int last_errno; - PJ_COORD coo = {{0,0,0,0}}; - coo.lpz = lpz; - - last_errno = proj_errno_reset(P); - - if (!P->skip_fwd_prepare) - coo = fwd_prepare (P, coo); - if (HUGE_VAL==coo.v[0]) - return proj_coord_error ().xyz; - - /* Do the transformation, using the lowest dimensional transformer feasible */ - if (P->fwd3d) - coo.xyz = P->fwd3d(coo.lpz, P); - else if (P->fwd4d) - coo = P->fwd4d (coo, P); - else if (P->fwd) - coo.xy = P->fwd (coo.lp, P); - else { - proj_errno_set (P, EINVAL); - return proj_coord_error ().xyz; - } - if (HUGE_VAL==coo.v[0]) - return proj_coord_error ().xyz; - - if (!P->skip_fwd_finalize) - coo = fwd_finalize (P, coo); - - return error_or_coord(P, coo, last_errno).xyz; -} - - - -PJ_COORD pj_fwd4d (PJ_COORD coo, PJ *P) { - int last_errno = proj_errno_reset(P); - - if (!P->skip_fwd_prepare) - coo = fwd_prepare (P, coo); - if (HUGE_VAL==coo.v[0]) - return proj_coord_error (); - - /* Call the highest dimensional converter available */ - if (P->fwd4d) - coo = P->fwd4d (coo, P); - else if (P->fwd3d) - coo.xyz = P->fwd3d (coo.lpz, P); - else if (P->fwd) - coo.xy = P->fwd (coo.lp, P); - else { - proj_errno_set (P, EINVAL); - return proj_coord_error (); - } - if (HUGE_VAL==coo.v[0]) - return proj_coord_error (); - - if (!P->skip_fwd_finalize) - coo = fwd_finalize (P, coo); - - return error_or_coord(P, coo, last_errno); -} diff --git a/src/pj_gauss.cpp b/src/pj_gauss.cpp deleted file mode 100644 index 2db713ad..00000000 --- a/src/pj_gauss.cpp +++ /dev/null @@ -1,103 +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 - -#include "projects.h" - -#define MAX_ITER 20 - -namespace { // anonymous namespace -struct GAUSS { - double C; - double K; - double e; - double ratexp; -}; -} // anonymous namespace -#define DEL_TOL 1e-14 - -static double srat(double esinp, double ratexp) { - return(pow((1.-esinp)/(1.+esinp), ratexp)); -} - -void *pj_gauss_ini(double e, double phi0, double *chi, double *rc) { - double sphi, cphi, es; - struct GAUSS *en; - - if ((en = (struct GAUSS *)malloc(sizeof(struct GAUSS))) == nullptr) - return (nullptr); - es = e * e; - en->e = e; - sphi = sin(phi0); - cphi = cos(phi0); cphi *= cphi; - *rc = sqrt(1. - es) / (1. - es * sphi * sphi); - en->C = sqrt(1. + es * cphi * cphi / (1. - es)); - if (en->C == 0.0) { - free(en); - return nullptr; - } - *chi = asin(sphi / en->C); - en->ratexp = 0.5 * en->C * e; - en->K = tan(.5 * *chi + M_FORTPI) / ( - pow(tan(.5 * phi0 + M_FORTPI), en->C) * - srat(en->e * sphi, en->ratexp) ); - return ((void *)en); -} - -LP pj_gauss(projCtx ctx, LP elp, const void *data) { - const struct GAUSS *en = (const struct GAUSS *)data; - LP slp; - (void) ctx; - - slp.phi = 2. * atan( en->K * - pow(tan(.5 * elp.phi + M_FORTPI), en->C) * - srat(en->e * sin(elp.phi), en->ratexp) ) - M_HALFPI; - slp.lam = en->C * (elp.lam); - return(slp); -} - -LP pj_inv_gauss(projCtx ctx, LP slp, const void *data) { - const struct GAUSS *en = (const struct GAUSS *)data; - LP elp; - double num; - int i; - - elp.lam = slp.lam / en->C; - num = pow(tan(.5 * slp.phi + M_FORTPI)/en->K, 1./en->C); - for (i = MAX_ITER; i; --i) { - elp.phi = 2. * atan(num * srat(en->e * sin(slp.phi), -.5 * en->e)) - - M_HALFPI; - if (fabs(elp.phi - slp.phi) < DEL_TOL) break; - slp.phi = elp.phi; - } - /* convergence failed */ - if (!i) - pj_ctx_set_errno(ctx, PJD_ERR_NON_CONV_INV_MERI_DIST); - return (elp); -} diff --git a/src/pj_gc_reader.cpp b/src/pj_gc_reader.cpp deleted file mode 100644 index 118aadf6..00000000 --- a/src/pj_gc_reader.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Code to read a grid catalog from a .cvs file. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2012, 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include -#include -#include - -#include "projects.h" - -static int gc_readentry(projCtx ctx, PAFile fid, PJ_GridCatalogEntry *entry); - -/************************************************************************/ -/* pj_gc_readcatalog() */ -/* */ -/* Read a grid catalog from a .csv file. */ -/************************************************************************/ - -PJ_GridCatalog *pj_gc_readcatalog( projCtx ctx, const char *catalog_name ) -{ - PAFile fid; - PJ_GridCatalog *catalog; - int entry_max; - char line[302]; - - fid = pj_open_lib( ctx, catalog_name, "r" ); - if (fid == nullptr) - return nullptr; - - /* discard title line */ - pj_ctx_fgets(ctx, line, sizeof(line)-1, fid); - - catalog = (PJ_GridCatalog *) calloc(1,sizeof(PJ_GridCatalog)); - if( !catalog ) - { - pj_ctx_set_errno(ctx, ENOMEM); - pj_ctx_fclose(ctx, fid); - return nullptr; - } - - catalog->catalog_name = pj_strdup(catalog_name); - if (!catalog->catalog_name) { - pj_ctx_set_errno(ctx, ENOMEM); - free(catalog); - pj_ctx_fclose(ctx, fid); - return nullptr; - } - - entry_max = 10; - catalog->entries = (PJ_GridCatalogEntry *) - malloc(entry_max * sizeof(PJ_GridCatalogEntry)); - if (!catalog->entries) { - pj_ctx_set_errno(ctx, ENOMEM); - free(catalog->catalog_name); - free(catalog); - pj_ctx_fclose(ctx, fid); - return nullptr; - } - - while( gc_readentry( ctx, fid, - catalog->entries+catalog->entry_count) == 0) - { - catalog->entry_count++; - - if( catalog->entry_count == entry_max ) - { - PJ_GridCatalogEntry* new_entries; - entry_max = entry_max * 2; - new_entries = (PJ_GridCatalogEntry *) - realloc(catalog->entries, - entry_max * sizeof(PJ_GridCatalogEntry)); - if (new_entries == nullptr ) - { - int i; - for( i = 0; i < catalog->entry_count; i++ ) - free( catalog->entries[i].definition ); - free( catalog->entries ); - free( catalog->catalog_name ); - free( catalog ); - pj_ctx_fclose(ctx, fid); - return nullptr; - } - catalog->entries = new_entries; - } - } - - pj_ctx_fclose(ctx, fid); - - return catalog; -} - -/************************************************************************/ -/* gc_read_csv_line() */ -/* */ -/* Simple csv line splitter with fixed maximum line size and */ -/* token count. */ -/************************************************************************/ - -static int gc_read_csv_line( projCtx ctx, PAFile fid, - char **tokens, int max_tokens ) -{ - char line[302]; - - while( pj_ctx_fgets(ctx, line, sizeof(line)-1, fid) != nullptr ) - { - char *next = line; - int token_count = 0; - - while( isspace(*next) ) - next++; - - /* skip blank and comment lines */ - if( next[0] == '#' || next[0] == '\0' ) - continue; - - while( token_count < max_tokens && *next != '\0' ) - { - const char *start = next; - char* token; - - while( *next != '\0' && *next != ',' ) - next++; - - if( *next == ',' ) - { - *next = '\0'; - next++; - } - - token = pj_strdup(start); - if (!token) { - while (token_count > 0) - free(tokens[--token_count]); - pj_ctx_set_errno(ctx, ENOMEM); - return 0; - } - tokens[token_count++] = token; - } - - return token_count; - } - - return 0; -} - -/************************************************************************/ -/* pj_gc_parsedate() */ -/* */ -/* Parse a date into a floating point year value. Acceptable */ -/* values are "yyyy.fraction" and "yyyy-mm-dd". Anything else */ -/* returns 0.0. */ -/************************************************************************/ - -double pj_gc_parsedate( projCtx ctx, const char *date_string ) -{ - (void) ctx; - - if( strlen(date_string) == 10 - && date_string[4] == '-' && date_string[7] == '-' ) - { - int year = atoi(date_string); - int month = atoi(date_string+5); - int day = atoi(date_string+8); - - /* simplified calculation so we don't need to know all about months */ - return year + ((month-1) * 31 + (day-1)) / 372.0; - } - else - { - return pj_atof(date_string); - } -} - - -/************************************************************************/ -/* gc_readentry() */ -/* */ -/* Read one catalog entry from the file */ -/* */ -/* Format: */ -/* gridname,ll_long,ll_lat,ur_long,ur_lat,priority,date */ -/************************************************************************/ - -static int gc_readentry(projCtx ctx, PAFile fid, PJ_GridCatalogEntry *entry) -{ -#define MAX_TOKENS 30 - char *tokens[MAX_TOKENS]; - int token_count, i; - int error = 0; - - memset( entry, 0, sizeof(PJ_GridCatalogEntry) ); - - token_count = gc_read_csv_line( ctx, fid, tokens, MAX_TOKENS ); - if( token_count < 5 ) - { - error = 1; /* TODO: need real error codes */ - if( token_count != 0 ) - pj_log( ctx, PJ_LOG_ERROR, "Short line in grid catalog." ); - } - else - { - entry->definition = tokens[0]; - tokens[0] = nullptr; /* We take ownership of tokens[0] */ - entry->region.ll_long = dmstor_ctx( ctx, tokens[1], nullptr ); - entry->region.ll_lat = dmstor_ctx( ctx, tokens[2], nullptr ); - entry->region.ur_long = dmstor_ctx( ctx, tokens[3], nullptr ); - entry->region.ur_lat = dmstor_ctx( ctx, tokens[4], nullptr ); - if( token_count > 5 ) - entry->priority = atoi( tokens[5] ); /* defaults to zero */ - if( token_count > 6 ) - entry->date = pj_gc_parsedate( ctx, tokens[6] ); - } - - for( i = 0; i < token_count; i++ ) - free( tokens[i] ); - - return error; -} - - - diff --git a/src/pj_gridcatalog.cpp b/src/pj_gridcatalog.cpp deleted file mode 100644 index fef2df56..00000000 --- a/src/pj_gridcatalog.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Code in support of grid catalogs - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2012, 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include -#include -#include - -#include "projects.h" - -static PJ_GridCatalog *grid_catalog_list = nullptr; - -/************************************************************************/ -/* pj_gc_unloadall() */ -/* */ -/* Deallocate all the grid catalogs (but not the referenced */ -/* grids). */ -/************************************************************************/ - -void pj_gc_unloadall( projCtx ctx ) -{ - (void) ctx; - - while( grid_catalog_list != nullptr ) - { - int i; - PJ_GridCatalog *catalog = grid_catalog_list; - grid_catalog_list = grid_catalog_list->next; - - for( i = 0; i < catalog->entry_count; i++ ) - { - /* we don't own gridinfo - do not free here */ - free( catalog->entries[i].definition ); - } - free( catalog->entries ); - free( catalog->catalog_name ); - free( catalog ); - } -} - -/************************************************************************/ -/* pj_gc_findcatalog() */ -/************************************************************************/ - -PJ_GridCatalog *pj_gc_findcatalog( projCtx ctx, const char *name ) - -{ - PJ_GridCatalog *catalog; - - pj_acquire_lock(); - - for( catalog=grid_catalog_list; catalog != nullptr; catalog = catalog->next ) - { - if( strcmp(catalog->catalog_name, name) == 0 ) - { - pj_release_lock(); - return catalog; - } - } - - pj_release_lock(); - - catalog = pj_gc_readcatalog( ctx, name ); - if( catalog == nullptr ) - return nullptr; - - pj_acquire_lock(); - catalog->next = grid_catalog_list; - grid_catalog_list = catalog; - pj_release_lock(); - - return catalog; -} - -/************************************************************************/ -/* pj_gc_apply_gridshift() */ -/************************************************************************/ - -int pj_gc_apply_gridshift( PJ *defn, int inverse, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - int i; - (void) z; - - if( defn->catalog == nullptr ) - { - defn->catalog = pj_gc_findcatalog( defn->ctx, defn->catalog_name ); - if( defn->catalog == nullptr ) - return defn->ctx->last_errno; - } - - defn->ctx->last_errno = 0; - - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - LP input, output_after, output_before; - double mix_ratio; - PJ_GRIDINFO *gi; - - input.phi = y[io]; - input.lam = x[io]; - - /* make sure we have appropriate "after" shift file available */ - if( defn->last_after_grid == nullptr - || input.lam < defn->last_after_region.ll_long - || input.lam > defn->last_after_region.ur_long - || input.phi < defn->last_after_region.ll_lat - || input.phi > defn->last_after_region.ll_lat ) { - defn->last_after_grid = - pj_gc_findgrid( defn->ctx, defn->catalog, - 1, input, defn->datum_date, - &(defn->last_after_region), - &(defn->last_after_date)); - if( defn->last_after_grid == nullptr ) - { - pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return PJD_ERR_FAILED_TO_LOAD_GRID; - } - } - gi = defn->last_after_grid; - assert( gi->child == nullptr ); - - /* load the grid shift info if we don't have it. */ - if( gi->ct->cvs == nullptr && !pj_gridinfo_load( defn->ctx, gi ) ) - { - pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return PJD_ERR_FAILED_TO_LOAD_GRID; - } - - output_after = nad_cvt( input, inverse, gi->ct ); - if( output_after.lam == HUGE_VAL ) - { - if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) - { - pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR, - "pj_apply_gridshift(): failed to find a grid shift table for\n" - " location (%.7fdW,%.7fdN)", - x[io] * RAD_TO_DEG, - y[io] * RAD_TO_DEG ); - } - continue; - } - - if( defn->datum_date == 0.0 ) - { - y[io] = output_after.phi; - x[io] = output_after.lam; - continue; - } - - /* make sure we have appropriate "before" shift file available */ - if( defn->last_before_grid == nullptr - || input.lam < defn->last_before_region.ll_long - || input.lam > defn->last_before_region.ur_long - || input.phi < defn->last_before_region.ll_lat - || input.phi > defn->last_before_region.ll_lat ) { - defn->last_before_grid = - pj_gc_findgrid( defn->ctx, defn->catalog, - 0, input, defn->datum_date, - &(defn->last_before_region), - &(defn->last_before_date)); - if( defn->last_before_grid == nullptr ) - { - pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return PJD_ERR_FAILED_TO_LOAD_GRID; - } - } - - gi = defn->last_before_grid; - assert( gi->child == nullptr ); - - /* load the grid shift info if we don't have it. */ - if( gi->ct->cvs == nullptr && !pj_gridinfo_load( defn->ctx, gi ) ) - { - pj_ctx_set_errno( defn->ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return PJD_ERR_FAILED_TO_LOAD_GRID; - } - - output_before = nad_cvt( input, inverse, gi->ct ); - if( output_before.lam == HUGE_VAL ) - { - if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) - { - pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR, - "pj_apply_gridshift(): failed to find a grid shift table for\n" - " location (%.7fdW,%.7fdN)", - x[io] * RAD_TO_DEG, - y[io] * RAD_TO_DEG ); - } - continue; - } - - mix_ratio = (defn->datum_date - defn->last_before_date) - / (defn->last_after_date - defn->last_before_date); - - y[io] = mix_ratio * output_after.phi - + (1.0-mix_ratio) * output_before.phi; - x[io] = mix_ratio * output_after.lam - + (1.0-mix_ratio) * output_before.lam; - } - - return 0; -} - -/************************************************************************/ -/* pj_c_findgrid() */ -/************************************************************************/ - -PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx, PJ_GridCatalog *catalog, int after, - LP location, double date, - PJ_Region *optional_region, - double *grid_date ) -{ - int iEntry; - PJ_GridCatalogEntry *entry = nullptr; - - for( iEntry = 0; iEntry < catalog->entry_count; iEntry++ ) - { - entry = catalog->entries + iEntry; - - if( (after && entry->date < date) - || (!after && entry->date > date) ) - continue; - - if( location.lam < entry->region.ll_long - || location.lam > entry->region.ur_long - || location.phi < entry->region.ll_lat - || location.phi > entry->region.ur_lat ) - continue; - - if( entry->available == -1 ) - continue; - - break; - } - - if( entry == nullptr ) - { - if( grid_date ) - *grid_date = 0.0; - if( optional_region != nullptr ) - memset( optional_region, 0, sizeof(PJ_Region)); - return nullptr; - } - - if( grid_date ) - *grid_date = entry->date; - - if( optional_region ) - { - - } - - if( entry->gridinfo == nullptr ) - { - PJ_GRIDINFO **gridlist = nullptr; - int grid_count = 0; - gridlist = pj_gridlist_from_nadgrids( ctx, entry->definition, - &grid_count); - if( grid_count == 1 ) - entry->gridinfo = gridlist[0]; - } - - return entry->gridinfo; -} - diff --git a/src/pj_gridinfo.cpp b/src/pj_gridinfo.cpp deleted file mode 100644 index 046abfcc..00000000 --- a/src/pj_gridinfo.cpp +++ /dev/null @@ -1,991 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Functions for handling individual PJ_GRIDINFO's. Includes - * loaders for all formats but CTABLE (in nad_init.c). - * 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include -#include -#include -#include -#include - -#include "proj_internal.h" -#include "projects.h" - -/************************************************************************/ -/* swap_words() */ -/* */ -/* Convert the byte order of the given word(s) in place. */ -/************************************************************************/ - -static const int byte_order_test = 1; -#define IS_LSB (1 == ((const unsigned char *) (&byte_order_test))[0]) - -static void swap_words( unsigned char *data, int word_size, int word_count ) - -{ - int word; - - for( word = 0; word < word_count; word++ ) - { - int i; - - for( i = 0; i < word_size/2; i++ ) - { - unsigned char t; - - t = data[i]; - data[i] = data[word_size-i-1]; - data[word_size-i-1] = t; - } - - data += word_size; - } -} - -/************************************************************************/ -/* to_double() */ -/* */ -/* Returns a double from the pointed data. */ -/************************************************************************/ - -static double to_double( unsigned char* data ) -{ - double d; - memcpy(&d, data, sizeof(d)); - return d; -} - -/************************************************************************/ -/* pj_gridinfo_free() */ -/************************************************************************/ - -void pj_gridinfo_free( projCtx ctx, PJ_GRIDINFO *gi ) - -{ - if( gi == nullptr ) - return; - - if( gi->child != nullptr ) - { - PJ_GRIDINFO *child, *next; - - for( child = gi->child; child != nullptr; child=next) - { - next=child->next; - pj_gridinfo_free( ctx, child ); - } - } - - if( gi->ct != nullptr ) - nad_free( gi->ct ); - - free( gi->gridname ); - if( gi->filename != nullptr ) - free( gi->filename ); - - pj_dalloc( gi ); -} - -/************************************************************************/ -/* pj_gridinfo_load() */ -/* */ -/* This function is intended to implement delayed loading of */ -/* the data contents of a grid file. The header and related */ -/* stuff are loaded by pj_gridinfo_init(). */ -/************************************************************************/ - -int pj_gridinfo_load( projCtx ctx, PJ_GRIDINFO *gi ) - -{ - struct CTABLE ct_tmp; - - if( gi == nullptr || gi->ct == nullptr ) - return 0; - - pj_acquire_lock(); - if( gi->ct->cvs != nullptr ) - { - pj_release_lock(); - return 1; - } - - memcpy(&ct_tmp, gi->ct, sizeof(struct CTABLE)); - -/* -------------------------------------------------------------------- */ -/* Original platform specific CTable format. */ -/* -------------------------------------------------------------------- */ - if( strcmp(gi->format,"ctable") == 0 ) - { - PAFile fid; - int result; - - fid = pj_open_lib( ctx, gi->filename, "rb" ); - - if( fid == nullptr ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return 0; - } - - result = nad_ctable_load( ctx, &ct_tmp, fid ); - - pj_ctx_fclose( ctx, fid ); - - gi->ct->cvs = ct_tmp.cvs; - pj_release_lock(); - - return result; - } - -/* -------------------------------------------------------------------- */ -/* CTable2 format. */ -/* -------------------------------------------------------------------- */ - else if( strcmp(gi->format,"ctable2") == 0 ) - { - PAFile fid; - int result; - - fid = pj_open_lib( ctx, gi->filename, "rb" ); - - if( fid == nullptr ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return 0; - } - - result = nad_ctable2_load( ctx, &ct_tmp, fid ); - - pj_ctx_fclose( ctx, fid ); - - gi->ct->cvs = ct_tmp.cvs; - - pj_release_lock(); - return result; - } - -/* -------------------------------------------------------------------- */ -/* NTv1 format. */ -/* We process one line at a time. Note that the array storage */ -/* direction (e-w) is different in the NTv1 file and what */ -/* the CTABLE is supposed to have. The phi/lam are also */ -/* reversed, and we have to be aware of byte swapping. */ -/* -------------------------------------------------------------------- */ - else if( strcmp(gi->format,"ntv1") == 0 ) - { - double *row_buf; - int row; - PAFile fid; - - fid = pj_open_lib( ctx, gi->filename, "rb" ); - - if( fid == nullptr ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return 0; - } - - pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); - - row_buf = (double *) pj_malloc(gi->ct->lim.lam * sizeof(double) * 2); - ct_tmp.cvs = (FLP *) pj_malloc(gi->ct->lim.lam*gi->ct->lim.phi*sizeof(FLP)); - if( row_buf == nullptr || ct_tmp.cvs == nullptr ) - { - pj_dalloc( row_buf ); - pj_dalloc( ct_tmp.cvs ); - pj_ctx_set_errno( ctx, ENOMEM ); - pj_release_lock(); - return 0; - } - - for( row = 0; row < gi->ct->lim.phi; row++ ) - { - int i; - FLP *cvs; - double *diff_seconds; - - if( pj_ctx_fread( ctx, row_buf, - sizeof(double), gi->ct->lim.lam * 2, fid ) - != (size_t)( 2 * gi->ct->lim.lam ) ) - { - pj_dalloc( row_buf ); - pj_dalloc( ct_tmp.cvs ); - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return 0; - } - - if( IS_LSB ) - swap_words( (unsigned char *) row_buf, 8, gi->ct->lim.lam*2 ); - - /* convert seconds to radians */ - diff_seconds = row_buf; - - for( i = 0; i < gi->ct->lim.lam; i++ ) - { - cvs = ct_tmp.cvs + (row) * gi->ct->lim.lam - + (gi->ct->lim.lam - i - 1); - - cvs->phi = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); - cvs->lam = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); - } - } - - pj_dalloc( row_buf ); - - pj_ctx_fclose( ctx, fid ); - - gi->ct->cvs = ct_tmp.cvs; - pj_release_lock(); - - return 1; - } - -/* -------------------------------------------------------------------- */ -/* NTv2 format. */ -/* We process one line at a time. Note that the array storage */ -/* direction (e-w) is different in the NTv2 file and what */ -/* the CTABLE is supposed to have. The phi/lam are also */ -/* reversed, and we have to be aware of byte swapping. */ -/* -------------------------------------------------------------------- */ - else if( strcmp(gi->format,"ntv2") == 0 ) - { - float *row_buf; - int row; - PAFile fid; - - pj_log( ctx, PJ_LOG_DEBUG_MINOR, - "NTv2 - loading grid %s", gi->ct->id ); - - fid = pj_open_lib( ctx, gi->filename, "rb" ); - - if( fid == nullptr ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return 0; - } - - pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); - - row_buf = (float *) pj_malloc(gi->ct->lim.lam * sizeof(float) * 4); - ct_tmp.cvs = (FLP *) pj_malloc(gi->ct->lim.lam*gi->ct->lim.phi*sizeof(FLP)); - if( row_buf == nullptr || ct_tmp.cvs == nullptr ) - { - pj_dalloc( row_buf ); - pj_dalloc( ct_tmp.cvs ); - pj_ctx_set_errno( ctx, ENOMEM ); - pj_release_lock(); - return 0; - } - - for( row = 0; row < gi->ct->lim.phi; row++ ) - { - int i; - FLP *cvs; - float *diff_seconds; - - if( pj_ctx_fread( ctx, row_buf, sizeof(float), - gi->ct->lim.lam*4, fid ) - != (size_t)( 4 * gi->ct->lim.lam ) ) - { - pj_dalloc( row_buf ); - pj_dalloc( ct_tmp.cvs ); - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return 0; - } - - if( gi->must_swap ) - swap_words( (unsigned char *) row_buf, 4, - gi->ct->lim.lam*4 ); - - /* convert seconds to radians */ - diff_seconds = row_buf; - - for( i = 0; i < gi->ct->lim.lam; i++ ) - { - cvs = ct_tmp.cvs + (row) * gi->ct->lim.lam - + (gi->ct->lim.lam - i - 1); - - cvs->phi = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); - cvs->lam = (float) (*(diff_seconds++) * ((M_PI/180.0) / 3600.0)); - diff_seconds += 2; /* skip accuracy values */ - } - } - - pj_dalloc( row_buf ); - - pj_ctx_fclose( ctx, fid ); - - gi->ct->cvs = ct_tmp.cvs; - - pj_release_lock(); - return 1; - } - -/* -------------------------------------------------------------------- */ -/* GTX format. */ -/* -------------------------------------------------------------------- */ - else if( strcmp(gi->format,"gtx") == 0 ) - { - int words = gi->ct->lim.lam * gi->ct->lim.phi; - PAFile fid; - - fid = pj_open_lib( ctx, gi->filename, "rb" ); - - if( fid == nullptr ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return 0; - } - - pj_ctx_fseek( ctx, fid, gi->grid_offset, SEEK_SET ); - - ct_tmp.cvs = (FLP *) pj_malloc(words*sizeof(float)); - if( ct_tmp.cvs == nullptr ) - { - pj_ctx_set_errno( ctx, ENOMEM ); - pj_release_lock(); - return 0; - } - - if( pj_ctx_fread( ctx, ct_tmp.cvs, sizeof(float), words, fid ) - != (size_t)words ) - { - pj_dalloc( ct_tmp.cvs ); - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return 0; - } - - if( IS_LSB ) - swap_words( (unsigned char *) ct_tmp.cvs, 4, words ); - - pj_ctx_fclose( ctx, fid ); - gi->ct->cvs = ct_tmp.cvs; - pj_release_lock(); - return 1; - } - - else - { - pj_release_lock(); - return 0; - } -} - -/************************************************************************/ -/* gridinfo_parent() */ -/* */ -/* Seek a parent grid file by name from a grid list */ -/************************************************************************/ - -static PJ_GRIDINFO* gridinfo_parent( PJ_GRIDINFO *gilist, - const char *name, int length ) -{ - while( gilist ) - { - if( strncmp(gilist->ct->id,name,length) == 0 ) return gilist; - if( gilist->child ) - { - PJ_GRIDINFO *parent=gridinfo_parent( gilist->child, name, length ); - if( parent ) return parent; - } - gilist=gilist->next; - } - return gilist; -} - -/************************************************************************/ -/* pj_gridinfo_init_ntv2() */ -/* */ -/* Load a ntv2 (.gsb) file. */ -/************************************************************************/ - -static int pj_gridinfo_init_ntv2( projCtx ctx, PAFile fid, PJ_GRIDINFO *gilist ) -{ - unsigned char header[11*16]; - int num_subfiles, subfile; - int must_swap; - - /* cppcheck-suppress sizeofCalculation */ - STATIC_ASSERT( sizeof(pj_int32) == 4 ); - /* cppcheck-suppress sizeofCalculation */ - STATIC_ASSERT( sizeof(double) == 8 ); - -/* -------------------------------------------------------------------- */ -/* Read the overview header. */ -/* -------------------------------------------------------------------- */ - if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return 0; - } - - if( header[8] == 11 ) - must_swap = !IS_LSB; - else - must_swap = IS_LSB; - -/* -------------------------------------------------------------------- */ -/* Byte swap interesting fields if needed. */ -/* -------------------------------------------------------------------- */ - if( must_swap ) - { - swap_words( header+8, 4, 1 ); - swap_words( header+8+16, 4, 1 ); - swap_words( header+8+32, 4, 1 ); - swap_words( header+8+7*16, 8, 1 ); - swap_words( header+8+8*16, 8, 1 ); - swap_words( header+8+9*16, 8, 1 ); - swap_words( header+8+10*16, 8, 1 ); - } - -/* -------------------------------------------------------------------- */ -/* Get the subfile count out ... all we really use for now. */ -/* -------------------------------------------------------------------- */ - memcpy( &num_subfiles, header+8+32, 4 ); - -/* ==================================================================== */ -/* Step through the subfiles, creating a PJ_GRIDINFO for each. */ -/* ==================================================================== */ - for( subfile = 0; subfile < num_subfiles; subfile++ ) - { - struct CTABLE *ct; - LP ur; - int gs_count; - PJ_GRIDINFO *gi; - -/* -------------------------------------------------------------------- */ -/* Read header. */ -/* -------------------------------------------------------------------- */ - if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return 0; - } - - if( strncmp((const char *) header,"SUB_NAME",8) != 0 ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return 0; - } - -/* -------------------------------------------------------------------- */ -/* Byte swap interesting fields if needed. */ -/* -------------------------------------------------------------------- */ - if( must_swap ) - { - swap_words( header+8+16*4, 8, 1 ); - swap_words( header+8+16*5, 8, 1 ); - swap_words( header+8+16*6, 8, 1 ); - swap_words( header+8+16*7, 8, 1 ); - swap_words( header+8+16*8, 8, 1 ); - swap_words( header+8+16*9, 8, 1 ); - swap_words( header+8+16*10, 4, 1 ); - } - -/* -------------------------------------------------------------------- */ -/* Initialize a corresponding "ct" structure. */ -/* -------------------------------------------------------------------- */ - ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); - if (!ct) { - pj_ctx_set_errno(ctx, ENOMEM); - return 0; - } - strncpy( ct->id, (const char *) header + 8, 8 ); - ct->id[8] = '\0'; - - ct->ll.lam = - to_double(header+7*16+8); /* W_LONG */ - ct->ll.phi = to_double(header+4*16+8); /* S_LAT */ - - ur.lam = - to_double(header+6*16+8); /* E_LONG */ - ur.phi = to_double(header+5*16+8); /* N_LAT */ - - ct->del.lam = to_double(header+9*16+8); - ct->del.phi = to_double(header+8*16+8); - - ct->lim.lam = (pj_int32) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1; - ct->lim.phi = (pj_int32) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1; - - pj_log( ctx, PJ_LOG_DEBUG_MINOR, - "NTv2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", - ct->id, - ct->lim.lam, ct->lim.phi, - ct->ll.lam/3600.0, ct->ll.phi/3600.0, - ur.lam/3600.0, ur.phi/3600.0 ); - - ct->ll.lam *= DEG_TO_RAD/3600.0; - ct->ll.phi *= DEG_TO_RAD/3600.0; - ct->del.lam *= DEG_TO_RAD/3600.0; - ct->del.phi *= DEG_TO_RAD/3600.0; - - memcpy( &gs_count, header + 8 + 16*10, 4 ); - if( gs_count != ct->lim.lam * ct->lim.phi ) - { - pj_log( ctx, PJ_LOG_ERROR, - "GS_COUNT(%d) does not match expected cells (%dx%d=%d)", - gs_count, ct->lim.lam, ct->lim.phi, - ct->lim.lam * ct->lim.phi ); - pj_dalloc(ct); - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return 0; - } - - ct->cvs = nullptr; - -/* -------------------------------------------------------------------- */ -/* Create a new gridinfo for this if we aren't processing the */ -/* 1st subfile, and initialize our grid info. */ -/* -------------------------------------------------------------------- */ - if( subfile == 0 ) - gi = gilist; - else - { - gi = (PJ_GRIDINFO *) pj_calloc(1, sizeof(PJ_GRIDINFO)); - if (!gi) { - pj_dalloc(ct); - pj_gridinfo_free(ctx, gilist); - pj_ctx_set_errno(ctx, ENOMEM); - return 0; - } - - gi->gridname = pj_strdup( gilist->gridname ); - gi->filename = pj_strdup( gilist->filename ); - if (!gi->gridname || !gi->filename) { - pj_gridinfo_free(ctx, gi); - pj_dalloc(ct); - pj_gridinfo_free(ctx, gilist); - pj_ctx_set_errno(ctx, ENOMEM); - return 0; - } - gi->next = nullptr; - } - - gi->must_swap = must_swap; - gi->ct = ct; - gi->format = "ntv2"; - gi->grid_offset = pj_ctx_ftell( ctx, fid ); - -/* -------------------------------------------------------------------- */ -/* Attach to the correct list or sublist. */ -/* -------------------------------------------------------------------- */ - if( strncmp((const char *)header+24,"NONE",4) == 0 ) - { - if( gi != gilist ) - { - PJ_GRIDINFO *lnk; - - for( lnk = gilist; lnk->next != nullptr; lnk = lnk->next ) {} - lnk->next = gi; - } - } - - else - { - PJ_GRIDINFO *lnk; - PJ_GRIDINFO *gp = gridinfo_parent(gilist, - (const char*)header+24,8); - - if( gp == nullptr ) - { - pj_log( ctx, PJ_LOG_ERROR, - "pj_gridinfo_init_ntv2(): " - "failed to find parent %8.8s for %s.", - (const char *) header+24, gi->ct->id ); - - for( lnk = gilist; lnk->next != nullptr; lnk = lnk->next ) {} - lnk->next = gi; - } - else - { - if( gp->child == nullptr ) - { - gp->child = gi; - } - else - { - for( lnk = gp->child; lnk->next != nullptr; lnk = lnk->next ) {} - lnk->next = gi; - } - } - } - -/* -------------------------------------------------------------------- */ -/* Seek past the data. */ -/* -------------------------------------------------------------------- */ - pj_ctx_fseek( ctx, fid, gs_count * 16, SEEK_CUR ); - } - - return 1; -} - -/************************************************************************/ -/* pj_gridinfo_init_ntv1() */ -/* */ -/* Load an NTv1 style Canadian grid shift file. */ -/************************************************************************/ - -static int pj_gridinfo_init_ntv1( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi ) - -{ - unsigned char header[192]; /* 12 records of 16 bytes */ - struct CTABLE *ct; - LP ur; - - /* cppcheck-suppress sizeofCalculation */ - STATIC_ASSERT( sizeof(pj_int32) == 4 ); - /* cppcheck-suppress sizeofCalculation */ - STATIC_ASSERT( sizeof(double) == 8 ); - -/* -------------------------------------------------------------------- */ -/* Read the header. */ -/* -------------------------------------------------------------------- */ - if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return 0; - } - -/* -------------------------------------------------------------------- */ -/* Regularize fields of interest. */ -/* -------------------------------------------------------------------- */ - if( IS_LSB ) - { - swap_words( header+8, 4, 1 ); - swap_words( header+24, 8, 1 ); - swap_words( header+40, 8, 1 ); - swap_words( header+56, 8, 1 ); - swap_words( header+72, 8, 1 ); - swap_words( header+88, 8, 1 ); - swap_words( header+104, 8, 1 ); - } - - if( *((int *) (header+8)) != 12 ) - { - pj_log( ctx, PJ_LOG_ERROR, - "NTv1 grid shift file has wrong record count, corrupt?" ); - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return 0; - } - -/* -------------------------------------------------------------------- */ -/* Fill in CTABLE structure. */ -/* -------------------------------------------------------------------- */ - ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); - if (!ct) { - pj_ctx_set_errno(ctx, ENOMEM); - return 0; - } - strcpy( ct->id, "NTv1 Grid Shift File" ); - - ct->ll.lam = - to_double(header+72); - ct->ll.phi = to_double(header+24); - ur.lam = - to_double(header+56); - ur.phi = to_double(header+40); - ct->del.lam = to_double(header+104); - ct->del.phi = to_double(header+88); - ct->lim.lam = (pj_int32) (fabs(ur.lam-ct->ll.lam)/ct->del.lam + 0.5) + 1; - ct->lim.phi = (pj_int32) (fabs(ur.phi-ct->ll.phi)/ct->del.phi + 0.5) + 1; - - pj_log( ctx, PJ_LOG_DEBUG_MINOR, - "NTv1 %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", - ct->lim.lam, ct->lim.phi, - ct->ll.lam, ct->ll.phi, ur.lam, ur.phi ); - - ct->ll.lam *= DEG_TO_RAD; - ct->ll.phi *= DEG_TO_RAD; - ct->del.lam *= DEG_TO_RAD; - ct->del.phi *= DEG_TO_RAD; - ct->cvs = nullptr; - - gi->ct = ct; - gi->grid_offset = (long) sizeof(header); - gi->format = "ntv1"; - - return 1; -} - -/************************************************************************/ -/* pj_gridinfo_init_gtx() */ -/* */ -/* Load a NOAA .gtx vertical datum shift file. */ -/************************************************************************/ - -static int pj_gridinfo_init_gtx( projCtx ctx, PAFile fid, PJ_GRIDINFO *gi ) - -{ - unsigned char header[40]; - struct CTABLE *ct; - double xorigin,yorigin,xstep,ystep; - int rows, columns; - - /* cppcheck-suppress sizeofCalculation */ - STATIC_ASSERT( sizeof(pj_int32) == 4 ); - /* cppcheck-suppress sizeofCalculation */ - STATIC_ASSERT( sizeof(double) == 8 ); - -/* -------------------------------------------------------------------- */ -/* Read the header. */ -/* -------------------------------------------------------------------- */ - if( pj_ctx_fread( ctx, header, sizeof(header), 1, fid ) != 1 ) - { - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return 0; - } - -/* -------------------------------------------------------------------- */ -/* Regularize fields of interest and extract. */ -/* -------------------------------------------------------------------- */ - if( IS_LSB ) - { - swap_words( header+0, 8, 4 ); - swap_words( header+32, 4, 2 ); - } - - memcpy( &yorigin, header+0, 8 ); - memcpy( &xorigin, header+8, 8 ); - memcpy( &ystep, header+16, 8 ); - memcpy( &xstep, header+24, 8 ); - - memcpy( &rows, header+32, 4 ); - memcpy( &columns, header+36, 4 ); - - if( xorigin < -360 || xorigin > 360 - || yorigin < -90 || yorigin > 90 ) - { - pj_log( ctx, PJ_LOG_ERROR, - "gtx file header has invalid extents, corrupt?"); - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - return 0; - } - -/* -------------------------------------------------------------------- */ -/* Fill in CTABLE structure. */ -/* -------------------------------------------------------------------- */ - ct = (struct CTABLE *) pj_malloc(sizeof(struct CTABLE)); - if (!ct) { - pj_ctx_set_errno(ctx, ENOMEM); - return 0; - } - strcpy( ct->id, "GTX Vertical Grid Shift File" ); - - ct->ll.lam = xorigin; - ct->ll.phi = yorigin; - ct->del.lam = xstep; - ct->del.phi = ystep; - ct->lim.lam = columns; - ct->lim.phi = rows; - - /* some GTX files come in 0-360 and we shift them back into the - expected -180 to 180 range if possible. This does not solve - problems with grids spanning the dateline. */ - if( ct->ll.lam >= 180.0 ) - ct->ll.lam -= 360.0; - - if( ct->ll.lam >= 0.0 && ct->ll.lam + ct->del.lam * ct->lim.lam > 180.0 ) - { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "This GTX spans the dateline! This will cause problems." ); - } - - pj_log( ctx, PJ_LOG_DEBUG_MINOR, - "GTX %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", - ct->lim.lam, ct->lim.phi, - ct->ll.lam, ct->ll.phi, - ct->ll.lam + (columns-1)*xstep, ct->ll.phi + (rows-1)*ystep); - - ct->ll.lam *= DEG_TO_RAD; - ct->ll.phi *= DEG_TO_RAD; - ct->del.lam *= DEG_TO_RAD; - ct->del.phi *= DEG_TO_RAD; - ct->cvs = nullptr; - - gi->ct = ct; - gi->grid_offset = 40; - gi->format = "gtx"; - - return 1; -} - -/************************************************************************/ -/* pj_gridinfo_init() */ -/* */ -/* Open and parse header details from a datum gridshift file */ -/* returning a list of PJ_GRIDINFOs for the grids in that */ -/* file. This superceeds use of nad_init() for modern */ -/* applications. */ -/************************************************************************/ - -PJ_GRIDINFO *pj_gridinfo_init( projCtx ctx, const char *gridname ) - -{ - char fname[MAX_PATH_FILENAME+1]; - PJ_GRIDINFO *gilist; - PAFile fp; - char header[160]; - size_t header_size = 0; - - errno = pj_errno = 0; - ctx->last_errno = 0; - -/* -------------------------------------------------------------------- */ -/* Initialize a GRIDINFO with stub info we would use if it */ -/* cannot be loaded. */ -/* -------------------------------------------------------------------- */ - gilist = (PJ_GRIDINFO *) pj_calloc(1, sizeof(PJ_GRIDINFO)); - if (!gilist) { - pj_ctx_set_errno(ctx, ENOMEM); - return nullptr; - } - - gilist->gridname = pj_strdup( gridname ); - if (!gilist->gridname) { - pj_dalloc(gilist); - pj_ctx_set_errno(ctx, ENOMEM); - return nullptr; - } - gilist->filename = nullptr; - gilist->format = "missing"; - gilist->grid_offset = 0; - gilist->ct = nullptr; - gilist->next = nullptr; - -/* -------------------------------------------------------------------- */ -/* Open the file using the usual search rules. */ -/* -------------------------------------------------------------------- */ - strcpy(fname, gridname); - if (!(fp = pj_open_lib(ctx, fname, "rb"))) { - ctx->last_errno = 0; /* don't treat as a persistent error */ - return gilist; - } - - gilist->filename = pj_strdup(fname); - if (!gilist->filename) { - pj_dalloc(gilist->gridname); - pj_dalloc(gilist); - pj_ctx_set_errno(ctx, ENOMEM); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Load a header, to determine the file type. */ -/* -------------------------------------------------------------------- */ - if( (header_size = pj_ctx_fread( ctx, header, 1, - sizeof(header), fp ) ) != sizeof(header) ) - { - /* some files may be smaller that sizeof(header), eg 160, so */ - ctx->last_errno = 0; /* don't treat as a persistent error */ - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "pj_gridinfo_init: short header read of %d bytes", - (int)header_size ); - } - - pj_ctx_fseek( ctx, fp, SEEK_SET, 0 ); - -/* -------------------------------------------------------------------- */ -/* Determine file type. */ -/* -------------------------------------------------------------------- */ - if( header_size >= 144 + 16 - && strncmp(header + 0, "HEADER", 6) == 0 - && strncmp(header + 96, "W GRID", 6) == 0 - && strncmp(header + 144, "TO NAD83 ", 16) == 0 ) - { - pj_gridinfo_init_ntv1( ctx, fp, gilist ); - } - - else if( header_size >= 48 + 7 - && strncmp(header + 0, "NUM_OREC", 8) == 0 - && strncmp(header + 48, "GS_TYPE", 7) == 0 ) - { - pj_gridinfo_init_ntv2( ctx, fp, gilist ); - } - - else if( strlen(gridname) > 4 - && (strcmp(gridname+strlen(gridname)-3,"gtx") == 0 - || strcmp(gridname+strlen(gridname)-3,"GTX") == 0) ) - { - pj_gridinfo_init_gtx( ctx, fp, gilist ); - } - - else if( header_size >= 9 && strncmp(header + 0,"CTABLE V2",9) == 0 ) - { - struct CTABLE *ct = nad_ctable2_init( ctx, fp ); - - gilist->format = "ctable2"; - gilist->ct = ct; - - if (ct == nullptr) - { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "CTABLE V2 ct is NULL."); - } - else - { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "Ctable2 %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", - ct->id, - ct->lim.lam, ct->lim.phi, - ct->ll.lam * RAD_TO_DEG, ct->ll.phi * RAD_TO_DEG, - (ct->ll.lam + (ct->lim.lam-1)*ct->del.lam) * RAD_TO_DEG, - (ct->ll.phi + (ct->lim.phi-1)*ct->del.phi) * RAD_TO_DEG ); - } - } - - else - { - struct CTABLE *ct = nad_ctable_init( ctx, fp ); - if (ct == nullptr) - { - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "CTABLE ct is NULL."); - } else - { - gilist->format = "ctable"; - gilist->ct = ct; - - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "Ctable %s %dx%d: LL=(%.9g,%.9g) UR=(%.9g,%.9g)", - ct->id, - ct->lim.lam, ct->lim.phi, - ct->ll.lam * RAD_TO_DEG, ct->ll.phi * RAD_TO_DEG, - (ct->ll.lam + (ct->lim.lam-1)*ct->del.lam) * RAD_TO_DEG, - (ct->ll.phi + (ct->lim.phi-1)*ct->del.phi) * RAD_TO_DEG ); - } - } - - pj_ctx_fclose(ctx, fp); - - return gilist; -} diff --git a/src/pj_gridlist.cpp b/src/pj_gridlist.cpp deleted file mode 100644 index 169abcb9..00000000 --- a/src/pj_gridlist.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Code to manage the list of currently loaded (cached) PJ_GRIDINFOs - * See pj_gridinfo.c for details of loading individual grids. - * 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include -#include - -#include "projects.h" - -static PJ_GRIDINFO *grid_list = nullptr; -#define PJ_MAX_PATH_LENGTH 1024 - -/************************************************************************/ -/* pj_deallocate_grids() */ -/* */ -/* Deallocate all loaded grids. */ -/************************************************************************/ - -void pj_deallocate_grids() - -{ - while( grid_list != nullptr ) - { - PJ_GRIDINFO *item = grid_list; - grid_list = grid_list->next; - item->next = nullptr; - - pj_gridinfo_free( pj_get_default_ctx(), item ); - } -} - -/************************************************************************/ -/* pj_gridlist_merge_grid() */ -/* */ -/* Find/load the named gridfile and merge it into the */ -/* last_nadgrids_list. */ -/************************************************************************/ - -static int pj_gridlist_merge_gridfile( projCtx ctx, - const char *gridname, - PJ_GRIDINFO ***p_gridlist, - int *p_gridcount, - int *p_gridmax ) - -{ - int got_match=0; - PJ_GRIDINFO *this_grid, *tail = nullptr; - -/* -------------------------------------------------------------------- */ -/* Try to find in the existing list of loaded grids. Add all */ -/* matching grids as with NTv2 we can get many grids from one */ -/* file (one shared gridname). */ -/* -------------------------------------------------------------------- */ - for( this_grid = grid_list; this_grid != nullptr; this_grid = this_grid->next) - { - if( strcmp(this_grid->gridname,gridname) == 0 ) - { - got_match = 1; - - /* don't add to the list if it is invalid. */ - if( this_grid->ct == nullptr ) - return 0; - - /* do we need to grow the list? */ - if( *p_gridcount >= *p_gridmax - 2 ) - { - PJ_GRIDINFO **new_list; - int new_max = *p_gridmax + 20; - - new_list = (PJ_GRIDINFO **) pj_calloc(new_max, sizeof(void *)); - if (!new_list) { - pj_ctx_set_errno( ctx, ENOMEM ); - return 0; - } - if( *p_gridlist != nullptr ) - { - memcpy( new_list, *p_gridlist, - sizeof(void *) * (*p_gridmax) ); - pj_dalloc( *p_gridlist ); - } - - *p_gridlist = new_list; - *p_gridmax = new_max; - } - - /* add to the list */ - (*p_gridlist)[(*p_gridcount)++] = this_grid; - (*p_gridlist)[*p_gridcount] = nullptr; - } - - tail = this_grid; - } - - if( got_match ) - return 1; - -/* -------------------------------------------------------------------- */ -/* Try to load the named grid. */ -/* -------------------------------------------------------------------- */ - this_grid = pj_gridinfo_init( ctx, gridname ); - - if( this_grid == nullptr ) - { - return 0; - } - - if( tail != nullptr ) - tail->next = this_grid; - else - grid_list = this_grid; - -/* -------------------------------------------------------------------- */ -/* Recurse to add the grid now that it is loaded. */ -/* -------------------------------------------------------------------- */ - return pj_gridlist_merge_gridfile( ctx, gridname, p_gridlist, - p_gridcount, p_gridmax ); -} - -/************************************************************************/ -/* pj_gridlist_from_nadgrids() */ -/* */ -/* This functions loads the list of grids corresponding to a */ -/* particular nadgrids string into a list, and returns it. The */ -/* list is kept around till a request is made with a different */ -/* string in order to cut down on the string parsing cost, and */ -/* the cost of building the list of tables each time. */ -/************************************************************************/ - -PJ_GRIDINFO **pj_gridlist_from_nadgrids( projCtx ctx, const char *nadgrids, - int *grid_count) - -{ - const char *s; - PJ_GRIDINFO **gridlist = nullptr; - int grid_max = 0; - - pj_errno = 0; - *grid_count = 0; - - pj_acquire_lock(); - -/* -------------------------------------------------------------------- */ -/* Loop processing names out of nadgrids one at a time. */ -/* -------------------------------------------------------------------- */ - for( s = nadgrids; *s != '\0'; ) - { - size_t end_char; - int required = 1; - char name[PJ_MAX_PATH_LENGTH]; - - if( *s == '@' ) - { - required = 0; - s++; - } - - for( end_char = 0; - s[end_char] != '\0' && s[end_char] != ','; - end_char++ ) {} - - if( end_char >= sizeof(name) ) - { - pj_dalloc( gridlist ); - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return nullptr; - } - - strncpy( name, s, end_char ); - name[end_char] = '\0'; - - s += end_char; - if( *s == ',' ) - s++; - - if( !pj_gridlist_merge_gridfile( ctx, name, &gridlist, grid_count, - &grid_max) - && required ) - { - pj_dalloc( gridlist ); - pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); - pj_release_lock(); - return nullptr; - } - else - pj_errno = 0; - } - - pj_release_lock(); - - return gridlist; -} diff --git a/src/pj_init.cpp b/src/pj_init.cpp deleted file mode 100644 index 5710031c..00000000 --- a/src/pj_init.cpp +++ /dev/null @@ -1,888 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Initialize projection object from string definition. Includes - * pj_init(), pj_init_plus() and pj_free() function. - * Author: Gerald Evenden, Frank Warmerdam - * - ****************************************************************************** - * Copyright (c) 1995, Gerald Evenden - * Copyright (c) 2002, 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include -#include -#include -#include -#include - -#include "geodesic.h" -#include "proj.h" -#include "proj_internal.h" -#include "proj_math.h" -#include "projects.h" - - -/**************************************************************************************/ -static paralist *string_to_paralist (PJ_CONTEXT *ctx, char *definition) { -/*************************************************************************************** - Convert a string (presumably originating from get_init_string) to a paralist. -***************************************************************************************/ - char *c = definition; - paralist *first = nullptr, *next = nullptr; - - while (*c) { - /* Find start of next substring */ - while (isspace (*c)) - c++; - - /* Keep a handle to the start of the list, so we have something to return */ - if (nullptr==first) - first = next = pj_mkparam_ws (c); - else - next = next->next = pj_mkparam_ws (c); - if (nullptr==next) { - pj_dealloc_params (ctx, first, ENOMEM); - return nullptr; - } - - /* And skip to the end of the substring */ - while ((!isspace(*c)) && 0!=*c) - c++; - } - - if( next == nullptr ) - return nullptr; - - /* Terminate list and return */ - next->next = nullptr; - return first; -} - - - -/**************************************************************************************/ -static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { -/*************************************************************************************** - Read a section of an init file. Return its contents as a plain character string. - It is the duty of the caller to free the memory allocated for the string. -***************************************************************************************/ -#define MAX_LINE_LENGTH 1000 - size_t current_buffer_size = 5 * (MAX_LINE_LENGTH + 1); - char *fname, *section; - const char *key; - char *buffer = nullptr; - char *line = nullptr; - PAFile fid; - size_t n; - - - line = static_cast(pj_malloc (MAX_LINE_LENGTH + 1)); - if (nullptr==line) - return nullptr; - - fname = static_cast(pj_malloc (MAX_PATH_FILENAME+ID_TAG_MAX+3)); - if (nullptr==fname) { - pj_dealloc (line); - return nullptr; - } - - /* Support "init=file:section", "+init=file:section", and "file:section" format */ - key = strstr (name, "init="); - if (nullptr==key) - key = name; - else - key += 5; - if (MAX_PATH_FILENAME + ID_TAG_MAX + 2 < strlen (key)) { - pj_dealloc (fname); - pj_dealloc (line); - return nullptr; - } - memmove (fname, key, strlen (key) + 1); - - /* Locate the name of the section we search for */ - section = strrchr(fname, ':'); - if (nullptr==section) { - proj_context_errno_set (ctx, PJD_ERR_NO_COLON_IN_INIT_STRING); - pj_dealloc (fname); - pj_dealloc (line); - return nullptr; - } - *section = 0; - section++; - n = strlen (section); - pj_log (ctx, PJ_LOG_TRACE, - "get_init_string: searching for section [%s] in init file [%s]", - section, fname); - - fid = pj_open_lib (ctx, fname, "rt"); - if (nullptr==fid) { - pj_dealloc (fname); - pj_dealloc (line); - proj_context_errno_set (ctx, PJD_ERR_NO_OPTION_IN_INIT_FILE); - return nullptr; - } - - /* Search for section in init file */ - for (;;) { - - /* End of file? */ - if (nullptr==pj_ctx_fgets (ctx, line, MAX_LINE_LENGTH, fid)) { - pj_dealloc (buffer); - pj_dealloc (fname); - pj_dealloc (line); - pj_ctx_fclose (ctx, fid); - proj_context_errno_set (ctx, PJD_ERR_NO_OPTION_IN_INIT_FILE); - return nullptr; - } - - /* At start of right section? */ - pj_chomp (line); - if ('<'!=line[0]) - continue; - if (strlen (line) < n + 2) - continue; - if (line[n + 1] != '>') - continue; - if (0==strncmp (line + 1, section, n)) - break; - } - - /* We're at the first line of the right section - copy line to buffer */ - buffer = static_cast(pj_malloc (current_buffer_size)); - if (nullptr==buffer) { - pj_dealloc (fname); - pj_dealloc (line); - pj_ctx_fclose (ctx, fid); - return nullptr; - } - - /* Skip the "
" indicator, and copy the rest of the line over */ - strcpy (buffer, line + strlen (section) + 2); - - /* Copy the remaining lines of the section to buffer */ - for (;;) { - char *end_i_cator; - size_t next_length, buffer_length; - - /* Did the section end somewhere in the most recently read line? */ - end_i_cator = strchr (buffer, '<'); - if (end_i_cator) { - *end_i_cator = 0; - break; - } - - /* End of file? - done! */ - if (nullptr==pj_ctx_fgets (ctx, line, MAX_LINE_LENGTH, fid)) - break; - - /* Otherwise, handle the line. It MAY be the start of the next section, */ - /* but that will be handled at the start of next trip through the loop */ - buffer_length = strlen (buffer); - pj_chomp (line); /* Remove '#' style comments */ - next_length = strlen (line) + buffer_length + 2; - if (next_length > current_buffer_size) { - char *b = static_cast(pj_malloc (2 * current_buffer_size)); - if (nullptr==b) { - pj_dealloc (buffer); - buffer = nullptr; - break; - } - strcpy (b, buffer); - current_buffer_size *= 2; - pj_dealloc (buffer); - buffer = b; - } - buffer[buffer_length] = ' '; - strcpy (buffer + buffer_length + 1, line); - } - - pj_ctx_fclose (ctx, fid); - pj_dealloc (fname); - pj_dealloc (line); - if (nullptr==buffer) - return nullptr; - pj_shrink (buffer); - pj_log (ctx, PJ_LOG_TRACE, "key=%s, value: [%s]", key, buffer); - return buffer; -} - - - -/************************************************************************/ -static paralist *get_init(PJ_CONTEXT *ctx, const char *key, int allow_init_epsg) { -/************************************************************************* -Expand key from buffer or (if not in buffer) from init file -*************************************************************************/ - const char *xkey; - char *definition = nullptr; - paralist *init_items = nullptr; - - /* support "init=file:section", "+init=file:section", and "file:section" format */ - xkey = strstr (key, "init="); - if (nullptr==xkey) - xkey = key; - else - xkey += 5; - pj_log (ctx, PJ_LOG_TRACE, "get_init: searching cache for key: [%s]", xkey); - - /* Is file/key pair already in cache? */ - init_items = pj_search_initcache (xkey); - if (init_items) - return init_items; - - if( (strncmp(xkey, "epsg:", 5) == 0 || strncmp(xkey, "IGNF:", 5) == 0) ) { - char unused[256]; - char initname[5]; - int exists; - - memcpy(initname, xkey, 4); - initname[4] = 0; - - if( strncmp(xkey, "epsg:", 5) == 0 ) { - exists = ctx->epsg_file_exists; - if( exists < 0 ) { - exists = pj_find_file(ctx, initname, unused, sizeof(unused)); - ctx->epsg_file_exists = exists; - } - } else { - exists = pj_find_file(ctx, initname, unused, sizeof(unused)); - } - - if( !exists ) { - const char* const optionsProj4Mode[] = { "USE_PROJ4_INIT_RULES=YES", nullptr }; - char szInitStr[7 + 64]; - PJ_OBJ* src; - const char* proj_string; - - pj_ctx_set_errno( ctx, 0 ); - - if( !allow_init_epsg ) { - pj_log (ctx, PJ_LOG_TRACE, "%s expansion disallowed", xkey); - return nullptr; - } - if( strlen(xkey) > 64 ) { - return nullptr; - } - strcpy(szInitStr, "+init="); - strcat(szInitStr, xkey); - - src = proj_obj_create_from_user_input(ctx, szInitStr, optionsProj4Mode); - if( !src ) { - return nullptr; - } - - proj_string = proj_obj_as_proj_string(ctx, src, PJ_PROJ_4, nullptr); - if( !proj_string ) { - proj_obj_destroy(src); - return nullptr; - } - definition = (char*)calloc(1, strlen(proj_string)+1); - if( definition ) { - strcpy(definition, proj_string); - } - - proj_obj_destroy(src); - } - } - - if( !definition ) { - /* If not, we must read it from file */ - pj_log (ctx, PJ_LOG_TRACE, - "get_init: searching on in init files for [%s]", xkey); - definition = get_init_string (ctx, xkey); - } - - if (nullptr==definition) - return nullptr; - init_items = string_to_paralist (ctx, definition); - if (init_items) - pj_log (ctx, PJ_LOG_TRACE, "get_init: got [%s], paralist[0,1]: [%s,%s]", - definition, - init_items->param, - init_items->next ? init_items->next->param : "(empty)"); - pj_dealloc (definition); - if (nullptr==init_items) - return nullptr; - - /* We found it in file - now insert into the cache, before returning */ - pj_insert_initcache (xkey, init_items); - return init_items; -} - - - -static paralist *append_defaults_to_paralist (PJ_CONTEXT *ctx, paralist *start, const char *key, int allow_init_epsg) { - paralist *defaults, *last = nullptr; - char keystring[ID_TAG_MAX + 20]; - paralist *next, *proj; - int err; - - if (nullptr==start) - return nullptr; - - if (strlen(key) > ID_TAG_MAX) - return nullptr; - - /* Set defaults, unless inhibited (either explicitly through a "no_defs" token */ - /* or implicitly, because we are initializing a pipeline) */ - if (pj_param_exists (start, "no_defs")) - return start; - proj = pj_param_exists (start, "proj"); - if (nullptr==proj) - return start; - if (strlen (proj->param) < 6) - return start; - if (0==strcmp ("pipeline", proj->param + 5)) - return start; - - err = pj_ctx_get_errno (ctx); - pj_ctx_set_errno (ctx, 0); - - /* Locate end of start-list */ - for (last = start; last->next; last = last->next); - - strcpy (keystring, "proj_def.dat:"); - strcat (keystring, key); - defaults = get_init (ctx, keystring, allow_init_epsg); - - /* Defaults are optional - so we don't care if we cannot open the file */ - pj_ctx_set_errno (ctx, err); - - if (!defaults) - return last; - - /* Loop over all default items */ - for (next = defaults; next; next = next->next) { - - /* Don't override existing parameter value of same name */ - if (pj_param_exists (start, next->param)) - continue; - - /* Don't default ellipse if datum, ellps or any ellipsoid information is set */ - if (0==strncmp(next->param,"ellps=", 6)) { - if (pj_param_exists (start, "datum")) continue; - if (pj_param_exists (start, "ellps")) continue; - if (pj_param_exists (start, "a")) continue; - if (pj_param_exists (start, "b")) continue; - if (pj_param_exists (start, "rf")) continue; - if (pj_param_exists (start, "f")) continue; - if (pj_param_exists (start, "e")) continue; - if (pj_param_exists (start, "es")) continue; - } - - /* If we're here, it's OK to append the current default item */ - last = last->next = pj_mkparam(next->param); - } - last->next = nullptr; - - pj_dealloc_params (ctx, defaults, 0); - return last; -} - -/*****************************************************************************/ -static paralist *pj_expand_init_internal(PJ_CONTEXT *ctx, paralist *init, int allow_init_epsg) { -/****************************************************************************** -Append expansion of to the paralist . The expansion is appended, -rather than inserted at 's place, since may contain -overrides to the expansion. These must take precedence, and hence come first -in the expanded list. - -Consider e.g. the key 'foo:bar' which (hypothetically) expands to 'proj=utm -zone=32 ellps=GRS80', i.e. a UTM projection on the GRS80 ellipsoid. - -The expression 'init=foo:bar ellps=intl' will then expand to: - - 'init=foo:bar ellps=intl proj=utm zone=32 ellps=GRS80', - -where 'ellps=intl' precedes 'ellps=GRS80', and hence takes precedence, -turning the expansion into an UTM projection on the Hayford ellipsoid. - -Note that 'init=foo:bar' stays in the list. It is ignored after expansion. - -******************************************************************************/ - paralist *last; - paralist *expn; - - /* Nowhere to start? */ - if (nullptr==init) - return nullptr; - - expn = get_init(ctx, init->param, allow_init_epsg); - - /* Nothing in expansion? */ - if (nullptr==expn) - return nullptr; - - /* Locate the end of the list */ - for (last = init; last && last->next; last = last->next); - - /* Then append and return */ - last->next = expn; - return init; -} - -paralist *pj_expand_init(PJ_CONTEXT *ctx, paralist *init) { - return pj_expand_init_internal(ctx, init, TRUE); -} - - -/************************************************************************/ -/* pj_init_plus() */ -/* */ -/* Same as pj_init() except it takes one argument string with */ -/* individual arguments preceded by '+', such as "+proj=utm */ -/* +zone=11 +ellps=WGS84". */ -/************************************************************************/ - -PJ * -pj_init_plus( const char *definition ) - -{ - return pj_init_plus_ctx( pj_get_default_ctx(), definition ); -} - -PJ * -pj_init_plus_ctx( projCtx ctx, const char *definition ) -{ -#define MAX_ARG 200 - char *argv[MAX_ARG]; - char *defn_copy; - int argc = 0, i, blank_count = 0; - PJ *result = nullptr; - - /* make a copy that we can manipulate */ - defn_copy = (char *) pj_malloc( strlen(definition)+1 ); - if (!defn_copy) - return nullptr; - strcpy( defn_copy, definition ); - - /* split into arguments based on '+' and trim white space */ - - for( i = 0; defn_copy[i] != '\0'; i++ ) - { - switch( defn_copy[i] ) - { - case '+': - if( i == 0 || defn_copy[i-1] == '\0' || blank_count > 0 ) - { - /* trim trailing spaces from the previous param */ - if( blank_count > 0 ) - { - defn_copy[i - blank_count] = '\0'; - blank_count = 0; - } - - if( argc+1 == MAX_ARG ) - { - pj_dalloc( defn_copy ); - pj_ctx_set_errno( ctx, PJD_ERR_UNPARSEABLE_CS_DEF ); - return nullptr; - } - - argv[argc++] = defn_copy + i + 1; - } - break; - - case ' ': - case '\t': - case '\n': - /* trim leading spaces from the current param */ - if( i == 0 || defn_copy[i-1] == '\0' || argc == 0 || argv[argc-1] == defn_copy + i ) - defn_copy[i] = '\0'; - else - blank_count++; - break; - - default: - /* reset blank_count */ - blank_count = 0; - } - } - /* trim trailing spaces from the last param */ - defn_copy[i - blank_count] = '\0'; - - /* perform actual initialization */ - result = pj_init_ctx( ctx, argc, argv ); - - pj_dalloc( defn_copy ); - return result; -} - - - -/************************************************************************/ -/* pj_init() */ -/* */ -/* Main entry point for initialing a PJ projections */ -/* definition. Note that the projection specific function is */ -/* called to do the initial allocation so it can be created */ -/* large enough to hold projection specific parameters. */ -/************************************************************************/ - -PJ * -pj_init(int argc, char **argv) { - return pj_init_ctx( pj_get_default_ctx(), argc, argv ); -} - - -static PJ_CONSTRUCTOR locate_constructor (const char *name) { - int i; - const char *s; - const PJ_OPERATIONS *operations; - operations = proj_list_operations(); - for (i = 0; (s = operations[i].id) && strcmp(name, s) ; ++i) ; - if (nullptr==s) - return nullptr; - return (PJ_CONSTRUCTOR) operations[i].proj; -} - - -PJ * -pj_init_ctx(projCtx ctx, int argc, char **argv) { - /* Legacy interface: allow init=epsg:XXXX syntax by default */ - int allow_init_epsg = proj_context_get_use_proj4_init_rules(ctx, TRUE); - return pj_init_ctx_with_allow_init_epsg(ctx, argc, argv, allow_init_epsg); -} - - -PJ * -pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_init_epsg) { - const char *s; - char *name; - PJ_CONSTRUCTOR proj; - paralist *curr, *init, *start; - int i; - int err; - PJ *PIN = nullptr; - int n_pipelines = 0; - int n_inits = 0; - const PJ_UNITS *units; - const PJ_PRIME_MERIDIANS *prime_meridians; - - if (nullptr==ctx) - ctx = pj_get_default_ctx (); - - ctx->last_errno = 0; - - if (argc <= 0) { - pj_ctx_set_errno (ctx, PJD_ERR_NO_ARGS); - return nullptr; - } - - /* count occurrences of pipelines and inits */ - for (i = 0; i < argc; ++i) { - if (!strcmp (argv[i], "+proj=pipeline") || !strcmp(argv[i], "proj=pipeline") ) - n_pipelines++; - if (!strncmp (argv[i], "+init=", 6) || !strncmp(argv[i], "init=", 5)) - n_inits++; - } - - /* can't have nested pipelines directly */ - if (n_pipelines > 1) { - pj_ctx_set_errno (ctx, PJD_ERR_MALFORMED_PIPELINE); - return nullptr; - } - - /* don't allow more than one +init in non-pipeline operations */ - if (n_pipelines == 0 && n_inits > 1) { - pj_ctx_set_errno (ctx, PJD_ERR_TOO_MANY_INITS); - return nullptr; - } - - - /* put arguments into internal linked list */ - start = curr = pj_mkparam(argv[0]); - if (!curr) { - pj_dealloc_params (ctx, start, ENOMEM); - return nullptr; - } - - for (i = 1; i < argc; ++i) { - curr->next = pj_mkparam(argv[i]); - if (!curr->next) { - pj_dealloc_params (ctx, start, ENOMEM); - return nullptr; - } - curr = curr->next; - } - - - /* Only expand '+init's in non-pipeline operations. '+init's in pipelines are */ - /* expanded in the individual pipeline steps during pipeline initialization. */ - /* Potentially this leads to many nested pipelines, which shouldn't be a */ - /* problem when '+init's are expanded as late as possible. */ - init = pj_param_exists (start, "init"); - if (init && n_pipelines == 0) { - init = pj_expand_init_internal (ctx, init, allow_init_epsg); - if (!init) { - pj_dealloc_params (ctx, start, PJD_ERR_NO_ARGS); - return nullptr; - } - } - if (ctx->last_errno) { - pj_dealloc_params (ctx, start, ctx->last_errno); - return nullptr; - } - - /* Find projection selection */ - curr = pj_param_exists (start, "proj"); - if (nullptr==curr) { - pj_dealloc_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); - return nullptr; - } - name = curr->param; - if (strlen (name) < 6) { - pj_dealloc_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); - return nullptr; - } - name += 5; - - proj = locate_constructor (name); - if (nullptr==proj) { - pj_dealloc_params (ctx, start, PJD_ERR_UNKNOWN_PROJECTION_ID); - return nullptr; - } - - - /* Append general and projection specific defaults to the definition list */ - append_defaults_to_paralist (ctx, start, "general", allow_init_epsg); - append_defaults_to_paralist (ctx, start, name, allow_init_epsg); - - - /* Allocate projection structure */ - PIN = proj(nullptr); - if (nullptr==PIN) { - pj_dealloc_params (ctx, start, ENOMEM); - return nullptr; - } - - - PIN->ctx = ctx; - PIN->params = start; - PIN->is_latlong = 0; - PIN->is_geocent = 0; - PIN->is_long_wrap_set = 0; - PIN->long_wrap_center = 0.0; - strcpy( PIN->axis, "enu" ); - - PIN->gridlist = nullptr; - PIN->gridlist_count = 0; - - PIN->vgridlist_geoid = nullptr; - PIN->vgridlist_geoid_count = 0; - - /* Set datum parameters. Similarly to +init parameters we want to expand */ - /* +datum parameters as late as possible when dealing with pipelines. */ - /* otherwise only the first occurrence of +datum will be expanded and that */ - if (n_pipelines == 0) { - if (pj_datum_set(ctx, start, PIN)) - return pj_default_destructor (PIN, proj_errno(PIN)); - } - - err = pj_ellipsoid (PIN); - - if (err) { - /* Didn't get an ellps, but doesn't need one: Get a free WGS84 */ - if (PIN->need_ellps) { - pj_log (ctx, PJ_LOG_DEBUG_MINOR, "pj_init_ctx: Must specify ellipsoid or sphere"); - return pj_default_destructor (PIN, proj_errno(PIN)); - } - else { - if (PJD_ERR_MAJOR_AXIS_NOT_GIVEN==proj_errno (PIN)) - proj_errno_reset (PIN); - PIN->f = 1.0/298.257223563; - PIN->a_orig = PIN->a = 6378137.0; - PIN->es_orig = PIN->es = PIN->f*(2-PIN->f); - } - } - PIN->a_orig = PIN->a; - PIN->es_orig = PIN->es; - if (pj_calc_ellipsoid_params (PIN, PIN->a, PIN->es)) - return pj_default_destructor (PIN, PJD_ERR_ECCENTRICITY_IS_ONE); - - /* Now that we have ellipse information check for WGS84 datum */ - if( PIN->datum_type == PJD_3PARAM - && PIN->datum_params[0] == 0.0 - && PIN->datum_params[1] == 0.0 - && PIN->datum_params[2] == 0.0 - && PIN->a == 6378137.0 - && ABS(PIN->es - 0.006694379990) < 0.000000000050 )/*WGS84/GRS80*/ - { - PIN->datum_type = PJD_WGS84; - } - - /* Set PIN->geoc coordinate system */ - PIN->geoc = (PIN->es != 0.0 && pj_param(ctx, start, "bgeoc").i); - - /* Over-ranging flag */ - PIN->over = pj_param(ctx, start, "bover").i; - - /* Vertical datum geoid grids */ - PIN->has_geoid_vgrids = pj_param(ctx, start, "tgeoidgrids").i; - if( PIN->has_geoid_vgrids ) /* we need to mark it as used. */ - pj_param(ctx, start, "sgeoidgrids"); - - /* Longitude center for wrapping */ - PIN->is_long_wrap_set = pj_param(ctx, start, "tlon_wrap").i; - if (PIN->is_long_wrap_set) { - PIN->long_wrap_center = pj_param(ctx, start, "rlon_wrap").f; - /* Don't accept excessive values otherwise we might perform badly */ - /* when correcting longitudes around it */ - /* The test is written this way to error on long_wrap_center "=" NaN */ - if( !(fabs(PIN->long_wrap_center) < 10 * M_TWOPI) ) - return pj_default_destructor (PIN, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); - } - - /* Axis orientation */ - if( (pj_param(ctx, start,"saxis").s) != nullptr ) - { - const char *axis_legal = "ewnsud"; - const char *axis_arg = pj_param(ctx, start,"saxis").s; - if( strlen(axis_arg) != 3 ) - return pj_default_destructor (PIN, PJD_ERR_AXIS); - - if( strchr( axis_legal, axis_arg[0] ) == nullptr - || strchr( axis_legal, axis_arg[1] ) == nullptr - || strchr( axis_legal, axis_arg[2] ) == nullptr) - return pj_default_destructor (PIN, PJD_ERR_AXIS); - - /* TODO: it would be nice to validate we don't have on axis repeated */ - strcpy( PIN->axis, axis_arg ); - } - - /* Central meridian */ - PIN->lam0=pj_param(ctx, start, "rlon_0").f; - - /* Central latitude */ - PIN->phi0 = pj_param(ctx, start, "rlat_0").f; - - /* False easting and northing */ - PIN->x0 = pj_param(ctx, start, "dx_0").f; - PIN->y0 = pj_param(ctx, start, "dy_0").f; - PIN->z0 = pj_param(ctx, start, "dz_0").f; - PIN->t0 = pj_param(ctx, start, "dt_0").f; - - /* General scaling factor */ - if (pj_param(ctx, start, "tk_0").i) - PIN->k0 = pj_param(ctx, start, "dk_0").f; - else if (pj_param(ctx, start, "tk").i) - PIN->k0 = pj_param(ctx, start, "dk").f; - else - PIN->k0 = 1.; - if (PIN->k0 <= 0.) - return pj_default_destructor (PIN, PJD_ERR_K_LESS_THAN_ZERO); - - /* Set units */ - units = proj_list_units(); - s = nullptr; - if ((name = pj_param(ctx, start, "sunits").s) != nullptr) { - for (i = 0; (s = units[i].id) && strcmp(name, s) ; ++i) ; - if (!s) - return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_UNIT_ID); - s = units[i].to_meter; - } - if (s || (s = pj_param(ctx, start, "sto_meter").s)) { - double factor; - int ratio = 0; - - /* ratio number? */ - if (strlen (s) > 1 && s[0] == '1' && s[1]=='/') { - ratio = 1; - s += 2; - } - - factor = pj_strtod(s, nullptr); - if ((factor <= 0.0) || (1/factor==0)) - return pj_default_destructor (PIN, PJD_ERR_UNIT_FACTOR_LESS_THAN_0); - - PIN->to_meter = ratio? 1 / factor: factor; - PIN->fr_meter = 1 / PIN->to_meter; - - } else - PIN->to_meter = PIN->fr_meter = 1.; - - /* Set vertical units */ - s = nullptr; - if ((name = pj_param(ctx, start, "svunits").s) != nullptr) { - for (i = 0; (s = units[i].id) && strcmp(name, s) ; ++i) ; - if (!s) - return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_UNIT_ID); - s = units[i].to_meter; - } - if (s || (s = pj_param(ctx, start, "svto_meter").s)) { - PIN->vto_meter = pj_strtod(s, nullptr); - if (*s == '/') /* ratio number */ - PIN->vto_meter /= pj_strtod(++s, nullptr); - if (PIN->vto_meter <= 0.0) - return pj_default_destructor (PIN, PJD_ERR_UNIT_FACTOR_LESS_THAN_0); - PIN->vfr_meter = 1. / PIN->vto_meter; - } else { - PIN->vto_meter = PIN->to_meter; - PIN->vfr_meter = PIN->fr_meter; - } - - /* Prime meridian */ - prime_meridians = proj_list_prime_meridians(); - s = nullptr; - if ((name = pj_param(ctx, start, "spm").s) != nullptr) { - const char *value = nullptr; - char *next_str = nullptr; - - for (i = 0; prime_meridians[i].id != nullptr; ++i ) - { - if( strcmp(name,prime_meridians[i].id) == 0 ) - { - value = prime_meridians[i].defn; - break; - } - } - - if( value == nullptr - && (dmstor_ctx(ctx,name,&next_str) != 0.0 || *name == '0') - && *next_str == '\0' ) - value = name; - - if (!value) - return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_PRIME_MERIDIAN); - PIN->from_greenwich = dmstor_ctx(ctx,value,nullptr); - } - else - PIN->from_greenwich = 0.0; - - /* Private object for the geodesic functions */ - PIN->geod = static_cast(pj_calloc (1, sizeof (struct geod_geodesic))); - if (nullptr==PIN->geod) - return pj_default_destructor (PIN, ENOMEM); - geod_init(PIN->geod, PIN->a, (1 - sqrt (1 - PIN->es))); - - /* Projection specific initialization */ - err = proj_errno_reset (PIN); - PIN = proj(PIN); - if (proj_errno (PIN)) { - pj_free(PIN); - return nullptr; - } - proj_errno_restore (PIN, err); - return PIN; -} diff --git a/src/pj_initcache.cpp b/src/pj_initcache.cpp deleted file mode 100644 index 052a016c..00000000 --- a/src/pj_initcache.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: init file definition cache. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2009, 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. - *****************************************************************************/ - -#include - -#include "projects.h" - -static int cache_count = 0; -static int cache_alloc = 0; -static char **cache_key = nullptr; -static paralist **cache_paralist = nullptr; - -/************************************************************************/ -/* pj_clone_paralist() */ -/* */ -/* Allocate a copy of a parameter list. */ -/************************************************************************/ - -paralist *pj_clone_paralist( const paralist *list) -{ - paralist *list_copy = nullptr, *next_copy = nullptr; - - for( ; list != nullptr; list = list->next ) - { - paralist *newitem = (paralist *) - pj_malloc(sizeof(paralist) + strlen(list->param)); - - newitem->used = 0; - newitem->next = nullptr; - strcpy( newitem->param, list->param ); - - if( list_copy == nullptr ) - list_copy = newitem; - else - next_copy->next = newitem; - - next_copy = newitem; - } - - return list_copy; -} - -/************************************************************************/ -/* pj_clear_initcache() */ -/* */ -/* Clear out all memory held in the init file cache. */ -/************************************************************************/ - -void pj_clear_initcache() -{ - if( cache_alloc > 0 ) - { - int i; - - pj_acquire_lock(); - - for( i = 0; i < cache_count; i++ ) - { - paralist *n, *t = cache_paralist[i]; - - pj_dalloc( cache_key[i] ); - - /* free parameter list elements */ - for (; t != nullptr; t = n) { - n = t->next; - pj_dalloc(t); - } - } - - pj_dalloc( cache_key ); - pj_dalloc( cache_paralist ); - cache_count = 0; - cache_alloc= 0; - cache_key = nullptr; - cache_paralist = nullptr; - - pj_release_lock(); - } -} - -/************************************************************************/ -/* pj_search_initcache() */ -/* */ -/* Search for a matching definition in the init cache. */ -/************************************************************************/ - -paralist *pj_search_initcache( const char *filekey ) - -{ - int i; - paralist *result = nullptr; - - pj_acquire_lock(); - - for( i = 0; result == nullptr && i < cache_count; i++) - { - if( strcmp(filekey,cache_key[i]) == 0 ) - { - result = pj_clone_paralist( cache_paralist[i] ); - } - } - - pj_release_lock(); - - return result; -} - -/************************************************************************/ -/* pj_insert_initcache() */ -/* */ -/* Insert a paralist definition in the init file cache. */ -/************************************************************************/ - -void pj_insert_initcache( const char *filekey, const paralist *list ) - -{ - pj_acquire_lock(); - - /* - ** Grow list if required. - */ - if( cache_count == cache_alloc ) - { - char **cache_key_new; - paralist **cache_paralist_new; - - cache_alloc = cache_alloc * 2 + 15; - - cache_key_new = (char **) pj_malloc(sizeof(char*) * cache_alloc); - if( cache_key && cache_count ) - { - memcpy( cache_key_new, cache_key, sizeof(char*) * cache_count); - } - pj_dalloc( cache_key ); - cache_key = cache_key_new; - - cache_paralist_new = (paralist **) - pj_malloc(sizeof(paralist*) * cache_alloc); - if( cache_paralist && cache_count ) - { - memcpy( cache_paralist_new, cache_paralist, - sizeof(paralist*) * cache_count ); - } - pj_dalloc( cache_paralist ); - cache_paralist = cache_paralist_new; - } - - /* - ** Duplicate the filekey and paralist, and insert in cache. - */ - cache_key[cache_count] = (char *) pj_malloc(strlen(filekey)+1); - strcpy( cache_key[cache_count], filekey ); - - cache_paralist[cache_count] = pj_clone_paralist( list ); - - cache_count++; - - pj_release_lock(); -} - diff --git a/src/pj_internal.cpp b/src/pj_internal.cpp deleted file mode 100644 index 3f3d191e..00000000 --- a/src/pj_internal.cpp +++ /dev/null @@ -1,445 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: This is primarily material originating from pj_obs_api.c - * (now proj_4D_api.c), that does not fit into the API - * category. Hence this pile of tubings and fittings for - * PROJ.4 internal plumbing. - * - * Author: Thomas Knudsen, thokn@sdfe.dk, 2017-07-05 - * - ****************************************************************************** - * Copyright (c) 2016, 2017, 2018, Thomas Knudsen/SDFE - * - * 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. - *****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include "geodesic.h" -#include "proj_internal.h" -#include "projects.h" - - -enum pj_io_units pj_left (PJ *P) { - enum pj_io_units u = P->inverted? P->right: P->left; - if (u==PJ_IO_UNITS_CLASSIC) - return PJ_IO_UNITS_PROJECTED; - return u; -} - -enum pj_io_units pj_right (PJ *P) { - enum pj_io_units u = P->inverted? P->left: P->right; - if (u==PJ_IO_UNITS_CLASSIC) - return PJ_IO_UNITS_PROJECTED; - return u; -} - - -/* Work around non-constness of MSVC HUGE_VAL by providing functions rather than constants */ -PJ_COORD proj_coord_error (void) { - PJ_COORD c; - c.v[0] = c.v[1] = c.v[2] = c.v[3] = HUGE_VAL; - return c; -} - - - -/**************************************************************************************/ -PJ_COORD pj_approx_2D_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coo) { -/*************************************************************************************** -Behave mostly as proj_trans, but attempt to use 2D interfaces only. -Used in gie.c, to enforce testing 2D code, and by PJ_pipeline.c to implement -chained calls starting out with a call to its 2D interface. -***************************************************************************************/ - if (nullptr==P) - return coo; - if (P->inverted) - direction = static_cast(-direction); - switch (direction) { - case PJ_FWD: - coo.xy = pj_fwd (coo.lp, P); - return coo; - case PJ_INV: - coo.lp = pj_inv (coo.xy, P); - return coo; - case PJ_IDENT: - return coo; - default: - break; - } - proj_errno_set (P, EINVAL); - return proj_coord_error (); -} - - -/**************************************************************************************/ -PJ_COORD pj_approx_3D_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coo) { -/*************************************************************************************** -Companion to pj_approx_2D_trans. - -Behave mostly as proj_trans, but attempt to use 3D interfaces only. -Used in gie.c, to enforce testing 3D code, and by PJ_pipeline.c to implement -chained calls starting out with a call to its 3D interface. -***************************************************************************************/ - if (nullptr==P) - return coo; - if (P->inverted) - direction = static_cast(-direction); - switch (direction) { - case PJ_FWD: - coo.xyz = pj_fwd3d (coo.lpz, P); - return coo; - case PJ_INV: - coo.lpz = pj_inv3d (coo.xyz, P); - return coo; - case PJ_IDENT: - return coo; - default: - break; - } - proj_errno_set (P, EINVAL); - return proj_coord_error (); -} - -/**************************************************************************************/ -int pj_has_inverse(PJ *P) { -/*************************************************************************************** -Check if a a PJ has an inverse. -***************************************************************************************/ - return ( (P->inverted && (P->fwd || P->fwd3d || P->fwd4d) ) || - ( P->inv || P->inv3d || P->inv4d) ); -} - - -/* Move P to a new context - or to the default context if 0 is specified */ -void proj_context_set (PJ *P, PJ_CONTEXT *ctx) { - if (nullptr==ctx) - ctx = pj_get_default_ctx (); - pj_set_ctx (P, ctx); -} - - -void proj_context_inherit (PJ *parent, PJ *child) { - if (nullptr==parent) - pj_set_ctx (child, pj_get_default_ctx()); - else - pj_set_ctx (child, pj_get_ctx(parent)); -} - - - -/*****************************************************************************/ -char *pj_chomp (char *c) { -/****************************************************************************** -Strip pre- and postfix whitespace. Inline comments (indicated by '#') are -considered whitespace. -******************************************************************************/ - size_t i, n; - char *comment; - char *start = c; - - if (nullptr==c) - return nullptr; - - comment = strchr (c, '#'); - if (comment) - *comment = 0; - - n = strlen (c); - if (0==n) - return c; - - /* Eliminate postfix whitespace */ - for (i = n - 1; (i > 0) && (isspace (c[i]) || ';'==c[i]); i--) - c[i] = 0; - - /* Find start of non-whitespace */ - while (0 != *start && (';'==*start || isspace (*start))) - start++; - - n = strlen (start); - if (0==n) { - c[0] = 0; - return c; - } - - memmove (c, start, n + 1); - return c; -} - - - -/*****************************************************************************/ -char *pj_shrink (char *c) { -/****************************************************************************** -Collapse repeated whitespace. Remove '+' and ';'. Make ',' and '=' greedy, -consuming their surrounding whitespace. -******************************************************************************/ - size_t i, j, n; - - /* Flag showing that a whitespace (ws) has been written after last non-ws */ - size_t ws; - - if (nullptr==c) - return nullptr; - - pj_chomp (c); - n = strlen (c); - - /* First collapse repeated whitespace (including +/;) */ - i = 0; - ws = 0; - for (j = 0; j < n; j++) { - - /* Eliminate prefix '+', only if preceded by whitespace */ - /* (i.e. keep it in 1.23e+08) */ - if ((i > 0) && ('+'==c[j]) && ws) - c[j] = ' '; - if ((i==0) && ('+'==c[j])) - c[j] = ' '; - - if (isspace (c[j]) || ';'==c[j]) { - if (0==ws && (i > 0)) - c[i++] = ' '; - ws = 1; - continue; - } - else { - ws = 0; - c[i++] = c[j]; - } - } - c[i] = 0; - n = strlen(c); - - /* Then make ',' and '=' greedy */ - i = 0; - for (j = 0; j < n; j++) { - if (i==0) { - c[i++] = c[j]; - continue; - } - - /* Skip space before '='/',' */ - if ('='==c[j] || ','==c[j]) { - if (c[i - 1]==' ') - c[i - 1] = c[j]; - else - c[i++] = c[j]; - continue; - } - - if (' '==c[j] && ('='==c[i - 1] || ','==c[i - 1]) ) - continue; - - c[i++] = c[j]; - } - c[i] = 0; - return c; -} - - - -/*****************************************************************************/ -size_t pj_trim_argc (char *args) { -/****************************************************************************** -Trim all unnecessary whitespace (and non-essential syntactic tokens) from the -argument string, args, and count its number of elements. -******************************************************************************/ - size_t i, m, n; - pj_shrink (args); - n = strlen (args); - if (n==0) - return 0; - for (i = m = 0; i < n; i++) { - if (' '==args[i]) { - args[i] = 0; - m++; - } - } - return m + 1; -} - - - -/*****************************************************************************/ -char **pj_trim_argv (size_t argc, char *args) { -/****************************************************************************** -Create an argv-style array from elements placed in the argument string, args. - -args is a trimmed string as returned by pj_trim_argc(), and argc is the number -of trimmed strings found (i.e. the return value of pj_trim_args()). Hence, - int argc = pj_trim_argc (args); - char **argv = pj_trim_argv (argc, args); -will produce a classic style (argc, argv) pair from a string of whitespace -separated args. No new memory is allocated for storing the individual args -(they stay in the args string), but for the pointers to the args a new array -is allocated and returned. - -It is the duty of the caller to free this array. -******************************************************************************/ - size_t i, j; - char **argv; - - if (nullptr==args) - return nullptr; - if (0==argc) - return nullptr; - - - /* turn the input string into an array of strings */ - argv = (char **) calloc (argc, sizeof (char *)); - if (nullptr==argv) - return nullptr; - argv[0] = args; - j = 1; - for (i = 0; ; i++) { - if (0==args[i]) { - argv[j++] = args + (i + 1); - } - if (j==argc) - break; - } - return argv; -} - - - -/*****************************************************************************/ -char *pj_make_args (size_t argc, char **argv) { -/****************************************************************************** -pj_make_args is the inverse of the pj_trim_argc/pj_trim_argv combo: It -converts free format command line input to something proj_create can consume. - -Allocates, and returns, an array of char, large enough to hold a whitespace -separated copy of the args in argv. It is the duty of the caller to free this -array. -******************************************************************************/ - size_t i, n; - char *p; - - for (i = n = 0; i < argc; i++) - n += strlen (argv[i]); - - p = static_cast(pj_calloc (n + argc + 1, sizeof (char))); - if (nullptr==p) - return nullptr; - if (0==argc) - return p; - - for (i = 0; i < argc; i++) { - strcat (p, argv[i]); - strcat (p, " "); - } - return pj_shrink (p); -} - - - -/*****************************************************************************/ -void proj_context_errno_set (PJ_CONTEXT *ctx, int err) { -/****************************************************************************** -Raise an error directly on a context, without going through a PJ belonging -to that context. -******************************************************************************/ - if (nullptr==ctx) - ctx = pj_get_default_ctx(); - pj_ctx_set_errno (ctx, err); -} - -/* logging */ - -/* pj_vlog resides in pj_log.c and relates to pj_log as vsprintf relates to sprintf */ -void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ); - - -/***************************************************************************************/ -PJ_LOG_LEVEL proj_log_level (PJ_CONTEXT *ctx, PJ_LOG_LEVEL log_level) { -/**************************************************************************************** - Set logging level 0-3. Higher number means more debug info. 0 turns it off -****************************************************************************************/ - PJ_LOG_LEVEL previous; - if (nullptr==ctx) - ctx = pj_get_default_ctx(); - if (nullptr==ctx) - return PJ_LOG_TELL; - previous = static_cast(abs (ctx->debug_level)); - if (PJ_LOG_TELL==log_level) - return previous; - ctx->debug_level = log_level; - return previous; -} - - -/*****************************************************************************/ -void proj_log_error (PJ *P, const char *fmt, ...) { -/****************************************************************************** - For reporting the most severe events. -******************************************************************************/ - va_list args; - va_start( args, fmt ); - pj_vlog (pj_get_ctx (P), PJ_LOG_ERROR , fmt, args); - va_end( args ); -} - - -/*****************************************************************************/ -void proj_log_debug (PJ *P, const char *fmt, ...) { -/****************************************************************************** - For reporting debugging information. -******************************************************************************/ - va_list args; - va_start( args, fmt ); - pj_vlog (pj_get_ctx (P), PJ_LOG_DEBUG_MAJOR , fmt, args); - va_end( args ); -} - - -/*****************************************************************************/ -void proj_log_trace (PJ *P, const char *fmt, ...) { -/****************************************************************************** - For reporting embarrasingly detailed debugging information. -******************************************************************************/ - va_list args; - va_start( args, fmt ); - pj_vlog (pj_get_ctx (P), PJ_LOG_DEBUG_MINOR , fmt, args); - va_end( args ); -} - - -/*****************************************************************************/ -void proj_log_func (PJ_CONTEXT *ctx, void *app_data, PJ_LOG_FUNCTION logf) { -/****************************************************************************** - Put a new logging function into P's context. The opaque object app_data is - passed as first arg at each call to the logger -******************************************************************************/ - if (nullptr==ctx) - pj_get_default_ctx (); - if (nullptr==ctx) - return; - ctx->app_data = app_data; - if (nullptr!=logf) - ctx->logger = logf; -} diff --git a/src/pj_inv.cpp b/src/pj_inv.cpp deleted file mode 100644 index ba7e6722..00000000 --- a/src/pj_inv.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Inverse operation invocation - * Author: Thomas Knudsen, thokn@sdfe.dk, 2018-01-02 - * Based on material from Gerald Evenden (original pj_inv) - * and Piyush Agram (original pj_inv3d) - * - ****************************************************************************** - * Copyright (c) 2000, Frank Warmerdam - * Copyright (c) 2018, Thomas Knudsen / SDFE - * - * 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. - *****************************************************************************/ -#include -#include - -#include "proj_internal.h" -#include "proj_math.h" -#include "projects.h" - -#define INPUT_UNITS P->right -#define OUTPUT_UNITS P->left - -static PJ_COORD inv_prepare (PJ *P, PJ_COORD coo) { - if (coo.v[0] == HUGE_VAL || coo.v[1] == HUGE_VAL || coo.v[2] == HUGE_VAL) { - proj_errno_set (P, PJD_ERR_INVALID_X_OR_Y); - return proj_coord_error (); - } - - /* The helmert datum shift will choke unless it gets a sensible 4D coordinate */ - if (HUGE_VAL==coo.v[2] && P->helmert) coo.v[2] = 0.0; - if (HUGE_VAL==coo.v[3] && P->helmert) coo.v[3] = 0.0; - - if (P->axisswap) - coo = proj_trans (P->axisswap, PJ_INV, coo); - - /* Handle remaining possible input types */ - switch (INPUT_UNITS) { - case PJ_IO_UNITS_WHATEVER: - return coo; - - /* de-scale and de-offset */ - case PJ_IO_UNITS_CARTESIAN: - coo.xyz.x *= P->to_meter; - coo.xyz.y *= P->to_meter; - coo.xyz.z *= P->to_meter; - if (P->is_geocent) { - coo = proj_trans (P->cart, PJ_INV, coo); - } - - return coo; - - case PJ_IO_UNITS_PROJECTED: - case PJ_IO_UNITS_CLASSIC: - coo.xyz.x = P->to_meter * coo.xyz.x - P->x0; - coo.xyz.y = P->to_meter * coo.xyz.y - P->y0; - coo.xyz.z = P->vto_meter * coo.xyz.z - P->z0; - if (INPUT_UNITS==PJ_IO_UNITS_PROJECTED) - return coo; - - /* Classic proj.4 functions expect plane coordinates in units of the semimajor axis */ - /* Multiplying by ra, rather than dividing by a because the CalCOFI projection */ - /* stomps on a and hence (apparently) depends on this to roundtrip correctly */ - /* (CalCOFI avoids further scaling by stomping - but a better solution is possible) */ - coo.xyz.x *= P->ra; - coo.xyz.y *= P->ra; - return coo; - - case PJ_IO_UNITS_ANGULAR: - coo.lpz.z = P->vto_meter * coo.lpz.z - P->z0; - break; - } - - /* Should not happen, so we could return pj_coord_err here */ - return coo; -} - - - -static PJ_COORD inv_finalize (PJ *P, PJ_COORD coo) { - if (coo.xyz.x == HUGE_VAL) { - proj_errno_set (P, PJD_ERR_INVALID_X_OR_Y); - return proj_coord_error (); - } - - if (OUTPUT_UNITS==PJ_IO_UNITS_ANGULAR) { - - /* Distance from central meridian, taking system zero meridian into account */ - coo.lp.lam = coo.lp.lam + P->from_greenwich + P->lam0; - - /* adjust longitude to central meridian */ - if (0==P->over) - coo.lpz.lam = adjlon(coo.lpz.lam); - - if (P->vgridshift) - coo = proj_trans (P->vgridshift, PJ_INV, coo); /* Go geometric from orthometric */ - if (coo.lp.lam==HUGE_VAL) - return coo; - if (P->hgridshift) - coo = proj_trans (P->hgridshift, PJ_FWD, coo); - else if (P->helmert || (P->cart_wgs84 != nullptr && P->cart != nullptr)) { - coo = proj_trans (P->cart, PJ_FWD, coo); /* Go cartesian in local frame */ - if( P->helmert ) - coo = proj_trans (P->helmert, PJ_FWD, coo); /* Step into WGS84 */ - coo = proj_trans (P->cart_wgs84, PJ_INV, coo); /* Go back to angular using WGS84 ellps */ - } - if (coo.lp.lam==HUGE_VAL) - return coo; - - /* If input latitude was geocentrical, convert back to geocentrical */ - if (P->geoc) - coo = pj_geocentric_latitude (P, PJ_FWD, coo); - } - - return coo; -} - - -static PJ_COORD error_or_coord(PJ *P, PJ_COORD coord, int last_errno) { - if (proj_errno(P)) - return proj_coord_error(); - - proj_errno_restore(P, last_errno); - return coord; -} - - -LP pj_inv(XY xy, PJ *P) { - int last_errno; - PJ_COORD coo = {{0,0,0,0}}; - coo.xy = xy; - - last_errno = proj_errno_reset(P); - - if (!P->skip_inv_prepare) - coo = inv_prepare (P, coo); - if (HUGE_VAL==coo.v[0]) - return proj_coord_error ().lp; - - /* Do the transformation, using the lowest dimensional transformer available */ - if (P->inv) - coo.lp = P->inv(coo.xy, P); - else if (P->inv3d) - coo.lpz = P->inv3d (coo.xyz, P); - else if (P->inv4d) - coo = P->inv4d (coo, P); - else { - proj_errno_set (P, EINVAL); - return proj_coord_error ().lp; - } - if (HUGE_VAL==coo.v[0]) - return proj_coord_error ().lp; - - if (!P->skip_inv_finalize) - coo = inv_finalize (P, coo); - - return error_or_coord(P, coo, last_errno).lp; -} - - - -LPZ pj_inv3d (XYZ xyz, PJ *P) { - int last_errno; - PJ_COORD coo = {{0,0,0,0}}; - coo.xyz = xyz; - - last_errno = proj_errno_reset(P); - - if (!P->skip_inv_prepare) - coo = inv_prepare (P, coo); - if (HUGE_VAL==coo.v[0]) - return proj_coord_error ().lpz; - - /* Do the transformation, using the lowest dimensional transformer feasible */ - if (P->inv3d) - coo.lpz = P->inv3d (coo.xyz, P); - else if (P->inv4d) - coo = P->inv4d (coo, P); - else if (P->inv) - coo.lp = P->inv (coo.xy, P); - else { - proj_errno_set (P, EINVAL); - return proj_coord_error ().lpz; - } - if (HUGE_VAL==coo.v[0]) - return proj_coord_error ().lpz; - - if (!P->skip_inv_finalize) - coo = inv_finalize (P, coo); - - return error_or_coord(P, coo, last_errno).lpz; -} - - - -PJ_COORD pj_inv4d (PJ_COORD coo, PJ *P) { - int last_errno = proj_errno_reset(P); - - if (!P->skip_inv_prepare) - coo = inv_prepare (P, coo); - if (HUGE_VAL==coo.v[0]) - return proj_coord_error (); - - /* Call the highest dimensional converter available */ - if (P->inv4d) - coo = P->inv4d (coo, P); - else if (P->inv3d) - coo.lpz = P->inv3d (coo.xyz, P); - else if (P->inv) - coo.lp = P->inv (coo.xy, P); - else { - proj_errno_set (P, EINVAL); - return proj_coord_error (); - } - if (HUGE_VAL==coo.v[0]) - return proj_coord_error (); - - if (!P->skip_inv_finalize) - coo = inv_finalize (P, coo); - - return error_or_coord(P, coo, last_errno); -} diff --git a/src/pj_list.cpp b/src/pj_list.cpp deleted file mode 100644 index 73ca5f86..00000000 --- a/src/pj_list.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* Projection System: default list of projections -** Use local definition of PJ_LIST_H for subset. -*/ - -#include "proj.h" - -#define USE_PJ_LIST_H 1 -#include "projects.h" - - -/* Generate prototypes for projection functions */ -#define PROJ_HEAD(id, name) extern "C" struct PJconsts *pj_##id(struct PJconsts*); -#include "pj_list.h" -#undef PROJ_HEAD - -/* Generate extern declarations for description strings */ -#define PROJ_HEAD(id, name) extern "C" const char * const pj_s_##id; -#include "pj_list.h" -#undef PROJ_HEAD - -/* Generate the null-terminated list of projection functions with associated mnemonics and descriptions */ -#define PROJ_HEAD(id, name) {#id, pj_##id, &pj_s_##id}, -const struct PJ_LIST pj_list[] = { -#include "pj_list.h" - {nullptr, nullptr, nullptr}, -}; -#undef PROJ_HEAD - - -const PJ_OPERATIONS *proj_list_operations(void) { - return pj_list; -} diff --git a/src/pj_log.cpp b/src/pj_log.cpp deleted file mode 100644 index 0f81dc13..00000000 --- a/src/pj_log.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of pj_log() function. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2010, 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. - *****************************************************************************/ - -#include -#include -#include -#include - -#include "proj.h" -#include "projects.h" - -/************************************************************************/ -/* pj_stderr_logger() */ -/************************************************************************/ - -void pj_stderr_logger( void *app_data, int level, const char *msg ) - -{ - (void) app_data; - (void) level; - fprintf( stderr, "%s\n", msg ); -} - -/************************************************************************/ -/* pj_vlog() */ -/************************************************************************/ -void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ); -/* Workhorse for the log functions - relates to pj_log as vsprintf relates to sprintf */ -void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ) - -{ - char *msg_buf; - int debug_level = ctx->debug_level; - int shutup_unless_errno_set = debug_level < 0; - - /* For negative debug levels, we first start logging when errno is set */ - if (ctx->last_errno==0 && shutup_unless_errno_set) - return; - - if (debug_level < 0) - debug_level = -debug_level; - - if( level > debug_level ) - return; - - msg_buf = (char *) malloc(100000); - if( msg_buf == nullptr ) - return; - - /* we should use vsnprintf where available once we add configure detect.*/ - vsprintf( msg_buf, fmt, args ); - - ctx->logger( ctx->app_data, level, msg_buf ); - - free( msg_buf ); -} - - -/************************************************************************/ -/* pj_log() */ -/************************************************************************/ - -void pj_log( projCtx ctx, int level, const char *fmt, ... ) - -{ - va_list args; - - if( level > ctx->debug_level ) - return; - - va_start( args, fmt ); - pj_vlog( ctx, level, fmt, args ); - va_end( args ); -} diff --git a/src/pj_malloc.cpp b/src/pj_malloc.cpp deleted file mode 100644 index c8681570..00000000 --- a/src/pj_malloc.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Memory management for proj.4. - * This version includes an implementation of generic destructors, - * for memory deallocation for the large majority of PJ-objects - * that do not allocate anything else than the PJ-object itself, - * and its associated opaque object - i.e. no additional malloc'ed - * memory inside the opaque object. - * - * Author: Gerald I. Evenden (Original proj.4 author), - * Frank Warmerdam (2000) pj_malloc? - * Thomas Knudsen (2016) - freeup/dealloc parts - * - ****************************************************************************** - * Copyright (c) 2000, Frank Warmerdam - * Copyright (c) 2016, Thomas Knudsen / SDFE - * - * 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. - *****************************************************************************/ - -/* allocate and deallocate memory */ -/* These routines are used so that applications can readily replace -** projection system memory allocation/deallocation call with custom -** application procedures. */ - -#include -#include -#include -#include - -#include "proj.h" -#include "projects.h" - -/**********************************************************************/ -void *pj_malloc(size_t size) { -/*********************************************************************** -Currently, pj_malloc is a hack to solve an errno problem. -The problem is described in more details at -https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=86420. -It seems, that pj_init and similar functions incorrectly -(under debian/glibs-2.3.2) assume that pj_malloc resets -errno after success. pj_malloc tries to mimic this. - -NOTE (2017-09-29): The problem described at the bugzilla page -referred to above, is most likely a case of someone not -understanding the proper usage of errno. We should review -whether "the problem is actually a problem" in PROJ.4 code. - -Library specific allocators can be useful, and improve -interoperability, if properly used. That is, by making them -run/initialization time switchable, somewhat like the file i/o -interface. - -But as things stand, we are more likely to get benefit -from reviewing the code for proper errno usage, which is hard, -due to the presence of context local and global pj_errnos. - -Probably, these were introduced in order to support incomplete -implementations of thread local errnos at an early phase of the -implementation of multithreading support in PROJ.4). - -It is likely too late to get rid of contexts, but we can still -benefit from a better usage of errno. -***********************************************************************/ - int old_errno = errno; - void *res = malloc(size); - if ( res && !old_errno ) - errno = 0; - return res; -} - - -/**********************************************************************/ -void *pj_calloc (size_t n, size_t size) { -/*********************************************************************** -pj_calloc is the pj-equivalent of calloc(). - -It allocates space for an array of elements of size . -The array is initialized to zeros. -***********************************************************************/ - void *res = pj_malloc (n*size); - if (nullptr==res) - return nullptr; - memset (res, 0, n*size); - return res; -} - - -/**********************************************************************/ -void pj_dalloc(void *ptr) { -/**********************************************************************/ - free(ptr); -} - - -/**********************************************************************/ -void *pj_dealloc (void *ptr) { -/*********************************************************************** -pj_dealloc supports the common use case of "clean up and return a null -pointer" to signal an error in a multi level allocation: - - struct foo { int bar; int *baz; }; - - struct foo *p = pj_calloc (1, sizeof (struct foo)); - if (0==p) - return 0; - - p->baz = pj_calloc (10, sizeof(int)); - if (0==p->baz) - return pj_dealloc (p); // clean up + signal error by 0-return - - return p; // success - -***********************************************************************/ - if (nullptr==ptr) - return nullptr; - pj_dalloc (ptr); - return nullptr; -} - -/**********************************************************************/ -char *pj_strdup(const char *str) -/**********************************************************************/ -{ - size_t len = strlen(str) + 1; - char *dup = static_cast(pj_malloc(len)); - if (dup) - memcpy(dup, str, len); - return dup; -} - - -/*****************************************************************************/ -void *pj_dealloc_params (PJ_CONTEXT *ctx, paralist *start, int errlev) { -/***************************************************************************** - Companion to pj_default_destructor (below). Deallocates a linked list - of "+proj=xxx" initialization parameters. - - Also called from pj_init_ctx when encountering errors before the PJ - proper is allocated. -******************************************************************************/ - paralist *t, *n; - for (t = start; t; t = n) { - n = t->next; - pj_dealloc(t); - } - pj_ctx_set_errno (ctx, errlev); - return (void *) nullptr; -} - - - - -/************************************************************************/ -/* pj_free() */ -/* */ -/* This is the application callable entry point for destroying */ -/* a projection definition. It does work generic to all */ -/* projection types, and then calls the projection specific */ -/* free function, P->destructor(), to do local work. */ -/* In most cases P->destructor()==pj_default_destructor. */ -/************************************************************************/ - -void pj_free(PJ *P) { - if (nullptr==P) - return; - /* free projection parameters - all the hard work is done by */ - /* pj_default_destructor, which is supposed */ - /* to be called as the last step of the local destructor */ - /* pointed to by P->destructor. In most cases, */ - /* pj_default_destructor actually *is* what is pointed to */ - P->destructor (P, proj_errno(P)); -} - - - - -/*****************************************************************************/ -PJ *pj_default_destructor (PJ *P, int errlev) { /* Destructor */ -/***************************************************************************** - Does memory deallocation for "plain" PJ objects, i.e. that vast majority - of PJs where the opaque object does not contain any additionally - allocated memory below the P->opaque level. -******************************************************************************/ - - /* Even if P==0, we set the errlev on pj_error and the default context */ - /* Note that both, in the multithreaded case, may then contain undefined */ - /* values. This is expected behaviour. For MT have one ctx per thread */ - if (0!=errlev) - pj_ctx_set_errno (pj_get_ctx(P), errlev); - - if (nullptr==P) - return nullptr; - - /* free grid lists */ - pj_dealloc( P->gridlist ); - pj_dealloc( P->vgridlist_geoid ); - pj_dealloc( P->catalog_name ); - - /* We used to call pj_dalloc( P->catalog ), but this will leak */ - /* memory. The safe way to clear catalog and grid is to call */ - /* pj_gc_unloadall(pj_get_default_ctx()); and pj_deallocate_grids(); */ - /* TODO: we should probably have a public pj_cleanup() method to do all */ - /* that */ - - /* free the interface to Charles Karney's geodesic library */ - pj_dealloc( P->geod ); - - /* free parameter list elements */ - pj_dealloc_params (pj_get_ctx(P), P->params, errlev); - pj_dealloc (P->def_full); - - /* free the cs2cs emulation elements */ - pj_free (P->axisswap); - pj_free (P->helmert); - pj_free (P->cart); - pj_free (P->cart_wgs84); - pj_free (P->hgridshift); - pj_free (P->vgridshift); - - pj_dealloc (static_cast(P->opaque)); - pj_dealloc(P); - return nullptr; -} diff --git a/src/pj_math.cpp b/src/pj_math.cpp deleted file mode 100644 index 540ab9eb..00000000 --- a/src/pj_math.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/****************************************************************************** - * Project: PROJ - * Purpose: Make C99 math functions available on C89 systems - * Author: Kristian Evers - * - ****************************************************************************** - * Copyright (c) 2018, 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. - *****************************************************************************/ - -#include "proj_math.h" - -/* pj_isnan is used in gie.c which means that is has to */ -/* be exported in the Windows DLL and therefore needs */ -/* to be declared even though we have isnan() on the */ -/* system. */ - -#ifdef HAVE_C99_MATH -int pj_isnan (double x); -#endif - -/* Returns 0 if not a NaN and non-zero if val is a NaN */ -int pj_isnan (double x) { - /* cppcheck-suppress duplicateExpression */ - return x != x; -} - -#if !(defined(HAVE_C99_MATH) && HAVE_C99_MATH) - -/* Compute hypotenuse */ -double pj_hypot(double x, double y) { - x = fabs(x); - y = fabs(y); - if ( x < y ) { - x /= y; - return ( y * sqrt( 1. + x * x ) ); - } else { - y /= (x != 0.0 ? x : 1.0); - return ( x * sqrt( 1. + y * y ) ); - } -} - -/* Compute log(1+x) accurately */ -double pj_log1p(double x) { - volatile double - y = 1 + x, - z = y - 1; - /* Here's the explanation for this magic: y = 1 + z, exactly, and z - * approx x, thus log(y)/z (which is nearly constant near z = 0) returns - * a good approximation to the true log(1 + x)/x. The multiplication x * - * (log(y)/z) introduces little additional error. */ - return z == 0 ? x : x * log(y) / z; -} - -/* Compute asinh(x) accurately */ -double pj_asinh(double x) { - double y = fabs(x); /* Enforce odd parity */ - y = log1p(y * (1 + y/(hypot(1.0, y) + 1))); - return x > 0 ? y : (x < 0 ? -y : x); -} - -double pj_round(double x) { - /* The handling of corner cases is copied from boost; see - * https://github.com/boostorg/math/pull/8 - * with improvements to return -0.0 when appropriate */ - double t; - if (x == 0) - return x; /* Retain sign of 0 */ - else if (0 < x && x < 0.5) - return +0.0; - else if (0 > x && x > -0.5) - return -0.0; - else if (x > 0) { - t = ceil(x); - return 0.5 < t - x ? t - 1 : t; - } else { /* Includes NaN */ - t = floor(x); - return 0.5 < x - t ? t + 1 : t; - } -} - -long pj_lround(double x) { - /* Default value for overflow + NaN + (x == LONG_MIN) */ - long r = LONG_MIN; - x = round(x); - if (fabs(x) < -(double)LONG_MIN) /* Assume (double)LONG_MIN is exact */ - r = (int)x; - return r; -} - -#endif /* !(defined(HAVE_C99_MATH) && HAVE_C99_MATH) */ diff --git a/src/pj_mlfn.cpp b/src/pj_mlfn.cpp deleted file mode 100644 index e032e642..00000000 --- a/src/pj_mlfn.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include - -#include "projects.h" - -/* meridional distance for ellipsoid and inverse -** 8th degree - accurate to < 1e-5 meters when used in conjunction -** with typical major axis values. -** Inverse determines phi to EPS (1e-11) radians, about 1e-6 seconds. -*/ -#define C00 1. -#define C02 .25 -#define C04 .046875 -#define C06 .01953125 -#define C08 .01068115234375 -#define C22 .75 -#define C44 .46875 -#define C46 .01302083333333333333 -#define C48 .00712076822916666666 -#define C66 .36458333333333333333 -#define C68 .00569661458333333333 -#define C88 .3076171875 -#define EPS 1e-11 -#define MAX_ITER 10 -#define EN_SIZE 5 - -double *pj_enfn(double es) { - double t, *en; - - en = (double *) pj_malloc(EN_SIZE * sizeof (double)); - if (nullptr==en) - return nullptr; - - en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08))); - en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08))); - en[2] = (t = es * es) * (C44 - es * (C46 + es * C48)); - en[3] = (t *= es) * (C66 - es * C68); - en[4] = t * es * C88; - - return en; -} - - double -pj_mlfn(double phi, double sphi, double cphi, double *en) { - cphi *= sphi; - sphi *= sphi; - return(en[0] * phi - cphi * (en[1] + sphi*(en[2] - + sphi*(en[3] + sphi*en[4])))); -} - double -pj_inv_mlfn(projCtx ctx, double arg, double es, double *en) { - double s, t, phi, k = 1./(1.-es); - int i; - - phi = arg; - for (i = MAX_ITER; i ; --i) { /* rarely goes over 2 iterations */ - s = sin(phi); - t = 1. - es * s * s; - phi -= t = (pj_mlfn(phi, s, cos(phi), en) - arg) * (t * sqrt(t)) * k; - if (fabs(t) < EPS) - return phi; - } - pj_ctx_set_errno( ctx, PJD_ERR_NON_CONV_INV_MERI_DIST ); - return phi; -} diff --git a/src/pj_msfn.cpp b/src/pj_msfn.cpp deleted file mode 100644 index 999e73a7..00000000 --- a/src/pj_msfn.cpp +++ /dev/null @@ -1,7 +0,0 @@ -/* determine constant small m */ -#include -#include "projects.h" - double -pj_msfn(double sinphi, double cosphi, double es) { - return (cosphi / sqrt (1. - es * sinphi * sinphi)); -} diff --git a/src/pj_mutex.cpp b/src/pj_mutex.cpp deleted file mode 100644 index 3752324c..00000000 --- a/src/pj_mutex.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Mutex (thread lock) functions. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2009, 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. - *****************************************************************************/ - - -/* projects.h and windows.h conflict - avoid this! */ - -#if defined(MUTEX_pthread) && !defined(_XOPEN_SOURCE) && !defined(__sun) -/* For pthread_mutexattr_settype */ -#define _XOPEN_SOURCE 500 -#endif - -/* For PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#ifndef _WIN32 -#include "proj_config.h" -#include "projects.h" -#else -#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#endif -#include "proj_api.h" -#endif - -/* on win32 we always use win32 mutexes, even if pthreads are available */ -#if defined(_WIN32) && !defined(MUTEX_stub) -#ifndef MUTEX_win32 -# define MUTEX_win32 -#endif -# undef MUTEX_pthread -#endif - -#if !defined(MUTEX_stub) && !defined(MUTEX_pthread) && !defined(MUTEX_win32) -# define MUTEX_stub -#endif - -/************************************************************************/ -/* ==================================================================== */ -/* stub mutex implementation */ -/* ==================================================================== */ -/************************************************************************/ - -#ifdef MUTEX_stub - -/************************************************************************/ -/* pj_acquire_lock() */ -/* */ -/* Acquire the PROJ.4 lock. */ -/************************************************************************/ - -void pj_acquire_lock() -{ -} - -/************************************************************************/ -/* pj_release_lock() */ -/* */ -/* Release the PROJ.4 lock. */ -/************************************************************************/ - -void pj_release_lock() -{ -} - -/************************************************************************/ -/* pj_cleanup_lock() */ -/************************************************************************/ -void pj_cleanup_lock() -{ -} - -#endif /* def MUTEX_stub */ - -/************************************************************************/ -/* ==================================================================== */ -/* pthread mutex implementation */ -/* ==================================================================== */ -/************************************************************************/ - -#ifdef MUTEX_pthread - -#include "pthread.h" - -#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" -#endif -static pthread_mutex_t core_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -#else -static pthread_mutex_t core_lock; - -/************************************************************************/ -/* pj_create_lock() */ -/************************************************************************/ - -static void pj_create_lock() -{ - /* - ** We need to ensure the core mutex is created in recursive mode - */ - pthread_mutexattr_t mutex_attr; - - pthread_mutexattr_init(&mutex_attr); -#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE - pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); -#else - pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE_NP); -#endif - pthread_mutex_init(&core_lock, &mutex_attr); -} - -#endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */ - -/************************************************************************/ -/* pj_acquire_lock() */ -/* */ -/* Acquire the PROJ.4 lock. */ -/************************************************************************/ - -void pj_acquire_lock() -{ - -#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP - static pthread_once_t sOnceKey = PTHREAD_ONCE_INIT; - if( pthread_once(&sOnceKey, pj_create_lock) != 0 ) - { - fprintf(stderr, "pthread_once() failed in pj_acquire_lock().\n"); - } -#endif - - pthread_mutex_lock( &core_lock); -} - -/************************************************************************/ -/* pj_release_lock() */ -/* */ -/* Release the PROJ.4 lock. */ -/************************************************************************/ - -void pj_release_lock() -{ - pthread_mutex_unlock( &core_lock ); -} - -/************************************************************************/ -/* pj_cleanup_lock() */ -/************************************************************************/ -void pj_cleanup_lock() -{ -} - -#endif /* def MUTEX_pthread */ - -/************************************************************************/ -/* ==================================================================== */ -/* win32 mutex implementation */ -/* ==================================================================== */ -/************************************************************************/ - -#ifdef MUTEX_win32 - -#include - -static HANDLE mutex_lock = NULL; - -#if _WIN32_WINNT >= 0x0600 - -/************************************************************************/ -/* pj_create_lock() */ -/************************************************************************/ - -static BOOL CALLBACK pj_create_lock(PINIT_ONCE InitOnce, - PVOID Parameter, - PVOID *Context) -{ - (void)InitOnce; - (void)Parameter; - (void)Context; - mutex_lock = CreateMutex( NULL, FALSE, NULL ); - return TRUE; -} -#endif - -/************************************************************************/ -/* pj_init_lock() */ -/************************************************************************/ - -static void pj_init_lock() - -{ -#if _WIN32_WINNT >= 0x0600 - static INIT_ONCE sInitOnce = INIT_ONCE_STATIC_INIT; - InitOnceExecuteOnce( &sInitOnce, pj_create_lock, NULL, NULL ); -#else - if( mutex_lock == NULL ) - mutex_lock = CreateMutex( NULL, FALSE, NULL ); -#endif -} - -/************************************************************************/ -/* pj_acquire_lock() */ -/* */ -/* Acquire the PROJ.4 lock. */ -/************************************************************************/ - -void pj_acquire_lock() -{ - if( mutex_lock == NULL ) - pj_init_lock(); - - WaitForSingleObject( mutex_lock, INFINITE ); -} - -/************************************************************************/ -/* pj_release_lock() */ -/* */ -/* Release the PROJ.4 lock. */ -/************************************************************************/ - -void pj_release_lock() -{ - if( mutex_lock == NULL ) - pj_init_lock(); - else - ReleaseMutex( mutex_lock ); -} - -/************************************************************************/ -/* pj_cleanup_lock() */ -/************************************************************************/ -void pj_cleanup_lock() -{ - if( mutex_lock != NULL ) - { - CloseHandle( mutex_lock ); - mutex_lock = NULL; - } -} - -#endif /* def MUTEX_win32 */ diff --git a/src/pj_open_lib.cpp b/src/pj_open_lib.cpp deleted file mode 100644 index c75b4af6..00000000 --- a/src/pj_open_lib.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of pj_open_lib(), and pj_set_finder(). These - * provide a standard interface for opening projections support - * data files. - * Author: Gerald Evenden, Frank Warmerdam - * - ****************************************************************************** - * Copyright (c) 1995, Gerald Evenden - * Copyright (c) 2002, 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include -#include -#include -#include - -#include "proj_internal.h" -#include "projects.h" - -static const char *(*pj_finder)(const char *) = nullptr; -static int path_count = 0; -static char **search_path = nullptr; -static const char * proj_lib_name = -#ifdef PROJ_LIB -PROJ_LIB; -#else -nullptr; -#endif - -/************************************************************************/ -/* pj_set_finder() */ -/************************************************************************/ - -void pj_set_finder( const char *(*new_finder)(const char *) ) - -{ - pj_finder = new_finder; -} - -/************************************************************************/ -/* pj_set_searchpath() */ -/* */ -/* Path control for callers that can't practically provide */ -/* pj_set_finder() style callbacks. Call with (0,NULL) as args */ -/* to clear the searchpath set. */ -/************************************************************************/ - -void pj_set_searchpath ( int count, const char **path ) -{ - int i; - - if (path_count > 0 && search_path != nullptr) - { - for (i = 0; i < path_count; i++) - { - pj_dalloc(search_path[i]); - } - pj_dalloc(search_path); - path_count = 0; - search_path = nullptr; - } - - if( count > 0 ) - { - search_path = static_cast(pj_malloc(sizeof *search_path * count)); - for (i = 0; i < count; i++) - { - search_path[i] = static_cast(pj_malloc(strlen(path[i]) + 1)); - strcpy(search_path[i], path[i]); - } - } - - path_count = count; -} - -/* just a couple of helper functions that lets other functions - access the otherwise private search path */ -const char * const *proj_get_searchpath(void) { - return (const char * const *)search_path; -} - -int proj_get_path_count(void) { - return path_count; -} -/************************************************************************/ -/* pj_open_lib_ex() */ -/************************************************************************/ - -static PAFile -pj_open_lib_ex(projCtx ctx, const char *name, const char *mode, - char* out_full_filename, size_t out_full_filename_size) { - char fname[MAX_PATH_FILENAME+1]; - const char *sysname; - PAFile fid; - int n = 0; - int i; -#ifdef WIN32 - static const char dir_chars[] = "/\\"; -#else - static const char dir_chars[] = "/"; -#endif - - if( out_full_filename != nullptr && out_full_filename_size > 0 ) - out_full_filename[0] = '\0'; - - /* check if ~/name */ - if (*name == '~' && strchr(dir_chars,name[1]) ) - if ((sysname = getenv("HOME")) != nullptr) { - if( strlen(sysname) + 1 + strlen(name) + 1 > sizeof(fname) ) - { - return nullptr; - } - (void)strcpy(fname, sysname); - fname[n = (int)strlen(fname)] = DIR_CHAR; - fname[++n] = '\0'; - (void)strcpy(fname+n, name + 1); - sysname = fname; - } else - return nullptr; - - /* or fixed path: /name, ./name or ../name */ - else if (strchr(dir_chars,*name) - || (*name == '.' && strchr(dir_chars,name[1])) - || (!strncmp(name, "..", 2) && strchr(dir_chars,name[2])) - || (name[1] == ':' && strchr(dir_chars,name[2])) ) - sysname = name; - - /* or try to use application provided file finder */ - else if( pj_finder != nullptr && pj_finder( name ) != nullptr ) - sysname = pj_finder( name ); - - /* or is environment PROJ_LIB defined */ - else if ((sysname = getenv("PROJ_LIB")) || (sysname = proj_lib_name)) { - if( strlen(sysname) + 1 + strlen(name) + 1 > sizeof(fname) ) - { - return nullptr; - } - (void)strcpy(fname, sysname); - fname[n = (int)strlen(fname)] = DIR_CHAR; - fname[++n] = '\0'; - (void)strcpy(fname+n, name); - sysname = fname; - } else /* just try it bare bones */ - sysname = name; - - if ((fid = pj_ctx_fopen(ctx, sysname, mode)) != nullptr) - { - if( out_full_filename != nullptr && out_full_filename_size > 0 ) - { - strncpy(out_full_filename, sysname, out_full_filename_size); - out_full_filename[out_full_filename_size-1] = '\0'; - } - errno = 0; - } - - /* If none of those work and we have a search path, try it */ - if (!fid && path_count > 0) - { - for (i = 0; fid == nullptr && i < path_count; i++) - { - if( strlen(search_path[i]) + 1 + strlen(name) + 1 <= sizeof(fname) ) - { - sprintf(fname, "%s%c%s", search_path[i], DIR_CHAR, name); - sysname = fname; - fid = pj_ctx_fopen(ctx, sysname, mode); - } - } - if (fid) - { - if( out_full_filename != nullptr && out_full_filename_size > 0 ) - { - strncpy(out_full_filename, sysname, out_full_filename_size); - out_full_filename[out_full_filename_size-1] = '\0'; - } - errno = 0; - } - } - - if( ctx->last_errno == 0 && errno != 0 ) - pj_ctx_set_errno( ctx, errno ); - - pj_log( ctx, PJ_LOG_DEBUG_MAJOR, - "pj_open_lib(%s): call fopen(%s) - %s", - name, sysname, - fid == nullptr ? "failed" : "succeeded" ); - - return(fid); -} - -/************************************************************************/ -/* pj_open_lib() */ -/************************************************************************/ - -PAFile -pj_open_lib(projCtx ctx, const char *name, const char *mode) { - return pj_open_lib_ex(ctx, name, mode, nullptr, 0); -} - -/************************************************************************/ -/* pj_find_file() */ -/************************************************************************/ - -/** Returns the full filename corresponding to a proj resource file specified - * as a short filename. - * - * @param ctx context. - * @param short_filename short filename (e.g. egm96_15.gtx) - * @param out_full_filename output buffer, of size out_full_filename_size, that - * will receive the full filename on success. - * Will be zero-terminated. - * @param out_full_filename_size size of out_full_filename. - * @return 1 if the file was found, 0 otherwise. - */ -int pj_find_file(projCtx ctx, const char *short_filename, - char* out_full_filename, size_t out_full_filename_size) -{ - PAFile f = pj_open_lib_ex(ctx, short_filename, "rb", out_full_filename, - out_full_filename_size); - if( f != nullptr ) - { - pj_ctx_fclose(ctx, f); - return 1; - } - return 0; -} diff --git a/src/pj_param.cpp b/src/pj_param.cpp deleted file mode 100644 index 74247b72..00000000 --- a/src/pj_param.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* put parameters in linked list and retrieve */ - -#include -#include -#include -#include -#include - -#include "projects.h" - -/* create parameter list entry */ -paralist *pj_mkparam(const char *str) { - paralist *newitem; - - if((newitem = (paralist *)pj_malloc(sizeof(paralist) + strlen(str))) != nullptr) { - newitem->used = 0; - newitem->next = nullptr; - if (*str == '+') - ++str; - (void)strcpy(newitem->param, str); - } - return newitem; -} - - -/* As pj_mkparam, but payload ends at first whitespace, rather than at end of */ -paralist *pj_mkparam_ws (const char *str) { - paralist *newitem; - size_t len = 0; - - if (nullptr==str) - return nullptr; - - /* Find start and length of string */ - while (isspace (*str)) - str++; - while ((!isspace(str[len])) && 0!=str[len]) - len++; - if (*str == '+') { - str++; - len--; - } - - /* Use calloc to automagically 0-terminate the copy */ - newitem = (paralist *) pj_calloc (1, sizeof(paralist) + len + 1); - if (nullptr==newitem) - return nullptr; - memmove(newitem->param, str, len); - - newitem->used = 0; - newitem->next = nullptr; - - return newitem; -} - -/**************************************************************************************/ -paralist *pj_param_exists (paralist *list, const char *parameter) { -/*************************************************************************************** - Determine whether a given parameter exists in a paralist. If it does, return - a pointer to the corresponding list element - otherwise return 0. - - In support of the pipeline syntax, the search is terminated once a "+step" list - element is reached, in which case a 0 is returned, unless the parameter - searched for is actually "step", in which case a pointer to the "step" list - element is returned. - - This function is equivalent to the pj_param (...) call with the "opt" argument - set to the parameter name preceeeded by a 't'. But by using this one, one avoids - writing the code allocating memory for a new copy of parameter name, and prepending - the t (for compile time known names, this is obviously not an issue). -***************************************************************************************/ - paralist *next = list; - const char *c = strchr (parameter, '='); - size_t len = strlen (parameter); - if (c) - len = c - parameter; - if (list==nullptr) - return nullptr; - - for (next = list; next; next = next->next) { - if (0==strncmp (parameter, next->param, len) && (next->param[len]=='=' || next->param[len]==0)) { - next->used = 1; - return next; - } - if (0==strcmp (parameter, "step")) - return nullptr; - } - - return nullptr; -} - - -/************************************************************************/ -/* pj_param() */ -/* */ -/* Test for presence or get parameter value. The first */ -/* character in `opt' is a parameter type which can take the */ -/* values: */ -/* */ -/* `t' - test for presence, return TRUE/FALSE in PROJVALUE.i */ -/* `i' - integer value returned in PROJVALUE.i */ -/* `d' - simple valued real input returned in PROJVALUE.f */ -/* `r' - degrees (DMS translation applied), returned as */ -/* radians in PROJVALUE.f */ -/* `s' - string returned in PROJVALUE.s */ -/* `b' - test for t/T/f/F, return in PROJVALUE.i */ -/* */ -/* Search is terminated when "step" is found, in which case */ -/* 0 is returned, unless "step" was the target searched for. */ -/* */ -/************************************************************************/ - -PROJVALUE pj_param (projCtx ctx, paralist *pl, const char *opt) { - - int type; - unsigned l; - PROJVALUE value = {0}; - - if ( ctx == nullptr ) - ctx = pj_get_default_ctx(); - - type = *opt++; - - if (nullptr==strchr ("tbirds", type)) { - fprintf(stderr, "invalid request to pj_param, fatal\n"); - exit(1); - } - - pl = pj_param_exists (pl, opt); - if (type == 't') { - value.i = pl != nullptr; - return value; - } - - /* Not found */ - if (nullptr==pl) { - /* Return value after the switch, so that the return path is */ - /* taken in all cases */ - switch (type) { - case 'b': case 'i': - value.i = 0; - break; - case 'd': case 'r': - value.f = 0.; - break; - case 's': - value.s = nullptr; - break; - } - return value; - } - - /* Found parameter - now find its value */ - pl->used |= 1; - l = (int) strlen(opt); - opt = pl->param + l; - if (*opt == '=') - ++opt; - - switch (type) { - case 'i': /* integer input */ - value.i = atoi(opt); - break; - case 'd': /* simple real input */ - value.f = pj_atof(opt); - break; - case 'r': /* degrees input */ - value.f = dmstor_ctx(ctx, opt, nullptr); - break; - case 's': /* char string */ - value.s = (char *) opt; - break; - case 'b': /* boolean */ - switch (*opt) { - case 'F': case 'f': - value.i = 0; - break; - case '\0': case 'T': case 't': - value.i = 1; - break; - default: - pj_ctx_set_errno (ctx, PJD_ERR_INVALID_BOOLEAN_PARAM); - value.i = 0; - break; - } - break; - } - return value; -} diff --git a/src/pj_phi2.cpp b/src/pj_phi2.cpp deleted file mode 100644 index a83302e6..00000000 --- a/src/pj_phi2.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* Determine latitude angle phi-2. */ - -#include - -#include "projects.h" - -static const double TOL = 1.0e-10; -static const int N_ITER = 15; - -/*****************************************************************************/ -double pj_phi2(projCtx ctx, double ts, double e) { -/****************************************************************************** -Determine latitude angle phi-2. -Inputs: - ts = exp(-psi) where psi is the isometric latitude (dimensionless) - e = eccentricity of the ellipsoid (dimensionless) -Output: - phi = geographic latitude (radians) -Here isometric latitude is defined by - psi = log( tan(pi/4 + phi/2) * - ( (1 - e*sin(phi)) / (1 + e*sin(phi)) )^(e/2) ) - = asinh(tan(phi)) - e * atanh(e * sin(phi)) -This routine inverts this relation using the iterative scheme given -by Snyder (1987), Eqs. (7-9) - (7-11) -*******************************************************************************/ - double eccnth = .5 * e; - double Phi = M_HALFPI - 2. * atan(ts); - double con; - int i = N_ITER; - - for(;;) { - double dphi; - con = e * sin(Phi); - dphi = M_HALFPI - 2. * atan(ts * pow((1. - con) / - (1. + con), eccnth)) - Phi; - - Phi += dphi; - - if (fabs(dphi) > TOL && --i) - continue; - break; - } - if (i <= 0) - pj_ctx_set_errno(ctx, PJD_ERR_NON_CON_INV_PHI2); - return Phi; -} diff --git a/src/pj_pr_list.cpp b/src/pj_pr_list.cpp deleted file mode 100644 index b8ad2c04..00000000 --- a/src/pj_pr_list.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* print projection's list of parameters */ - -#include -#include -#include - -#include "projects.h" - -#define LINE_LEN 72 - static int -pr_list(PJ *P, int not_used) { - paralist *t; - int l, n = 1, flag = 0; - - (void)putchar('#'); - for (t = P->params; t; t = t->next) - if ((!not_used && t->used) || (not_used && !t->used)) { - l = (int)strlen(t->param) + 1; - if (n + l > LINE_LEN) { - (void)fputs("\n#", stdout); - n = 2; - } - (void)putchar(' '); - if (*(t->param) != '+') - (void)putchar('+'); - (void)fputs(t->param, stdout); - n += l; - } else - flag = 1; - if (n > 1) - (void)putchar('\n'); - return flag; -} - void /* print link list of projection parameters */ -pj_pr_list(PJ *P) { - char const *s; - - (void)putchar('#'); - for (s = P->descr; *s ; ++s) { - (void)putchar(*s); - if (*s == '\n') - (void)putchar('#'); - } - (void)putchar('\n'); - if (pr_list(P, 0)) { - (void)fputs("#--- following specified but NOT used\n", stdout); - (void)pr_list(P, 1); - } -} - -/************************************************************************/ -/* pj_get_def() */ -/* */ -/* Returns the PROJ.4 command string that would produce this */ -/* definition expanded as much as possible. For instance, */ -/* +init= calls and +datum= definitions would be expanded. */ -/************************************************************************/ - -char *pj_get_def( PJ *P, int options ) - -{ - paralist *t; - int l; - char *definition; - size_t def_max = 10; - (void) options; - - definition = (char *) pj_malloc(def_max); - if (!definition) - return nullptr; - definition[0] = '\0'; - - for (t = P->params; t; t = t->next) - { - /* skip unused parameters ... mostly appended defaults and stuff */ - if (!t->used) - continue; - - /* grow the resulting string if needed */ - l = (int)strlen(t->param) + 1; - if( strlen(definition) + l + 5 > def_max ) - { - char *def2; - - def_max = def_max * 2 + l + 5; - def2 = (char *) pj_malloc(def_max); - if (def2) { - strcpy( def2, definition ); - pj_dalloc( definition ); - definition = def2; - } - else { - pj_dalloc( definition ); - return nullptr; - } - } - - /* append this parameter */ - strcat( definition, " +" ); - strcat( definition, t->param ); - } - - return definition; -} diff --git a/src/pj_qsfn.cpp b/src/pj_qsfn.cpp deleted file mode 100644 index c18a7b95..00000000 --- a/src/pj_qsfn.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* determine small q */ -#include -#include "projects.h" - -# define EPSILON 1.0e-7 - -double pj_qsfn(double sinphi, double e, double one_es) { - double con, div1, div2; - - if (e >= EPSILON) { - con = e * sinphi; - div1 = 1.0 - con * con; - div2 = 1.0 + con; - - /* avoid zero division, fail gracefully */ - if (div1 == 0.0 || div2 == 0.0) - return HUGE_VAL; - - return (one_es * (sinphi / div1 - (.5 / e) * log ((1. - con) / div2 ))); - } else - return (sinphi + sinphi); -} diff --git a/src/pj_release.cpp b/src/pj_release.cpp deleted file mode 100644 index 9beb45ef..00000000 --- a/src/pj_release.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* <<< Release Notice for library >>> */ - -#include "proj.h" -#include "projects.h" - -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) - -char const pj_release[] = - "Rel. " - STR(PROJ_VERSION_MAJOR)"." - STR(PROJ_VERSION_MINOR)"." - STR(PROJ_VERSION_PATCH)", " - "March 1st, 2019"; - -const char *pj_get_release() { - return pj_release; -} diff --git a/src/pj_strerrno.cpp b/src/pj_strerrno.cpp deleted file mode 100644 index 18ed0d33..00000000 --- a/src/pj_strerrno.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* list of projection system pj_errno values */ - -#include -#include -#include - -#include "proj.h" -#include "projects.h" - -static const char * const -pj_err_list[] = { - "no arguments in initialization list", /* -1 */ - "no options found in 'init' file", /* -2 */ - "no colon in init= string", /* -3 */ - "projection not named", /* -4 */ - "unknown projection id", /* -5 */ - "effective eccentricity = 1.", /* -6 */ - "unknown unit conversion id", /* -7 */ - "invalid boolean param argument", /* -8 */ - "unknown elliptical parameter name", /* -9 */ - "reciprocal flattening (1/f) = 0", /* -10 */ - "|radius reference latitude| > 90", /* -11 */ - "squared eccentricity < 0", /* -12 */ - "major axis or radius = 0 or not given", /* -13 */ - "latitude or longitude exceeded limits", /* -14 */ - "invalid x or y", /* -15 */ - "improperly formed DMS value", /* -16 */ - "non-convergent inverse meridional dist", /* -17 */ - "non-convergent inverse phi2", /* -18 */ - "acos/asin: |arg| >1.+1e-14", /* -19 */ - "tolerance condition error", /* -20 */ - "conic lat_1 = -lat_2", /* -21 */ - "lat_1 >= 90", /* -22 */ - "lat_1 = 0", /* -23 */ - "lat_ts >= 90", /* -24 */ - "no distance between control points", /* -25 */ - "projection not selected to be rotated", /* -26 */ - "W <= 0 or M <= 0", /* -27 */ - "lsat not in 1-5 range", /* -28 */ - "path not in range", /* -29 */ - "h <= 0", /* -30 */ - "k <= 0", /* -31 */ - "lat_0 = 0 or 90 or alpha = 90", /* -32 */ - "lat_1=lat_2 or lat_1=0 or lat_2=90", /* -33 */ - "elliptical usage required", /* -34 */ - "invalid UTM zone number", /* -35 */ - "arg(s) out of range for Tcheby eval", /* -36 */ - "failed to find projection to be rotated", /* -37 */ - "failed to load datum shift file", /* -38 */ - "both n & m must be spec'd and > 0", /* -39 */ - "n <= 0, n > 1 or not specified", /* -40 */ - "lat_1 or lat_2 not specified", /* -41 */ - "|lat_1| == |lat_2|", /* -42 */ - "lat_0 is pi/2 from mean lat", /* -43 */ - "unparseable coordinate system definition", /* -44 */ - "geocentric transformation missing z or ellps", /* -45 */ - "unknown prime meridian conversion id", /* -46 */ - "illegal axis orientation combination", /* -47 */ - "point not within available datum shift grids", /* -48 */ - "invalid sweep axis, choose x or y", /* -49 */ - "malformed pipeline", /* -50 */ - "unit conversion factor must be > 0", /* -51 */ - "invalid scale", /* -52 */ - "non-convergent computation", /* -53 */ - "missing required arguments", /* -54 */ - "lat_0 = 0", /* -55 */ - "ellipsoidal usage unsupported", /* -56 */ - "only one +init allowed for non-pipeline operations", /* -57 */ - "argument not numerical or out of range", /* -58 */ - "inconsistent unit type between input and output", /* -59 */ - - /* When adding error messages, remember to update ID defines in - projects.h, and transient_error array in pj_transform */ -}; - -char *pj_strerrno(int err) { - const int max_error = 9999; - static char note[50]; - size_t adjusted_err; - - if (0==err) - return nullptr; - - /* System error codes are positive */ - if (err > 0) { -#ifdef HAVE_STRERROR - return strerror(err); -#else - /* Defend string boundary against exorbitantly large err values */ - /* which may occur on platforms with 64-bit ints */ - sprintf(note, "no system list, errno: %d\n", - (err < max_error) ? err: max_error); - return note; -#endif - } - - /* PROJ.4 error codes are negative: -1 to -9999 */ - adjusted_err = err < -max_error ? max_error : -err - 1; - if (adjusted_err < (sizeof(pj_err_list) / sizeof(char *))) - return (char *)pj_err_list[adjusted_err]; - - sprintf(note, "invalid projection system error (%d)", - (err > -max_error) ? err: -max_error); - return note; -} - -const char* proj_errno_string(int err) { - return pj_strerrno(err); -} diff --git a/src/pj_strtod.cpp b/src/pj_strtod.cpp deleted file mode 100644 index 5a360c2e..00000000 --- a/src/pj_strtod.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/****************************************************************************** - * - * Derived from GDAL port/cpl_strtod.cpp - * Purpose: Functions to convert ASCII string to floating point number. - * Author: Andrey Kiselev, dron@ak4719.spb.edu. - * - ****************************************************************************** - * Copyright (c) 2006, Andrey Kiselev - * Copyright (c) 2008-2012, Even Rouault - * - * 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. - ****************************************************************************/ - -#include -#include -#include -#include - -#include "projects.h" - -/* Windows nmake build doesn't have a proj_config.h, but HAVE_LOCALECONV */ -/* is defined in the compilation line */ -#ifndef HAVE_LOCALECONV -#include "proj_config.h" -#endif - -#define PJ_STRTOD_WORK_BUFFER_SIZE 64 - -/************************************************************************/ -/* pj_atof() */ -/************************************************************************/ - -/** - * Converts ASCII string to floating point number. - * - * This function converts the initial portion of the string pointed to - * by nptr to double floating point representation. The behaviour is the - * same as - * - * pj_strtod(nptr, (char **)NULL); - * - * This function does the same as standard atof(3), but does not take - * locale in account. That means, the decimal delimiter is always '.' - * (decimal point). - * - * @param nptr Pointer to string to convert. - * - * @return Converted value. - */ -double pj_atof( const char* nptr ) -{ - return pj_strtod(nptr, nullptr); -} - - -/************************************************************************/ -/* replace_point_by_locale_point() */ -/************************************************************************/ - -static char* replace_point_by_locale_point(const char* pszNumber, char point, - char* pszWorkBuffer) -{ -#if !defined(HAVE_LOCALECONV) - -#if defined(_MSC_VER) /* Visual C++ */ -#pragma message("localeconv not available") -#else -#warning "localeconv not available" -#endif - - static char byPoint = 0; - if (byPoint == 0) - { - char szBuf[16]; - sprintf(szBuf, "%.1f", 1.0); - byPoint = szBuf[1]; - } - if (point != byPoint) - { - const char* pszPoint = strchr(pszNumber, point); - if (pszPoint) - { - char* pszNew; - if( strlen(pszNumber) < PJ_STRTOD_WORK_BUFFER_SIZE ) - { - strcpy(pszWorkBuffer, pszNumber); - pszNew = pszWorkBuffer; - } - else { - pszNew = pj_strdup(pszNumber); - if (!pszNew) - return NULL; - } - pszNew[pszPoint - pszNumber] = byPoint; - return pszNew; - } - } -#else - struct lconv *poLconv = localeconv(); - if ( poLconv - && poLconv->decimal_point - && poLconv->decimal_point[0] != '\0' ) - { - char byPoint = poLconv->decimal_point[0]; - - if (point != byPoint) - { - const char* pszLocalePoint = strchr(pszNumber, byPoint); - const char* pszPoint = strchr(pszNumber, point); - if (pszPoint || pszLocalePoint) - { - char* pszNew; - if( strlen(pszNumber) < PJ_STRTOD_WORK_BUFFER_SIZE ) - { - strcpy(pszWorkBuffer, pszNumber); - pszNew = pszWorkBuffer; - } - else { - pszNew = pj_strdup(pszNumber); - if (!pszNew) - return nullptr; - } - if( pszLocalePoint ) - pszNew[pszLocalePoint - pszNumber] = ' '; - if( pszPoint ) - pszNew[pszPoint - pszNumber] = byPoint; - return pszNew; - } - } - } -#endif - return (char*) pszNumber; -} - -/************************************************************************/ -/* pj_strtod() */ -/************************************************************************/ - -/** - * Converts ASCII string to floating point number. - * - * This function converts the initial portion of the string pointed to - * by nptr to double floating point representation. This function does the - * same as standard strtod(3), but does not take locale in account and use - * decimal point. - * - * @param nptr Pointer to string to convert. - * @param endptr If is not NULL, a pointer to the character after the last - * character used in the conversion is stored in the location referenced - * by endptr. - * - * @return Converted value. - */ -double pj_strtod( const char *nptr, char **endptr ) -{ -/* -------------------------------------------------------------------- */ -/* We are implementing a simple method here: copy the input string */ -/* into the temporary buffer, replace the specified decimal delimiter */ -/* with the one, taken from locale settings and use standard strtod() */ -/* on that buffer. */ -/* -------------------------------------------------------------------- */ - double dfValue; - int nError; - char szWorkBuffer[PJ_STRTOD_WORK_BUFFER_SIZE]; - - char* pszNumber = replace_point_by_locale_point(nptr, '.', szWorkBuffer); - - dfValue = strtod( pszNumber, endptr ); - nError = errno; - - if ( endptr ) - *endptr = (char *)nptr + (*endptr - pszNumber); - - if (pszNumber != (char*) nptr && pszNumber != szWorkBuffer ) - free( pszNumber ); - - errno = nError; - return dfValue; -} diff --git a/src/pj_transform.cpp b/src/pj_transform.cpp deleted file mode 100644 index 433fc017..00000000 --- a/src/pj_transform.cpp +++ /dev/null @@ -1,1047 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Perform overall coordinate system to coordinate system - * transformations (pj_transform() function) including reprojection - * and datum shifting. - * 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. - *****************************************************************************/ - -#include -#include -#include - -#include "proj.h" -#include "projects.h" -#include "geocent.h" - -static int adjust_axis( projCtx ctx, const char *axis, int denormalize_flag, - long point_count, int point_offset, - double *x, double *y, double *z ); - -#ifndef SRS_WGS84_SEMIMAJOR -#define SRS_WGS84_SEMIMAJOR 6378137.0 -#endif - -#ifndef SRS_WGS84_ESQUARED -#define SRS_WGS84_ESQUARED 0.0066943799901413165 -#endif - -#define Dx_BF (defn->datum_params[0]) -#define Dy_BF (defn->datum_params[1]) -#define Dz_BF (defn->datum_params[2]) -#define Rx_BF (defn->datum_params[3]) -#define Ry_BF (defn->datum_params[4]) -#define Rz_BF (defn->datum_params[5]) -#define M_BF (defn->datum_params[6]) - -/* -** This table is intended to indicate for any given error code -** whether that error will occur for all locations (ie. -** it is a problem with the coordinate system as a whole) in which case the -** value would be 0, or if the problem is with the point being transformed -** in which case the value is 1. -** -** At some point we might want to move this array in with the error message -** list or something, but while experimenting with it this should be fine. -** -** -** NOTE (2017-10-01): Non-transient errors really should have resulted in a -** PJ==0 during initialization, and hence should be handled at the level -** before calling pj_transform. The only obvious example of the contrary -** appears to be the PJD_ERR_GRID_AREA case, which may also be taken to -** mean "no grids available" -** -** -*/ - -static const int transient_error[60] = { - /* 0 1 2 3 4 5 6 7 8 9 */ - /* 0 to 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 10 to 19 */ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, - /* 20 to 29 */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, - /* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 40 to 49 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - /* 50 to 59 */ 1, 0, 1, 0, 1, 1, 1, 1, 0, 0 }; - - -/* -------------------------------------------------------------------- */ -/* Read transient_error[] in a safe way. */ -/* -------------------------------------------------------------------- */ -static int get_transient_error_value(int pos_index) -{ - const int array_size = - (int)(sizeof(transient_error) / sizeof(transient_error[0])); - if( pos_index < 0 || pos_index >= array_size ) { - return 0; - } - return transient_error[pos_index]; -} - - -/* -------------------------------------------------------------------- */ -/* Transform unusual input coordinate axis orientation to */ -/* standard form if needed. */ -/* -------------------------------------------------------------------- */ -static int adjust_axes (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { - /* Nothing to do? */ - if (0==strcmp(P->axis,"enu")) - return 0; - - return adjust_axis( P->ctx, P->axis, - dir==PJ_FWD ? 1: 0, n, dist, x, y, z ); -} - - - -/* ----------------------------------------------------------------------- */ -/* Transform geographic (lat/long) source coordinates to */ -/* cartesian ("geocentric"), if needed */ -/* ----------------------------------------------------------------------- */ -static int geographic_to_cartesian (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { - int res; - long i; - double fac = P->to_meter; - - /* Nothing to do? */ - if (!P->is_geocent) - return 0; - - if ( z == nullptr ) { - pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); - return PJD_ERR_GEOCENTRIC; - } - - if (PJ_FWD==dir) { - fac = P->fr_meter; - res = pj_geodetic_to_geocentric( P->a_orig, P->es_orig, n, dist, x, y, z ); - if (res) - return res; - } - - if (fac != 1.0) { - for( i = 0; i < n; i++ ) { - if( x[dist*i] != HUGE_VAL ) { - x[dist*i] *= fac; - y[dist*i] *= fac; - z[dist*i] *= fac; - } - } - } - - if (PJ_FWD==dir) - return 0; - return pj_geocentric_to_geodetic( - P->a_orig, P->es_orig, - n, dist, - x, y, z - ); -} - - - - - - - - - - -/* -------------------------------------------------------------------- */ -/* Transform destination points to projection coordinates, if */ -/* desired. */ -/* */ -/* Ought to fold this into projected_to_geographic */ -/* -------------------------------------------------------------------- */ -static int geographic_to_projected (PJ *P, long n, int dist, double *x, double *y, double *z) { - long i; - - /* Nothing to do? */ - if (P->is_latlong && !P->geoc && P->vto_meter == 1.0) - return 0; - if (P->is_geocent) - return 0; - - if(P->fwd3d != nullptr && !(z == nullptr && P->is_latlong)) - { - /* Three dimensions must be defined */ - if ( z == nullptr) - { - pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); - return PJD_ERR_GEOCENTRIC; - } - - for( i = 0; i < n; i++ ) - { - XYZ projected_loc; - LPZ geodetic_loc; - - geodetic_loc.lam = x[dist*i]; - geodetic_loc.phi = y[dist*i]; - geodetic_loc.z = z[dist*i]; - - if (geodetic_loc.lam == HUGE_VAL) - continue; - - proj_errno_reset( P ); - projected_loc = pj_fwd3d( geodetic_loc, P); - if( P->ctx->last_errno != 0 ) - { - if( (P->ctx->last_errno != EDOM - && P->ctx->last_errno != ERANGE) - && (P->ctx->last_errno > 0 - || P->ctx->last_errno < -44 || n == 1 - || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) - { - return P->ctx->last_errno; - } - else - { - projected_loc.x = HUGE_VAL; - projected_loc.y = HUGE_VAL; - projected_loc.z = HUGE_VAL; - } - } - - x[dist*i] = projected_loc.x; - y[dist*i] = projected_loc.y; - z[dist*i] = projected_loc.z; - } - return 0; - } - - for( i = 0; i ctx->last_errno != 0 ) - { - if( (P->ctx->last_errno != EDOM - && P->ctx->last_errno != ERANGE) - && (P->ctx->last_errno > 0 - || P->ctx->last_errno < -44 || n == 1 - || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) - { - return P->ctx->last_errno; - } - else - { - projected_loc.x = HUGE_VAL; - projected_loc.y = HUGE_VAL; - } - } - - x[dist*i] = projected_loc.x; - y[dist*i] = projected_loc.y; - } - return 0; -} - - - - - -/* ----------------------------------------------------------------------- */ -/* Transform projected source coordinates to lat/long, if needed */ -/* ----------------------------------------------------------------------- */ -static int projected_to_geographic (PJ *P, long n, int dist, double *x, double *y, double *z) { - long i; - - /* Nothing to do? */ - if (P->is_latlong && !P->geoc && P->vto_meter == 1.0) - return 0; - if (P->is_geocent) - return 0; - - /* Check first if projection is invertible. */ - if( (P->inv3d == nullptr) && (P->inv == nullptr)) - { - pj_ctx_set_errno(pj_get_ctx(P), PJD_ERR_NON_CONV_INV_MERI_DIST); - pj_log( pj_get_ctx(P), PJ_LOG_ERROR, - "pj_transform(): source projection not invertable" ); - return PJD_ERR_NON_CONV_INV_MERI_DIST; - } - - /* If invertible - First try inv3d if defined */ - if (P->inv3d != nullptr && !(z == nullptr && P->is_latlong)) - { - /* Three dimensions must be defined */ - if ( z == nullptr) - { - pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); - return PJD_ERR_GEOCENTRIC; - } - - for (i=0; i < n; i++) - { - XYZ projected_loc; - LPZ geodetic_loc; - - projected_loc.x = x[dist*i]; - projected_loc.y = y[dist*i]; - projected_loc.z = z[dist*i]; - - if (projected_loc.x == HUGE_VAL) - continue; - - proj_errno_reset( P ); - geodetic_loc = pj_inv3d(projected_loc, P); - if( P->ctx->last_errno != 0 ) - { - if( (P->ctx->last_errno != EDOM - && P->ctx->last_errno != ERANGE) - && (P->ctx->last_errno > 0 - || P->ctx->last_errno < -44 || n == 1 - || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) - { - return P->ctx->last_errno; - } - else - { - geodetic_loc.lam = HUGE_VAL; - geodetic_loc.phi = HUGE_VAL; - geodetic_loc.z = HUGE_VAL; - } - } - - x[dist*i] = geodetic_loc.lam; - y[dist*i] = geodetic_loc.phi; - z[dist*i] = geodetic_loc.z; - - } - return 0; - } - - /* Fallback to the original PROJ.4 API 2d inversion - inv */ - for( i = 0; i < n; i++ ) { - XY projected_loc; - LP geodetic_loc; - - projected_loc.x = x[dist*i]; - projected_loc.y = y[dist*i]; - - if( projected_loc.x == HUGE_VAL ) - continue; - - proj_errno_reset( P ); - geodetic_loc = pj_inv( projected_loc, P ); - if( P->ctx->last_errno != 0 ) - { - if( (P->ctx->last_errno != EDOM - && P->ctx->last_errno != ERANGE) - && (P->ctx->last_errno > 0 - || P->ctx->last_errno < -44 || n == 1 - || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) - { - return P->ctx->last_errno; - } - else - { - geodetic_loc.lam = HUGE_VAL; - geodetic_loc.phi = HUGE_VAL; - } - } - - x[dist*i] = geodetic_loc.lam; - y[dist*i] = geodetic_loc.phi; - } - return 0; -} - - - -/* -------------------------------------------------------------------- */ -/* Adjust for the prime meridian if needed. */ -/* -------------------------------------------------------------------- */ -static int prime_meridian (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x) { - int i; - double pm = P->from_greenwich; - - /* Nothing to do? */ - if (pm==0.0) - return 0; - if (!(P->is_geocent || P->is_latlong)) - return 0; - - if (dir==PJ_FWD) - pm = -pm; - - for (i = 0; i < n; i++) - if (x[dist*i] != HUGE_VAL) - x[dist*i] += pm; - - return 0; -} - - - -/* -------------------------------------------------------------------- */ -/* Adjust for vertical scale factor if needed */ -/* -------------------------------------------------------------------- */ -static int height_unit (PJ *P, PJ_DIRECTION dir, long n, int dist, double *z) { - int i; - double fac = P->vto_meter; - - if (PJ_FWD==dir) - fac = P->vfr_meter; - - /* Nothing to do? */ - if (fac==1.0) - return 0; - if (nullptr==z) - return 0; - if (P->is_latlong) - return 0; /* done in pj_inv3d() / pj_fwd3d() */ - - for (i = 0; i < n; i++) - if (z[dist*i] != HUGE_VAL ) - z[dist*i] *= fac; - - return 0; -} - - - -/* -------------------------------------------------------------------- */ -/* Transform to ellipsoidal heights if needed */ -/* -------------------------------------------------------------------- */ -static int geometric_to_orthometric (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { - int err; - if (0==P->has_geoid_vgrids) - return 0; - if (z==nullptr) - return PJD_ERR_GEOCENTRIC; - err = pj_apply_vgridshift (P, "sgeoidgrids", - &(P->vgridlist_geoid), - &(P->vgridlist_geoid_count), - dir==PJ_FWD ? 1 : 0, n, dist, x, y, z ); - if (err) - return pj_ctx_get_errno(P->ctx); - return 0; -} - - - -/* -------------------------------------------------------------------- */ -/* Convert datums if needed, and possible. */ -/* -------------------------------------------------------------------- */ -static int datum_transform (PJ *P, PJ *Q, long n, int dist, double *x, double *y, double *z) { - if (0==pj_datum_transform (P, Q, n, dist, x, y, z)) - return 0; - if (P->ctx->last_errno) - return P->ctx->last_errno; - return Q->ctx->last_errno; -} - - - - - -/* -------------------------------------------------------------------- */ -/* If a wrapping center other than 0 is provided, rewrap around */ -/* the suggested center (for latlong coordinate systems only). */ -/* -------------------------------------------------------------------- */ -static int long_wrap (PJ *P, long n, int dist, double *x) { - long i; - - /* Nothing to do? */ - if (P->is_geocent) - return 0; - if (!P->is_long_wrap_set) - return 0; - if (!P->is_latlong) - return 0; - - for (i = 0; i < n; i++ ) { - double val = x[dist*i]; - if (val == HUGE_VAL) - continue; - - /* Get fast in ] -2 PI, 2 PI [ range */ - val = fmod(val, M_TWOPI); - while( val < P->long_wrap_center - M_PI ) - val += M_TWOPI; - while( val > P->long_wrap_center + M_PI ) - val -= M_TWOPI; - x[dist*i] = val; - } - return 0; -} - - - -/************************************************************************/ -/* pj_transform() */ -/* */ -/* Currently this function doesn't recognise if two projections */ -/* are identical (to short circuit reprojection) because it is */ -/* difficult to compare PJ structures (since there are some */ -/* projection specific components). */ -/************************************************************************/ - -int pj_transform( - PJ *src, PJ *dst, - long point_count, int point_offset, - double *x, double *y, double *z -){ - int err; - - src->ctx->last_errno = 0; - dst->ctx->last_errno = 0; - - if( point_offset == 0 ) - point_offset = 1; - - /* Bring input to "normal form": longitude, latitude, ellipsoidal height */ - - err = adjust_axes (src, PJ_INV, point_count, point_offset, x, y, z); - if (err) - return err; - err = geographic_to_cartesian (src, PJ_INV, point_count, point_offset, x, y, z); - if (err) - return err; - err = projected_to_geographic (src, point_count, point_offset, x, y, z); - if (err) - return err; - err = prime_meridian (src, PJ_INV, point_count, point_offset, x); - if (err) - return err; - err = height_unit (src, PJ_INV, point_count, point_offset, z); - if (err) - return err; - err = geometric_to_orthometric (src, PJ_INV, point_count, point_offset, x, y, z); - if (err) - return err; - - /* At the center of the process we do the datum shift (if needed) */ - - err = datum_transform(src, dst, point_count, point_offset, x, y, z ); - if (err) - return err; - - /* Now get out on the other side: Bring "normal form" to output form */ - - err = geometric_to_orthometric (dst, PJ_FWD, point_count, point_offset, x, y, z); - if (err) - return err; - err = height_unit (dst, PJ_FWD, point_count, point_offset, z); - if (err) - return err; - err = prime_meridian (dst, PJ_FWD, point_count, point_offset, x); - if (err) - return err; - err = geographic_to_cartesian (dst, PJ_FWD, point_count, point_offset, x, y, z); - if (err) - return err; - err = geographic_to_projected (dst, point_count, point_offset, x, y, z); - if (err) - return err; - err = long_wrap (dst, point_count, point_offset, x); - if (err) - return err; - err = adjust_axes (dst, PJ_FWD, point_count, point_offset, x, y, z); - if (err) - return err; - - return 0; -} - - - -/************************************************************************/ -/* pj_geodetic_to_geocentric() */ -/************************************************************************/ - -int pj_geodetic_to_geocentric( double a, double es, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - double b; - int i; - GeocentricInfo gi; - int ret_errno = 0; - - if( es == 0.0 ) - b = a; - else - b = a * sqrt(1-es); - - if( pj_Set_Geocentric_Parameters( &gi, a, b ) != 0 ) - { - return PJD_ERR_GEOCENTRIC; - } - - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - - if( x[io] == HUGE_VAL ) - continue; - - if( pj_Convert_Geodetic_To_Geocentric( &gi, y[io], x[io], z[io], - x+io, y+io, z+io ) != 0 ) - { - ret_errno = PJD_ERR_LAT_OR_LON_EXCEED_LIMIT; - x[io] = y[io] = HUGE_VAL; - /* but keep processing points! */ - } - } - - return ret_errno; -} - -/************************************************************************/ -/* pj_geocentric_to_geodetic() */ -/************************************************************************/ - -int pj_geocentric_to_geodetic( double a, double es, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - double b; - int i; - GeocentricInfo gi; - - if( es == 0.0 ) - b = a; - else - b = a * sqrt(1-es); - - if( pj_Set_Geocentric_Parameters( &gi, a, b ) != 0 ) - { - return PJD_ERR_GEOCENTRIC; - } - - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - - if( x[io] == HUGE_VAL ) - continue; - - pj_Convert_Geocentric_To_Geodetic( &gi, x[io], y[io], z[io], - y+io, x+io, z+io ); - } - - return 0; -} - -/************************************************************************/ -/* pj_compare_datums() */ -/* */ -/* Returns TRUE if the two datums are identical, otherwise */ -/* FALSE. */ -/************************************************************************/ - -int pj_compare_datums( PJ *srcdefn, PJ *dstdefn ) - -{ - if( srcdefn->datum_type != dstdefn->datum_type ) - { - return 0; - } - else if( srcdefn->a_orig != dstdefn->a_orig - || ABS(srcdefn->es_orig - dstdefn->es_orig) > 0.000000000050 ) - { - /* the tolerance for es is to ensure that GRS80 and WGS84 are - considered identical */ - return 0; - } - else if( srcdefn->datum_type == PJD_3PARAM ) - { - return (srcdefn->datum_params[0] == dstdefn->datum_params[0] - && srcdefn->datum_params[1] == dstdefn->datum_params[1] - && srcdefn->datum_params[2] == dstdefn->datum_params[2]); - } - else if( srcdefn->datum_type == PJD_7PARAM ) - { - return (srcdefn->datum_params[0] == dstdefn->datum_params[0] - && srcdefn->datum_params[1] == dstdefn->datum_params[1] - && srcdefn->datum_params[2] == dstdefn->datum_params[2] - && srcdefn->datum_params[3] == dstdefn->datum_params[3] - && srcdefn->datum_params[4] == dstdefn->datum_params[4] - && srcdefn->datum_params[5] == dstdefn->datum_params[5] - && srcdefn->datum_params[6] == dstdefn->datum_params[6]); - } - else if( srcdefn->datum_type == PJD_GRIDSHIFT ) - { - const char* srcnadgrids = - pj_param(srcdefn->ctx, srcdefn->params,"snadgrids").s; - const char* dstnadgrids = - pj_param(dstdefn->ctx, dstdefn->params,"snadgrids").s; - return srcnadgrids != nullptr && dstnadgrids != nullptr && - strcmp( srcnadgrids, dstnadgrids ) == 0; - } - else - return 1; -} - -/************************************************************************/ -/* pj_geocentic_to_wgs84() */ -/************************************************************************/ - -static -int pj_geocentric_to_wgs84( PJ *defn, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - int i; - - if( defn->datum_type == PJD_3PARAM ) - { - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - - if( x[io] == HUGE_VAL ) - continue; - - x[io] = x[io] + Dx_BF; - y[io] = y[io] + Dy_BF; - z[io] = z[io] + Dz_BF; - } - } - else if( defn->datum_type == PJD_7PARAM ) - { - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - double x_out, y_out, z_out; - - if( x[io] == HUGE_VAL ) - continue; - - x_out = M_BF*( x[io] - Rz_BF*y[io] + Ry_BF*z[io]) + Dx_BF; - y_out = M_BF*( Rz_BF*x[io] + y[io] - Rx_BF*z[io]) + Dy_BF; - z_out = M_BF*(-Ry_BF*x[io] + Rx_BF*y[io] + z[io]) + Dz_BF; - - x[io] = x_out; - y[io] = y_out; - z[io] = z_out; - } - } - - return 0; -} - -/************************************************************************/ -/* pj_geocentic_from_wgs84() */ -/************************************************************************/ - -static -int pj_geocentric_from_wgs84( PJ *defn, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - int i; - - if( defn->datum_type == PJD_3PARAM ) - { - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - - if( x[io] == HUGE_VAL ) - continue; - - x[io] = x[io] - Dx_BF; - y[io] = y[io] - Dy_BF; - z[io] = z[io] - Dz_BF; - } - } - else if( defn->datum_type == PJD_7PARAM ) - { - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - double x_tmp, y_tmp, z_tmp; - - if( x[io] == HUGE_VAL ) - continue; - - x_tmp = (x[io] - Dx_BF) / M_BF; - y_tmp = (y[io] - Dy_BF) / M_BF; - z_tmp = (z[io] - Dz_BF) / M_BF; - - x[io] = x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp; - y[io] = -Rz_BF*x_tmp + y_tmp + Rx_BF*z_tmp; - z[io] = Ry_BF*x_tmp - Rx_BF*y_tmp + z_tmp; - } - } - - return 0; -} - -/************************************************************************/ -/* pj_datum_transform() */ -/* */ -/* The input should be long/lat/z coordinates in radians in the */ -/* source datum, and the output should be long/lat/z */ -/* coordinates in radians in the destination datum. */ -/************************************************************************/ - -int pj_datum_transform( PJ *src, PJ *dst, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - double src_a, src_es, dst_a, dst_es; - int z_is_temp = FALSE; - -/* -------------------------------------------------------------------- */ -/* We cannot do any meaningful datum transformation if either */ -/* the source or destination are of an unknown datum type */ -/* (ie. only a +ellps declaration, no +datum). This is new */ -/* behavior for PROJ 4.6.0. */ -/* -------------------------------------------------------------------- */ - if( src->datum_type == PJD_UNKNOWN - || dst->datum_type == PJD_UNKNOWN ) - return 0; - -/* -------------------------------------------------------------------- */ -/* Short cut if the datums are identical. */ -/* -------------------------------------------------------------------- */ - if( pj_compare_datums( src, dst ) ) - return 0; - - src_a = src->a_orig; - src_es = src->es_orig; - - dst_a = dst->a_orig; - dst_es = dst->es_orig; - -/* -------------------------------------------------------------------- */ -/* Create a temporary Z array if one is not provided. */ -/* -------------------------------------------------------------------- */ - if( z == nullptr ) - { - size_t bytes = sizeof(double) * point_count * point_offset; - z = (double *) pj_malloc(bytes); - memset( z, 0, bytes ); - z_is_temp = TRUE; - } - -#define CHECK_RETURN(defn) {if( defn->ctx->last_errno != 0 && (defn->ctx->last_errno > 0 || get_transient_error_value(-defn->ctx->last_errno) == 0) ) { if( z_is_temp ) pj_dalloc(z); return defn->ctx->last_errno; }} - -/* -------------------------------------------------------------------- */ -/* If this datum requires grid shifts, then apply it to geodetic */ -/* coordinates. */ -/* -------------------------------------------------------------------- */ - if( src->datum_type == PJD_GRIDSHIFT ) - { - pj_apply_gridshift_2( src, 0, point_count, point_offset, x, y, z ); - CHECK_RETURN(src); - - src_a = SRS_WGS84_SEMIMAJOR; - src_es = SRS_WGS84_ESQUARED; - } - - if( dst->datum_type == PJD_GRIDSHIFT ) - { - dst_a = SRS_WGS84_SEMIMAJOR; - dst_es = SRS_WGS84_ESQUARED; - } - -/* ==================================================================== */ -/* Do we need to go through geocentric coordinates? */ -/* ==================================================================== */ - if( src_es != dst_es || src_a != dst_a - || src->datum_type == PJD_3PARAM - || src->datum_type == PJD_7PARAM - || dst->datum_type == PJD_3PARAM - || dst->datum_type == PJD_7PARAM) - { -/* -------------------------------------------------------------------- */ -/* Convert to geocentric coordinates. */ -/* -------------------------------------------------------------------- */ - src->ctx->last_errno = - pj_geodetic_to_geocentric( src_a, src_es, - point_count, point_offset, x, y, z ); - CHECK_RETURN(src); - -/* -------------------------------------------------------------------- */ -/* Convert between datums. */ -/* -------------------------------------------------------------------- */ - if( src->datum_type == PJD_3PARAM - || src->datum_type == PJD_7PARAM ) - { - pj_geocentric_to_wgs84( src, point_count, point_offset,x,y,z); - CHECK_RETURN(src); - } - - if( dst->datum_type == PJD_3PARAM - || dst->datum_type == PJD_7PARAM ) - { - pj_geocentric_from_wgs84( dst, point_count,point_offset,x,y,z); - CHECK_RETURN(dst); - } - -/* -------------------------------------------------------------------- */ -/* Convert back to geodetic coordinates. */ -/* -------------------------------------------------------------------- */ - dst->ctx->last_errno = - pj_geocentric_to_geodetic( dst_a, dst_es, - point_count, point_offset, x, y, z ); - CHECK_RETURN(dst); - } - -/* -------------------------------------------------------------------- */ -/* Apply grid shift to destination if required. */ -/* -------------------------------------------------------------------- */ - if( dst->datum_type == PJD_GRIDSHIFT ) - { - pj_apply_gridshift_2( dst, 1, point_count, point_offset, x, y, z ); - CHECK_RETURN(dst); - } - - if( z_is_temp ) - pj_dalloc( z ); - - return 0; -} - -/************************************************************************/ -/* adjust_axis() */ -/* */ -/* Normalize or de-normalized the x/y/z axes. The normal form */ -/* is "enu" (easting, northing, up). */ -/************************************************************************/ -static int adjust_axis( projCtx ctx, - const char *axis, int denormalize_flag, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - double x_in, y_in, z_in = 0.0; - int i, i_axis; - - if( !denormalize_flag ) - { - for( i = 0; i < point_count; i++ ) - { - x_in = x[point_offset*i]; - y_in = y[point_offset*i]; - if( z ) - z_in = z[point_offset*i]; - - for( i_axis = 0; i_axis < 3; i_axis++ ) - { - double value; - - if( i_axis == 0 ) - value = x_in; - else if( i_axis == 1 ) - value = y_in; - else - value = z_in; - - switch( axis[i_axis] ) - { - case 'e': - x[point_offset*i] = value; - break; - case 'w': - x[point_offset*i] = -value; - break; - case 'n': - y[point_offset*i] = value; - break; - case 's': - y[point_offset*i] = -value; - break; - case 'u': - if( z ) - z[point_offset*i] = value; - break; - case 'd': - if( z ) - z[point_offset*i] = -value; - break; - default: - pj_ctx_set_errno( ctx, PJD_ERR_AXIS ); - return PJD_ERR_AXIS; - } - } /* i_axis */ - } /* i (point) */ - } - - else /* denormalize */ - { - for( i = 0; i < point_count; i++ ) - { - x_in = x[point_offset*i]; - y_in = y[point_offset*i]; - if( z ) - z_in = z[point_offset*i]; - - for( i_axis = 0; i_axis < 3; i_axis++ ) - { - double *target; - - if( i_axis == 2 && z == nullptr ) - continue; - - if( i_axis == 0 ) - target = x; - else if( i_axis == 1 ) - target = y; - else - target = z; - - switch( axis[i_axis] ) - { - case 'e': - target[point_offset*i] = x_in; break; - case 'w': - target[point_offset*i] = -x_in; break; - case 'n': - target[point_offset*i] = y_in; break; - case 's': - target[point_offset*i] = -y_in; break; - case 'u': - target[point_offset*i] = z_in; break; - case 'd': - target[point_offset*i] = -z_in; break; - default: - pj_ctx_set_errno( ctx, PJD_ERR_AXIS ); - return PJD_ERR_AXIS; - } - } /* i_axis */ - } /* i (point) */ - } - - return 0; -} diff --git a/src/pj_tsfn.cpp b/src/pj_tsfn.cpp deleted file mode 100644 index ea3b896d..00000000 --- a/src/pj_tsfn.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* determine small t */ -#include -#include "projects.h" - -double pj_tsfn(double phi, double sinphi, double e) { - double denominator; - sinphi *= e; - - /* avoid zero division, fail gracefully */ - denominator = 1.0 + sinphi; - if (denominator == 0.0) - return HUGE_VAL; - - return (tan (.5 * (M_HALFPI - phi)) / - pow((1. - sinphi) / (denominator), .5 * e)); -} diff --git a/src/pj_units.cpp b/src/pj_units.cpp deleted file mode 100644 index 50f11396..00000000 --- a/src/pj_units.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* definition of standard cartesian units */ - -#include - -#include "proj.h" - -#define PJ_UNITS__ -#include "projects.h" - -/* Field 2 that contains the multiplier to convert named units to meters -** may be expressed by either a simple floating point constant or a -** numerator/denomenator values (e.g. 1/1000) */ -static const struct PJ_UNITS -pj_units[] = { - {"km", "1000", "Kilometer", 1000.0}, - {"m", "1", "Meter", 1.0}, - {"dm", "1/10", "Decimeter", 0.1}, - {"cm", "1/100", "Centimeter", 0.01}, - {"mm", "1/1000", "Millimeter", 0.001}, - {"kmi", "1852", "International Nautical Mile", 1852.0}, - {"in", "0.0254", "International Inch", 0.0254}, - {"ft", "0.3048", "International Foot", 0.3048}, - {"yd", "0.9144", "International Yard", 0.9144}, - {"mi", "1609.344", "International Statute Mile", 1609.344}, - {"fath", "1.8288", "International Fathom", 1.8288}, - {"ch", "20.1168", "International Chain", 20.1168}, - {"link", "0.201168", "International Link", 0.201168}, - {"us-in", "1/39.37", "U.S. Surveyor's Inch", 100/3937.0}, - {"us-ft", "0.304800609601219", "U.S. Surveyor's Foot", 1200/3937.0}, - {"us-yd", "0.914401828803658", "U.S. Surveyor's Yard", 3600/3937.0}, - {"us-ch", "20.11684023368047", "U.S. Surveyor's Chain", 79200/3937.0}, - {"us-mi", "1609.347218694437", "U.S. Surveyor's Statute Mile", 6336000/3937.0}, - {"ind-yd", "0.91439523", "Indian Yard", 0.91439523}, - {"ind-ft", "0.30479841", "Indian Foot", 0.30479841}, - {"ind-ch", "20.11669506", "Indian Chain", 20.11669506}, - {nullptr, nullptr, nullptr, 0.0} -}; - -const PJ_UNITS *proj_list_units() -{ - return pj_units; -} - -/* M_PI / 200 */ -#define GRAD_TO_RAD 0.015707963267948967 - -const struct PJ_UNITS -pj_angular_units[] = { - {"rad", "1.0", "Radian", 1.0}, - {"deg", "0.017453292519943296", "Degree", DEG_TO_RAD}, - {"grad", "0.015707963267948967", "Grad", GRAD_TO_RAD}, - {nullptr, nullptr, nullptr, 0.0} -}; - -const PJ_UNITS *proj_list_angular_units() -{ - return pj_angular_units; -} diff --git a/src/pj_utils.cpp b/src/pj_utils.cpp deleted file mode 100644 index 8587dc30..00000000 --- a/src/pj_utils.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Some utility functions we don't want to bother putting in - * their own source files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2001, 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. - *****************************************************************************/ - -#define PJ_LIB__ - -#include -#include - -#include "projects.h" - -/************************************************************************/ -/* pj_is_latlong() */ -/* */ -/* Returns TRUE if this coordinate system object is */ -/* geographic. */ -/************************************************************************/ - -int pj_is_latlong( PJ *pj ) - -{ - return pj == nullptr || pj->is_latlong; -} - -/************************************************************************/ -/* pj_is_geocent() */ -/* */ -/* Returns TRUE if this coordinate system object is geocentric. */ -/************************************************************************/ - -int pj_is_geocent( PJ *pj ) - -{ - return pj != nullptr && pj->is_geocent; -} - -/************************************************************************/ -/* pj_latlong_from_proj() */ -/* */ -/* Return a PJ* definition defining the lat/long coordinate */ -/* system on which a projection is based. If the coordinate */ -/* system passed in is latlong, a clone of the same will be */ -/* returned. */ -/************************************************************************/ - -PJ *pj_latlong_from_proj( PJ *pj_in ) - -{ - char defn[512]; - int got_datum = FALSE; - - pj_errno = 0; - strcpy( defn, "+proj=latlong" ); - - if( pj_param(pj_in->ctx, pj_in->params, "tdatum").i ) - { - got_datum = TRUE; - sprintf( defn+strlen(defn), " +datum=%s", - pj_param(pj_in->ctx, pj_in->params,"sdatum").s ); - } - else if( pj_param(pj_in->ctx, pj_in->params, "tellps").i ) - { - sprintf( defn+strlen(defn), " +ellps=%s", - pj_param(pj_in->ctx, pj_in->params,"sellps").s ); - } - else if( pj_param(pj_in->ctx,pj_in->params, "ta").i ) - { - sprintf( defn+strlen(defn), " +a=%s", - pj_param(pj_in->ctx,pj_in->params,"sa").s ); - - if( pj_param(pj_in->ctx,pj_in->params, "tb").i ) - sprintf( defn+strlen(defn), " +b=%s", - pj_param(pj_in->ctx,pj_in->params,"sb").s ); - else if( pj_param(pj_in->ctx,pj_in->params, "tes").i ) - sprintf( defn+strlen(defn), " +es=%s", - pj_param(pj_in->ctx,pj_in->params,"ses").s ); - else if( pj_param(pj_in->ctx,pj_in->params, "tf").i ) - sprintf( defn+strlen(defn), " +f=%s", - pj_param(pj_in->ctx,pj_in->params,"sf").s ); - else - { - char* ptr = defn+strlen(defn); - sprintf( ptr, " +es=%.16g", pj_in->es ); - /* TODO later: use C++ ostringstream with imbue(std::locale::classic()) */ - /* to be locale unaware */ - for(; *ptr; ptr++) - { - if( *ptr == ',' ) - *ptr = '.'; - } - } - } - else - { - pj_ctx_set_errno( pj_in->ctx, PJD_ERR_MAJOR_AXIS_NOT_GIVEN ); - - return nullptr; - } - - if( !got_datum ) - { - if( pj_param(pj_in->ctx,pj_in->params, "ttowgs84").i ) - sprintf( defn+strlen(defn), " +towgs84=%s", - pj_param(pj_in->ctx,pj_in->params,"stowgs84").s ); - - if( pj_param(pj_in->ctx,pj_in->params, "tnadgrids").i ) - sprintf( defn+strlen(defn), " +nadgrids=%s", - pj_param(pj_in->ctx,pj_in->params,"snadgrids").s ); - } - - /* copy over some other information related to ellipsoid */ - if( pj_param(pj_in->ctx,pj_in->params, "tR").i ) - sprintf( defn+strlen(defn), " +R=%s", - pj_param(pj_in->ctx,pj_in->params,"sR").s ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_A").i ) - sprintf( defn+strlen(defn), " +R_A" ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_V").i ) - sprintf( defn+strlen(defn), " +R_V" ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_a").i ) - sprintf( defn+strlen(defn), " +R_a" ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_a").i ) - sprintf( defn+strlen(defn), " +R_lat_a=%s", - pj_param(pj_in->ctx,pj_in->params,"sR_lat_a").s ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_g").i ) - sprintf( defn+strlen(defn), " +R_lat_g=%s", - pj_param(pj_in->ctx,pj_in->params,"sR_lat_g").s ); - - /* copy over prime meridian */ - if( pj_param(pj_in->ctx,pj_in->params, "tpm").i ) - sprintf( defn+strlen(defn), " +pm=%s", - pj_param(pj_in->ctx,pj_in->params,"spm").s ); - - return pj_init_plus_ctx( pj_in->ctx, defn ); -} - -/************************************************************************/ -/* pj_get_spheroid_defn() */ -/* */ -/* Fetch the internal definition of the spheroid. Note that */ -/* you can compute "b" from eccentricity_squared as: */ -/* */ -/* b = a * sqrt(1 - es) */ -/************************************************************************/ - -void pj_get_spheroid_defn(projPJ defn, double *major_axis, double *eccentricity_squared) -{ - if ( major_axis ) - *major_axis = defn->a; - - if ( eccentricity_squared ) - *eccentricity_squared = defn->es; -} diff --git a/src/pj_wkt1_generated_parser.c b/src/pj_wkt1_generated_parser.c deleted file mode 100644 index 91d5e60d..00000000 --- a/src/pj_wkt1_generated_parser.c +++ /dev/null @@ -1,1664 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ - -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "3.0.4" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 1 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - - -/* Substitute the variable and function names. */ -#define yyparse pj_wkt1_parse -#define yylex pj_wkt1_lex -#define yyerror pj_wkt1_error -#define yydebug pj_wkt1_debug -#define yynerrs pj_wkt1_nerrs - - -/* Copy the first part of user declarations. */ - - -/****************************************************************************** - * Project: PROJ - * Purpose: WKT1 parser grammar - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2013-2018 Even Rouault, - * - * 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. - ****************************************************************************/ - -#include "pj_wkt1_parser.h" - - - - -# ifndef YY_NULLPTR -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULLPTR nullptr -# else -# define YY_NULLPTR 0 -# endif -# endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 1 -#endif - -/* In a future release of Bison, this section will be replaced - by #include "pj_wkt1_generated_parser.h". */ -#ifndef YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED -# define YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int pj_wkt1_debug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - END = 0, - T_PARAM_MT = 258, - T_CONCAT_MT = 259, - T_INVERSE_MT = 260, - T_PASSTHROUGH_MT = 261, - T_PROJCS = 262, - T_PROJECTION = 263, - T_GEOGCS = 264, - T_DATUM = 265, - T_SPHEROID = 266, - T_PRIMEM = 267, - T_UNIT = 268, - T_GEOCCS = 269, - T_AUTHORITY = 270, - T_VERT_CS = 271, - T_VERT_DATUM = 272, - T_COMPD_CS = 273, - T_AXIS = 274, - T_TOWGS84 = 275, - T_FITTED_CS = 276, - T_LOCAL_CS = 277, - T_LOCAL_DATUM = 278, - T_PARAMETER = 279, - T_EXTENSION = 280, - T_STRING = 281, - T_NUMBER = 282, - T_IDENTIFIER = 283 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef int YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - - -int pj_wkt1_parse (pj_wkt1_parse_context *context); - -#endif /* !YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED */ - -/* Copy the second part of user declarations. */ - - - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#else -typedef signed char yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) -# endif -# endif -# ifndef YY_ -# define YY_(Msgid) Msgid -# endif -#endif - -#ifndef YY_ATTRIBUTE -# if (defined __GNUC__ \ - && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ - || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C -# define YY_ATTRIBUTE(Spec) __attribute__(Spec) -# else -# define YY_ATTRIBUTE(Spec) /* empty */ -# endif -#endif - -#ifndef YY_ATTRIBUTE_PURE -# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) -#endif - -#ifndef YY_ATTRIBUTE_UNUSED -# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) -#endif - -#if !defined _Noreturn \ - && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) -# if defined _MSC_VER && 1200 <= _MSC_VER -# define _Noreturn __declspec (noreturn) -# else -# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) -#else -# define YYUSE(E) /* empty */ -#endif - -#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ -/* Suppress an incorrect diagnostic about yylval being uninitialized. */ -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ - _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ - _Pragma ("GCC diagnostic pop") -#else -# define YY_INITIAL_VALUE(Value) Value -#endif -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS -# include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's 'empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (0) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 28 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 215 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 34 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 66 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 99 -/* YYNSTATES -- Number of states. */ -#define YYNSTATES 257 - -/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned - by yylex, with out-of-bounds checking. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 283 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM - as returned by yylex, without out-of-bounds checking. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 30, 32, 2, 2, 33, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 29, 2, 31, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28 -}; - -#if YYDEBUG - /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 76, 76, 88, 88, 91, 94, 94, 97, 97, - 97, 97, 100, 103, 105, 106, 109, 111, 112, 115, - 118, 122, 127, 127, 127, 127, 127, 127, 130, 130, - 134, 138, 139, 142, 143, 145, 146, 147, 148, 150, - 151, 154, 157, 160, 164, 166, 167, 168, 169, 172, - 176, 179, 182, 185, 188, 191, 194, 197, 200, 203, - 204, 205, 206, 209, 212, 215, 217, 218, 219, 222, - 224, 225, 226, 229, 232, 235, 238, 240, 243, 248, - 251, 253, 256, 259, 262, 265, 268, 271, 274, 277, - 280, 283, 286, 289, 292, 294, 296, 297, 298, 301 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || 1 -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "\"end of string\"", "error", "$undefined", "\"PARAM_MT\"", - "\"CONCAT_MT\"", "\"INVERSE_MT\"", "\"PASSTHROUGH_MT\"", "\"PROJCS\"", - "\"PROJECTION\"", "\"GEOGCS\"", "\"DATUM\"", "\"SPHEROID\"", - "\"PRIMEM\"", "\"UNIT\"", "\"GEOCCS\"", "\"AUTHORITY\"", "\"VERT_CS\"", - "\"VERT_DATUM\"", "\"COMPD_CS\"", "\"AXIS\"", "\"TOWGS84\"", - "\"FITTED_CS\"", "\"LOCAL_CS\"", "\"LOCAL_DATUM\"", "\"PARAMETER\"", - "\"EXTENSION\"", "\"string\"", "\"number\"", "\"identifier\"", "'['", - "'('", "']'", "')'", "','", "$accept", "input", "begin_node", - "begin_node_name", "end_node", "math_transform", "param_mt", "parameter", - "opt_parameter_list", "concat_mt", "opt_math_transform_list", "inv_mt", - "passthrough_mt", "integer", "coordinate_system", "horz_cs", - "projected_cs", "opt_parameter_list_linear_unit", - "parameter_list_linear_unit", "opt_twin_axis_extension_authority", - "opt_authority", "extension", "projection", "geographic_cs", "datum", - "opt_towgs84_authority_extension", "spheroid", "semi_major_axis", - "inverse_flattening", "prime_meridian", "longitude", "angular_unit", - "linear_unit", "unit", "conversion_factor", "geocentric_cs", - "opt_three_axis_extension_authority", "three_axis", "authority", - "vert_cs", "opt_axis_authority", "vert_datum", "opt_extension_authority", - "datum_type", "compd_cs", "head_cs", "tail_cs", "twin_axis", "axis", - "towgs84", "towgs84_parameters", "three_parameters", "seven_parameters", - "dx", "dy", "dz", "ex", "ey", "ez", "ppm", "fitted_cs", "to_base", - "base_cs", "local_cs", "opt_axis_list_authority", "local_datum", YY_NULLPTR -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[NUM] -- (External) token number corresponding to the - (internal) symbol number NUM (which must be that of a token). */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 91, - 40, 93, 41, 44 -}; -# endif - -#define YYPACT_NINF -127 - -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-127))) - -#define YYTABLE_NINF -1 - -#define yytable_value_is_error(Yytable_value) \ - 0 - - /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -static const yytype_int16 yypact[] = -{ - 136, 2, 2, 2, 2, 2, 2, 2, 26, -127, - -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, - 11, 5, 18, 32, 36, 40, 42, 53, -127, -127, - 35, 66, 66, 61, 136, 85, -127, -127, 59, -127, - 67, 2, 68, 69, 2, 70, -127, 72, 2, 2, - 2, 2, -127, -127, -127, -127, -127, 76, 2, 77, - 84, 79, 87, 87, 82, 105, 136, 88, 85, 85, - 93, 136, 89, 105, 2, 90, 113, 2, 95, 96, - 103, 2, 98, -127, -127, 99, 109, 25, 101, 25, - -127, 107, -127, 25, 103, 111, 114, 1, 2, 115, - 120, 105, 105, -127, 99, 122, 14, 25, 34, 25, - 2, 88, -127, 85, 25, -127, 85, -127, 114, 119, - 141, 25, 126, 127, -127, -127, 128, 15, 25, 135, - 127, -127, 130, 25, 137, 2, 2, -127, 114, -127, - 2, 114, -127, -127, 132, -127, 101, -127, 25, 25, - 133, -127, -127, 1, 33, 25, 140, 2, 114, -127, - 99, -127, -127, 114, 25, 33, 25, -127, -127, 114, - 138, 139, -127, 142, -127, 143, -127, -127, -127, 14, - 25, -127, -127, 114, -127, 99, 144, -127, -127, 145, - 146, -127, -127, 25, -127, 114, 99, -127, 147, -127, - 25, 148, 151, 150, 25, -127, 133, -127, -127, -127, - 119, 154, -127, 25, -127, -127, 149, -127, -127, -127, - 119, -127, 25, 25, 25, -127, -127, -127, -127, 114, - -127, 156, 153, -127, -127, -127, 25, -127, 155, 119, - -127, 157, -127, -127, 158, 160, -127, 159, 162, -127, - 161, 163, -127, 164, 166, -127, -127 -}; - - /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE does not specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, - 22, 29, 28, 23, 24, 25, 26, 27, 3, 4, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, - 0, 0, 0, 0, 0, 0, 6, 7, 0, 95, - 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, - 0, 0, 92, 8, 9, 10, 11, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 66, 55, 76, 70, 0, 0, 17, 0, - 21, 0, 93, 0, 0, 0, 39, 0, 0, 45, - 0, 0, 0, 73, 70, 0, 0, 0, 0, 0, - 0, 14, 12, 0, 0, 19, 0, 91, 39, 0, - 0, 0, 0, 35, 32, 31, 0, 0, 0, 0, - 35, 54, 59, 0, 0, 0, 0, 68, 39, 65, - 0, 39, 72, 74, 0, 15, 17, 16, 0, 0, - 96, 40, 42, 0, 0, 0, 0, 0, 39, 48, - 70, 44, 53, 39, 0, 0, 0, 69, 57, 39, - 0, 0, 67, 0, 71, 0, 18, 20, 99, 0, - 0, 33, 34, 39, 38, 70, 0, 30, 50, 0, - 0, 47, 46, 0, 43, 39, 70, 62, 0, 58, - 0, 0, 0, 0, 0, 97, 96, 94, 37, 36, - 0, 0, 84, 0, 81, 80, 0, 52, 61, 60, - 0, 56, 0, 0, 0, 13, 98, 77, 51, 39, - 79, 0, 0, 64, 78, 41, 0, 85, 0, 0, - 49, 0, 63, 86, 82, 0, 87, 0, 0, 88, - 0, 0, 89, 0, 0, 90, 83 -}; - - /* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -127, -127, -46, 6, -87, -50, -127, 83, 57, -127, - 49, -127, -127, -127, -11, -127, -127, -127, 43, 71, - -44, -126, -127, 168, 167, -127, -127, -127, -127, 152, - -127, -127, -81, -56, -127, -127, -127, -127, -84, -127, - -127, -127, -89, 106, -127, -127, -127, -127, -112, -127, - -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, - -127, -127, -127, -127, -4, -127 -}; - - /* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 8, 20, 21, 39, 52, 53, 122, 87, 54, - 114, 55, 56, 91, 9, 10, 11, 123, 124, 155, - 121, 141, 75, 12, 42, 128, 99, 189, 229, 78, - 163, 130, 82, 83, 169, 13, 166, 196, 137, 14, - 107, 45, 109, 104, 15, 47, 85, 185, 138, 160, - 213, 214, 215, 216, 238, 244, 247, 250, 253, 256, - 16, 57, 93, 17, 180, 59 -}; - - /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule whose - number is the opposite. If YYTABLE_NINF, syntax error. */ -static const yytype_uint8 yytable[] = -{ - 112, 158, 115, 68, 69, 70, 117, 150, 22, 23, - 24, 25, 26, 27, 81, 133, 125, 95, 88, 89, - 139, 132, 143, 46, 142, 110, 28, 147, 183, 135, - 135, 18, 19, 136, 152, 157, 151, 29, 30, 195, - 140, 161, 186, 159, 2, 131, 167, 61, 135, 135, - 64, 31, 136, 198, 67, 84, 36, 37, 140, 140, - 92, 177, 178, 146, 72, 32, 148, 206, 187, 33, - 184, 192, 182, 34, 149, 35, 41, 194, 44, 199, - 96, 197, 58, 100, 36, 37, 38, 105, 48, 49, - 50, 51, 74, 207, 172, 205, 209, 174, 227, 77, - 60, 62, 63, 65, 126, 66, 217, 219, 232, 71, - 73, 190, 76, 221, 191, 80, 144, 225, 81, 193, - 90, 86, 94, 97, 98, 200, 230, 242, 101, 102, - 103, 106, 108, 110, 113, 233, 234, 235, 136, 208, - 116, 170, 171, 1, 119, 2, 173, 120, 127, 240, - 3, 218, 4, 129, 5, 134, 135, 6, 7, 153, - 154, 156, 162, 165, 168, 175, 179, 188, 145, 111, - 204, 201, 202, 212, 222, 203, 224, 210, 211, 223, - 220, 228, 231, 237, 243, 236, 239, 246, 241, 249, - 252, 245, 248, 255, 251, 176, 181, 254, 40, 43, - 118, 164, 226, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 79 -}; - -static const yytype_int16 yycheck[] = -{ - 87, 127, 89, 49, 50, 51, 93, 119, 2, 3, - 4, 5, 6, 7, 13, 104, 97, 73, 68, 69, - 107, 102, 109, 34, 108, 24, 0, 114, 154, 15, - 15, 29, 30, 19, 121, 20, 120, 26, 33, 165, - 25, 128, 154, 127, 9, 101, 133, 41, 15, 15, - 44, 33, 19, 165, 48, 66, 31, 32, 25, 25, - 71, 148, 149, 113, 58, 33, 116, 179, 155, 33, - 154, 160, 153, 33, 118, 33, 10, 164, 17, 166, - 74, 165, 23, 77, 31, 32, 33, 81, 3, 4, - 5, 6, 8, 180, 138, 179, 185, 141, 210, 12, - 33, 33, 33, 33, 98, 33, 193, 196, 220, 33, - 33, 157, 33, 200, 158, 33, 110, 204, 13, 163, - 27, 33, 33, 33, 11, 169, 213, 239, 33, 33, - 27, 33, 33, 24, 33, 222, 223, 224, 19, 183, - 33, 135, 136, 7, 33, 9, 140, 33, 33, 236, - 14, 195, 16, 33, 18, 33, 15, 21, 22, 33, - 33, 33, 27, 33, 27, 33, 33, 27, 111, 86, - 27, 33, 33, 27, 26, 33, 26, 33, 33, 28, - 33, 27, 33, 27, 27, 229, 33, 27, 33, 27, - 27, 33, 33, 27, 33, 146, 153, 33, 30, 32, - 94, 130, 206, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 63 -}; - - /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 7, 9, 14, 16, 18, 21, 22, 35, 48, - 49, 50, 57, 69, 73, 78, 94, 97, 29, 30, - 36, 37, 37, 37, 37, 37, 37, 37, 0, 26, - 33, 33, 33, 33, 33, 33, 31, 32, 33, 38, - 57, 10, 58, 58, 17, 75, 48, 79, 3, 4, - 5, 6, 39, 40, 43, 45, 46, 95, 23, 99, - 33, 37, 33, 33, 37, 33, 33, 37, 36, 36, - 36, 33, 37, 33, 8, 56, 33, 12, 63, 63, - 33, 13, 66, 67, 48, 80, 33, 42, 39, 39, - 27, 47, 48, 96, 33, 67, 37, 33, 11, 60, - 37, 33, 33, 27, 77, 37, 33, 74, 33, 76, - 24, 41, 38, 33, 44, 38, 33, 38, 77, 33, - 33, 54, 41, 51, 52, 66, 37, 33, 59, 33, - 65, 67, 66, 76, 33, 15, 19, 72, 82, 38, - 25, 55, 72, 38, 37, 42, 39, 38, 39, 54, - 82, 72, 38, 33, 33, 53, 33, 20, 55, 72, - 83, 38, 27, 64, 53, 33, 70, 38, 27, 68, - 37, 37, 54, 37, 54, 33, 44, 38, 38, 33, - 98, 52, 66, 55, 72, 81, 82, 38, 27, 61, - 36, 54, 76, 54, 38, 55, 71, 72, 82, 38, - 54, 33, 33, 33, 27, 72, 82, 38, 54, 76, - 33, 33, 27, 84, 85, 86, 87, 38, 54, 76, - 33, 38, 26, 28, 26, 38, 98, 82, 27, 62, - 38, 33, 82, 38, 38, 38, 54, 27, 88, 33, - 38, 33, 82, 27, 89, 33, 27, 90, 33, 27, - 91, 33, 27, 92, 33, 27, 93 -}; - - /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 34, 35, 36, 36, 37, 38, 38, 39, 39, - 39, 39, 40, 41, 42, 42, 43, 44, 44, 45, - 46, 47, 48, 48, 48, 48, 48, 48, 49, 49, - 50, 51, 51, 52, 52, 53, 53, 53, 53, 54, - 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 70, 70, 70, 71, 72, 73, 74, 74, 74, 75, - 76, 76, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 97, 98, 98, 98, 99 -}; - - /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 1, 1, 1, 2, 1, 1, 1, 1, - 1, 1, 4, 5, 0, 3, 5, 0, 3, 4, - 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 10, 1, 1, 3, 3, 0, 3, 3, 2, 0, - 2, 5, 4, 10, 6, 0, 3, 3, 2, 8, - 1, 1, 6, 1, 1, 1, 6, 1, 10, 0, - 3, 3, 2, 5, 5, 8, 0, 3, 2, 6, - 0, 3, 2, 1, 8, 1, 1, 3, 5, 4, - 1, 1, 5, 13, 1, 1, 1, 1, 1, 1, - 1, 7, 1, 1, 10, 3, 0, 2, 3, 6 -}; - - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (context, YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (0) - -/* Error token number */ -#define YYTERROR 1 -#define YYERRCODE 256 - - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - -/* This macro is provided for backward compatibility. */ -#ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -#endif - - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value, context); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - - -/*----------------------------------------. -| Print this symbol's value on YYOUTPUT. | -`----------------------------------------*/ - -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt1_parse_context *context) -{ - FILE *yyo = yyoutput; - YYUSE (yyo); - YYUSE (context); - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - YYUSE (yytype); -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt1_parse_context *context) -{ - YYFPRINTF (yyoutput, "%s %s (", - yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep, context); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -static void -yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, pj_wkt1_parse_context *context) -{ - unsigned long int yylno = yyrline[yyrule]; - int yynrhs = yyr2[yyrule]; - int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, - yystos[yyssp[yyi + 1 - yynrhs]], - &(yyvsp[(yyi + 1) - (yynrhs)]) - , context); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyssp, yyvsp, Rule, context); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -yystrlen (const char *yystr) -{ - YYSIZE_T yylen; - for (yylen = 0; yystr && yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -yystpcpy (char *yydest, const char *yysrc) -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) -{ - YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = YY_NULLPTR; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } - } - - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } - - { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } - - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; -} -#endif /* YYERROR_VERBOSE */ - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, pj_wkt1_parse_context *context) -{ - YYUSE (yyvaluep); - YYUSE (context); - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yytype); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - - - -/*----------. -| yyparse. | -`----------*/ - -int -yyparse (pj_wkt1_parse_context *context) -{ -/* The lookahead symbol. */ -int yychar; - - -/* The semantic value of the lookahead symbol. */ -/* Default value used for initialization, for pacifying older GCCs - or non-GCC compilers. */ -YY_INITIAL_VALUE (static YYSTYPE yyval_default;) -YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); - - /* Number of syntax errors so far. */ - int yynerrs; - - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - 'yyss': related to states. - 'yyvs': related to semantic values. - - Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - - int yyn; - int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; - yystacksize = YYINITDEPTH; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = (yytype_int16)yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = yylex (&yylval, context); - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yytable_value_is_error (yyn)) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the lookahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token. */ - yychar = YYEMPTY; - - yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - '$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - - - default: break; - } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - /* Now 'shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*--------------------------------------. -| yyerrlab -- here on detecting error. | -`--------------------------------------*/ -yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (context, YY_("syntax error")); -#else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) - { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (context, yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; - } -# undef YYSYNTAX_ERROR -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval, context); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -#if 0 -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule whose action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -#endif -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp, context); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#if !defined yyoverflow || YYERROR_VERBOSE -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (context, YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, context); - } - /* Do not reclaim the symbols of the rule whose action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, context); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - return yyresult; -} diff --git a/src/pj_wkt1_generated_parser.h b/src/pj_wkt1_generated_parser.h deleted file mode 100644 index 7bdec61f..00000000 --- a/src/pj_wkt1_generated_parser.h +++ /dev/null @@ -1,89 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -#ifndef YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED -# define YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int pj_wkt1_debug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - END = 0, - T_PARAM_MT = 258, - T_CONCAT_MT = 259, - T_INVERSE_MT = 260, - T_PASSTHROUGH_MT = 261, - T_PROJCS = 262, - T_PROJECTION = 263, - T_GEOGCS = 264, - T_DATUM = 265, - T_SPHEROID = 266, - T_PRIMEM = 267, - T_UNIT = 268, - T_GEOCCS = 269, - T_AUTHORITY = 270, - T_VERT_CS = 271, - T_VERT_DATUM = 272, - T_COMPD_CS = 273, - T_AXIS = 274, - T_TOWGS84 = 275, - T_FITTED_CS = 276, - T_LOCAL_CS = 277, - T_LOCAL_DATUM = 278, - T_PARAMETER = 279, - T_EXTENSION = 280, - T_STRING = 281, - T_NUMBER = 282, - T_IDENTIFIER = 283 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef int YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - - -int pj_wkt1_parse (pj_wkt1_parse_context *context); - -#endif /* !YY_PJ_WKT1_SRC_PJ_WKT1_GENERATED_PARSER_H_INCLUDED */ diff --git a/src/pj_wkt1_grammar.y b/src/pj_wkt1_grammar.y deleted file mode 100644 index 05ae792a..00000000 --- a/src/pj_wkt1_grammar.y +++ /dev/null @@ -1,301 +0,0 @@ -%{ -/****************************************************************************** - * Project: PROJ - * Purpose: WKT1 parser grammar - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2013-2018 Even Rouault, - * - * 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. - ****************************************************************************/ - -#include "pj_wkt1_parser.h" - -%} - -%define api.pure -/* if the next %define is commented out, Bison 2.4 should be sufficient */ -/* but will produce less prettier error messages */ -%define parse.error verbose -%require "3.0" - -%parse-param {pj_wkt1_parse_context *context} -%lex-param {pj_wkt1_parse_context *context} - -%token T_PARAM_MT "PARAM_MT" -%token T_CONCAT_MT "CONCAT_MT" -%token T_INVERSE_MT "INVERSE_MT" -%token T_PASSTHROUGH_MT "PASSTHROUGH_MT" -%token T_PROJCS "PROJCS" -%token T_PROJECTION "PROJECTION" -%token T_GEOGCS "GEOGCS" -%token T_DATUM "DATUM" -%token T_SPHEROID "SPHEROID" -%token T_PRIMEM "PRIMEM" -%token T_UNIT "UNIT" -%token T_GEOCCS "GEOCCS" -%token T_AUTHORITY "AUTHORITY" -%token T_VERT_CS "VERT_CS" -%token T_VERT_DATUM "VERT_DATUM" -%token T_COMPD_CS "COMPD_CS" -%token T_AXIS "AXIS" -%token T_TOWGS84 "TOWGS84" -%token T_FITTED_CS "FITTED_CS" -%token T_LOCAL_CS "LOCAL_CS" -%token T_LOCAL_DATUM "LOCAL_DATUM" -%token T_PARAMETER "PARAMETER" - -%token T_EXTENSION "EXTENSION" - -%token T_STRING "string" -%token T_NUMBER "number" -%token T_IDENTIFIER "identifier" - -%token END 0 "end of string" - -%% - -input: - coordinate_system - -/* Derived from BNF grammar in OGC 01-009 OpenGIS Implementation */ -/* Coordinate Transformation Services Revision 1.00 */ -/* with the following additions : */ -/* - accept an EXTENSION node at the end of GEOGCS, GEOCCS, PROJCS, COMPD_CS, VERT_DATUM */ -/* - accept 3 parameters in TOWGS84 */ -/* - accept LOCAL_CS["foo"] */ - -/* 7.1 Math Transform WKT */ - -begin_node: - '[' | '(' - -begin_node_name: - begin_node T_STRING - -end_node: - ']' | ')' - -math_transform: - param_mt | concat_mt | inv_mt | passthrough_mt - -param_mt: - T_PARAM_MT begin_node_name opt_parameter_list end_node - -parameter: - T_PARAMETER begin_node_name ',' T_NUMBER end_node - -opt_parameter_list: - | ',' parameter opt_parameter_list - -concat_mt: - T_CONCAT_MT begin_node math_transform opt_math_transform_list end_node - -opt_math_transform_list: - | ',' math_transform opt_math_transform_list - -inv_mt: - T_INVERSE_MT begin_node math_transform end_node - -passthrough_mt: - T_PASSTHROUGH_MT begin_node integer ',' math_transform end_node - -/* FIXME */ -integer: - T_NUMBER - -/* 7.2 Coordinate System WKT */ - -coordinate_system: - horz_cs | geocentric_cs | vert_cs | compd_cs | fitted_cs | local_cs - -horz_cs: - geographic_cs | projected_cs - -/* opt_extension is an extension of the CT spec */ -projected_cs: - T_PROJCS begin_node_name ',' geographic_cs ',' projection ',' - opt_parameter_list_linear_unit opt_twin_axis_extension_authority end_node - -opt_parameter_list_linear_unit: - linear_unit - | parameter_list_linear_unit - -parameter_list_linear_unit: - parameter ',' parameter_list_linear_unit - | parameter ',' linear_unit - -opt_twin_axis_extension_authority: - | ',' twin_axis opt_extension_authority - | ',' extension opt_authority - | ',' authority - -opt_authority: - | ',' authority - -extension: - T_EXTENSION begin_node_name ',' T_STRING end_node - -projection: - T_PROJECTION begin_node_name opt_authority end_node - -geographic_cs: - T_GEOGCS begin_node_name',' datum ',' prime_meridian ',' - angular_unit opt_twin_axis_extension_authority end_node - -datum: - T_DATUM begin_node_name ',' spheroid opt_towgs84_authority_extension end_node - -opt_towgs84_authority_extension: - | ',' towgs84 opt_extension_authority - | ',' extension opt_authority - | ',' authority - -spheroid: - T_SPHEROID begin_node_name ',' semi_major_axis ',' - inverse_flattening opt_authority end_node - -semi_major_axis: - T_NUMBER - -inverse_flattening: - T_NUMBER - -prime_meridian: - T_PRIMEM begin_node_name ',' longitude opt_authority end_node - -longitude: - T_NUMBER - -angular_unit: - unit - -linear_unit: - unit - -unit: - T_UNIT begin_node_name ',' conversion_factor opt_authority end_node - -conversion_factor: - T_NUMBER - -geocentric_cs: - T_GEOCCS begin_node_name ',' datum ',' prime_meridian ',' - linear_unit opt_three_axis_extension_authority end_node - -opt_three_axis_extension_authority: - | ',' three_axis opt_extension_authority - | ',' extension opt_authority - | ',' authority - -three_axis: - axis ',' axis ',' axis - -authority: - T_AUTHORITY begin_node_name ',' T_STRING end_node - -vert_cs: - T_VERT_CS begin_node_name ',' vert_datum ',' linear_unit opt_axis_authority end_node - -opt_axis_authority: - | ',' axis opt_authority - | ',' authority - -vert_datum: - T_VERT_DATUM begin_node_name ',' datum_type opt_extension_authority end_node - -opt_extension_authority: - | ',' extension opt_authority - | ',' authority - -datum_type: - T_NUMBER - -compd_cs: - T_COMPD_CS begin_node_name ',' head_cs ',' tail_cs opt_extension_authority end_node - -head_cs: - coordinate_system - -tail_cs: - coordinate_system - -twin_axis: axis ',' axis - -axis: - T_AXIS begin_node_name ',' T_IDENTIFIER end_node -/* Extension of the CT spec */ -/* | T_AXIS '[' T_STRING ',' T_STRING ']'*/ - -towgs84: - T_TOWGS84 begin_node towgs84_parameters end_node - -towgs84_parameters: - seven_parameters -/* Extension of the CT spec */ - | three_parameters - -three_parameters: - dx ',' dy ',' dz - -seven_parameters: - dx ',' dy ',' dz ',' ex ',' ey ',' ez ',' ppm - -dx: - T_NUMBER - -dy: - T_NUMBER - -dz: - T_NUMBER - -ex: - T_NUMBER - -ey: - T_NUMBER - -ez: - T_NUMBER - -ppm: - T_NUMBER - -fitted_cs: - T_FITTED_CS begin_node_name ',' to_base ',' base_cs end_node - -to_base: - math_transform - -base_cs: - coordinate_system - -local_cs: - T_LOCAL_CS begin_node_name ',' local_datum ',' unit ',' axis opt_axis_list_authority end_node -/* Extension of the CT spec: accept only name */ - | T_LOCAL_CS begin_node_name end_node - -opt_axis_list_authority: - | ',' authority - | ',' axis opt_axis_list_authority - -local_datum: - T_LOCAL_DATUM begin_node_name ',' datum_type opt_authority end_node diff --git a/src/pj_wkt1_parser.cpp b/src/pj_wkt1_parser.cpp deleted file mode 100644 index cdeb6b87..00000000 --- a/src/pj_wkt1_parser.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/****************************************************************************** - * Project: PROJ - * Purpose: WKT1 parser grammar - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2013, Even Rouault - * - * 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. - ****************************************************************************/ - -#ifndef FROM_PROJ_CPP -#define FROM_PROJ_CPP -#endif - -#include "proj/internal/internal.hpp" - -#include -#include -#include - -#include "pj_wkt1_parser.h" -#include "pj_wkt_parser.hpp" - -using namespace NS_PROJ::internal; - -//! @cond Doxygen_Suppress - -// --------------------------------------------------------------------------- - -struct pj_wkt1_parse_context : public pj_wkt_parse_context {}; - -// --------------------------------------------------------------------------- - -void pj_wkt1_error(pj_wkt1_parse_context *context, const char *msg) { - pj_wkt_error(context, msg); -} - -// --------------------------------------------------------------------------- - -std::string pj_wkt1_parse(const std::string &wkt) { - pj_wkt1_parse_context context; - context.pszInput = wkt.c_str(); - context.pszLastSuccess = wkt.c_str(); - context.pszNext = wkt.c_str(); - if (pj_wkt1_parse(&context) != 0) { - return context.errorMsg; - } - return std::string(); -} - -// --------------------------------------------------------------------------- - -typedef struct { - const char *pszToken; - int nTokenVal; -} osr_cs_wkt_tokens; - -#define PAIR(X) \ - { #X, T_##X } - -static const osr_cs_wkt_tokens tokens[] = { - PAIR(PARAM_MT), PAIR(PARAMETER), PAIR(CONCAT_MT), PAIR(INVERSE_MT), - PAIR(PASSTHROUGH_MT), - - PAIR(PROJCS), PAIR(PROJECTION), PAIR(GEOGCS), PAIR(DATUM), - PAIR(SPHEROID), PAIR(PRIMEM), PAIR(UNIT), PAIR(GEOCCS), - PAIR(AUTHORITY), PAIR(VERT_CS), PAIR(VERT_DATUM), PAIR(COMPD_CS), - PAIR(AXIS), PAIR(TOWGS84), PAIR(FITTED_CS), PAIR(LOCAL_CS), - PAIR(LOCAL_DATUM), - - PAIR(EXTENSION)}; - -// --------------------------------------------------------------------------- - -int pj_wkt1_lex(YYSTYPE * /*pNode */, pj_wkt1_parse_context *context) { - size_t i; - const char *pszInput = context->pszNext; - - /* -------------------------------------------------------------------- */ - /* Skip white space. */ - /* -------------------------------------------------------------------- */ - while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 || - *pszInput == 13) - pszInput++; - - context->pszLastSuccess = pszInput; - - if (*pszInput == '\0') { - context->pszNext = pszInput; - return EOF; - } - - /* -------------------------------------------------------------------- */ - /* Recognize node names. */ - /* -------------------------------------------------------------------- */ - if (isalpha(*pszInput)) { - for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) { - if (ci_starts_with(pszInput, tokens[i].pszToken) && - !isalpha(pszInput[strlen(tokens[i].pszToken)])) { - context->pszNext = pszInput + strlen(tokens[i].pszToken); - return tokens[i].nTokenVal; - } - } - } - - /* -------------------------------------------------------------------- */ - /* Recognize double quoted strings. */ - /* -------------------------------------------------------------------- */ - if (*pszInput == '"') { - pszInput++; - while (*pszInput != '\0' && *pszInput != '"') - pszInput++; - if (*pszInput == '\0') { - context->pszNext = pszInput; - return EOF; - } - context->pszNext = pszInput + 1; - return T_STRING; - } - - /* -------------------------------------------------------------------- */ - /* Recognize numerical values. */ - /* -------------------------------------------------------------------- */ - - if (((*pszInput == '-' || *pszInput == '+') && pszInput[1] >= '0' && - pszInput[1] <= '9') || - (*pszInput >= '0' && *pszInput <= '9')) { - if (*pszInput == '-' || *pszInput == '+') - pszInput++; - - // collect non-decimal part of number - while (*pszInput >= '0' && *pszInput <= '9') - pszInput++; - - // collect decimal places. - if (*pszInput == '.') { - pszInput++; - while (*pszInput >= '0' && *pszInput <= '9') - pszInput++; - } - - // collect exponent - if (*pszInput == 'e' || *pszInput == 'E') { - pszInput++; - if (*pszInput == '-' || *pszInput == '+') - pszInput++; - while (*pszInput >= '0' && *pszInput <= '9') - pszInput++; - } - - context->pszNext = pszInput; - - return T_NUMBER; - } - - /* -------------------------------------------------------------------- */ - /* Recognize identifiers. */ - /* -------------------------------------------------------------------- */ - if ((*pszInput >= 'A' && *pszInput <= 'Z') || - (*pszInput >= 'a' && *pszInput <= 'z')) { - pszInput++; - while ((*pszInput >= 'A' && *pszInput <= 'Z') || - (*pszInput >= 'a' && *pszInput <= 'z')) - pszInput++; - context->pszNext = pszInput; - return T_IDENTIFIER; - } - - /* -------------------------------------------------------------------- */ - /* Handle special tokens. */ - /* -------------------------------------------------------------------- */ - context->pszNext = pszInput + 1; - return *pszInput; -} - -//! @endcond diff --git a/src/pj_wkt1_parser.h b/src/pj_wkt1_parser.h deleted file mode 100644 index f8f7c841..00000000 --- a/src/pj_wkt1_parser.h +++ /dev/null @@ -1,54 +0,0 @@ -/****************************************************************************** - * Project: PROJ - * Purpose: WKT1 parser grammar - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2013, Even Rouault - * - * 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. - ****************************************************************************/ - -#ifndef PJ_WKT1_PARSER_H_INCLUDED -#define PJ_WKT1_PARSER_H_INCLUDED - -#ifndef DOXYGEN_SKIP - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct pj_wkt1_parse_context pj_wkt1_parse_context; - -#include "pj_wkt1_generated_parser.h" - -void pj_wkt1_error( pj_wkt1_parse_context *context, const char *msg ); -int pj_wkt1_lex(YYSTYPE* pNode, pj_wkt1_parse_context *context); -int pj_wkt1_parse(pj_wkt1_parse_context *context); - -#ifdef __cplusplus -} - -std::string pj_wkt1_parse(const std::string& wkt); - -#endif - -#endif /* #ifndef DOXYGEN_SKIP */ - -#endif /* PJ_WKT1_PARSER_H_INCLUDED */ diff --git a/src/pj_wkt2_generated_parser.c b/src/pj_wkt2_generated_parser.c deleted file mode 100644 index 759ad052..00000000 --- a/src/pj_wkt2_generated_parser.c +++ /dev/null @@ -1,3140 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ - -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "3.0.4" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 1 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - - -/* Substitute the variable and function names. */ -#define yyparse pj_wkt2_parse -#define yylex pj_wkt2_lex -#define yyerror pj_wkt2_error -#define yydebug pj_wkt2_debug -#define yynerrs pj_wkt2_nerrs - - -/* Copy the first part of user declarations. */ - - -/****************************************************************************** - * Project: PROJ - * Purpose: WKT2 parser grammar - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2018 Even Rouault, - * - * 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. - ****************************************************************************/ - -#include "pj_wkt2_parser.h" - - - - -# ifndef YY_NULLPTR -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULLPTR nullptr -# else -# define YY_NULLPTR 0 -# endif -# endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 1 -#endif - -/* In a future release of Bison, this section will be replaced - by #include "pj_wkt2_generated_parser.h". */ -#ifndef YY_PJ_WKT2_SRC_PJ_WKT2_GENERATED_PARSER_H_INCLUDED -# define YY_PJ_WKT2_SRC_PJ_WKT2_GENERATED_PARSER_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int pj_wkt2_debug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - END = 0, - T_PROJECTION = 258, - T_DATUM = 259, - T_SPHEROID = 260, - T_PRIMEM = 261, - T_UNIT = 262, - T_AXIS = 263, - T_PARAMETER = 264, - T_GEODCRS = 265, - T_LENGTHUNIT = 266, - T_ANGLEUNIT = 267, - T_SCALEUNIT = 268, - T_TIMEUNIT = 269, - T_ELLIPSOID = 270, - T_CS = 271, - T_ID = 272, - T_PROJCRS = 273, - T_BASEGEODCRS = 274, - T_MERIDIAN = 275, - T_BEARING = 276, - T_ORDER = 277, - T_ANCHOR = 278, - T_CONVERSION = 279, - T_METHOD = 280, - T_REMARK = 281, - T_GEOGCRS = 282, - T_BASEGEOGCRS = 283, - T_SCOPE = 284, - T_AREA = 285, - T_BBOX = 286, - T_CITATION = 287, - T_URI = 288, - T_VERTCRS = 289, - T_VDATUM = 290, - T_GEOIDMODEL = 291, - T_COMPOUNDCRS = 292, - T_PARAMETERFILE = 293, - T_COORDINATEOPERATION = 294, - T_SOURCECRS = 295, - T_TARGETCRS = 296, - T_INTERPOLATIONCRS = 297, - T_OPERATIONACCURACY = 298, - T_CONCATENATEDOPERATION = 299, - T_STEP = 300, - T_BOUNDCRS = 301, - T_ABRIDGEDTRANSFORMATION = 302, - T_DERIVINGCONVERSION = 303, - T_TDATUM = 304, - T_CALENDAR = 305, - T_TIMEORIGIN = 306, - T_TIMECRS = 307, - T_VERTICALEXTENT = 308, - T_TIMEEXTENT = 309, - T_USAGE = 310, - T_DYNAMIC = 311, - T_FRAMEEPOCH = 312, - T_MODEL = 313, - T_VELOCITYGRID = 314, - T_ENSEMBLE = 315, - T_MEMBER = 316, - T_ENSEMBLEACCURACY = 317, - T_DERIVEDPROJCRS = 318, - T_BASEPROJCRS = 319, - T_EDATUM = 320, - T_ENGCRS = 321, - T_PDATUM = 322, - T_PARAMETRICCRS = 323, - T_PARAMETRICUNIT = 324, - T_BASEVERTCRS = 325, - T_BASEENGCRS = 326, - T_BASEPARAMCRS = 327, - T_BASETIMECRS = 328, - T_EPOCH = 329, - T_COORDEPOCH = 330, - T_COORDINATEMETADATA = 331, - T_POINTMOTIONOPERATION = 332, - T_GEODETICCRS = 333, - T_GEODETICDATUM = 334, - T_PROJECTEDCRS = 335, - T_PRIMEMERIDIAN = 336, - T_GEOGRAPHICCRS = 337, - T_TRF = 338, - T_VERTICALCRS = 339, - T_VERTICALDATUM = 340, - T_VRF = 341, - T_TIMEDATUM = 342, - T_TEMPORALQUANTITY = 343, - T_ENGINEERINGDATUM = 344, - T_ENGINEERINGCRS = 345, - T_PARAMETRICDATUM = 346, - T_AFFINE = 347, - T_CARTESIAN = 348, - T_CYLINDRICAL = 349, - T_ELLIPSOIDAL = 350, - T_LINEAR = 351, - T_PARAMETRIC = 352, - T_POLAR = 353, - T_SPHERICAL = 354, - T_VERTICAL = 355, - T_TEMPORAL = 356, - T_TEMPORALCOUNT = 357, - T_TEMPORALMEASURE = 358, - T_ORDINAL = 359, - T_TEMPORALDATETIME = 360, - T_NORTH = 361, - T_NORTHNORTHEAST = 362, - T_NORTHEAST = 363, - T_EASTNORTHEAST = 364, - T_EAST = 365, - T_EASTSOUTHEAST = 366, - T_SOUTHEAST = 367, - T_SOUTHSOUTHEAST = 368, - T_SOUTH = 369, - T_SOUTHSOUTHWEST = 370, - T_SOUTHWEST = 371, - T_WESTSOUTHWEST = 372, - T_WEST = 373, - T_WESTNORTHWEST = 374, - T_NORTHWEST = 375, - T_NORTHNORTHWEST = 376, - T_UP = 377, - T_DOWN = 378, - T_GEOCENTRICX = 379, - T_GEOCENTRICY = 380, - T_GEOCENTRICZ = 381, - T_COLUMNPOSITIVE = 382, - T_COLUMNNEGATIVE = 383, - T_ROWPOSITIVE = 384, - T_ROWNEGATIVE = 385, - T_DISPLAYRIGHT = 386, - T_DISPLAYLEFT = 387, - T_DISPLAYUP = 388, - T_DISPLAYDOWN = 389, - T_FORWARD = 390, - T_AFT = 391, - T_PORT = 392, - T_STARBOARD = 393, - T_CLOCKWISE = 394, - T_COUNTERCLOCKWISE = 395, - T_TOWARDS = 396, - T_AWAYFROM = 397, - T_FUTURE = 398, - T_PAST = 399, - T_UNSPECIFIED = 400, - T_STRING = 401, - T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE = 402 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef int YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - - -int pj_wkt2_parse (pj_wkt2_parse_context *context); - -#endif /* !YY_PJ_WKT2_SRC_PJ_WKT2_GENERATED_PARSER_H_INCLUDED */ - -/* Copy the second part of user declarations. */ - - - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#else -typedef signed char yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(Msgid) dgettext ("bison-runtime", Msgid) -# endif -# endif -# ifndef YY_ -# define YY_(Msgid) Msgid -# endif -#endif - -#ifndef YY_ATTRIBUTE -# if (defined __GNUC__ \ - && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ - || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C -# define YY_ATTRIBUTE(Spec) __attribute__(Spec) -# else -# define YY_ATTRIBUTE(Spec) /* empty */ -# endif -#endif - -#ifndef YY_ATTRIBUTE_PURE -# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) -#endif - -#ifndef YY_ATTRIBUTE_UNUSED -# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) -#endif - -#if !defined _Noreturn \ - && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) -# if defined _MSC_VER && 1200 <= _MSC_VER -# define _Noreturn __declspec (noreturn) -# else -# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) -#else -# define YYUSE(E) /* empty */ -#endif - -#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ -/* Suppress an incorrect diagnostic about yylval being uninitialized. */ -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ - _Pragma ("GCC diagnostic push") \ - _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ - _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") -# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ - _Pragma ("GCC diagnostic pop") -#else -# define YY_INITIAL_VALUE(Value) Value -#endif -#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN -# define YY_IGNORE_MAYBE_UNINITIALIZED_END -#endif -#ifndef YY_INITIAL_VALUE -# define YY_INITIAL_VALUE(Value) /* Nothing. */ -#endif - - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS -# include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's 'empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (0) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 99 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 3313 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 163 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 324 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 651 -/* YYNSTATES -- Number of states. */ -#define YYNSTATES 1343 - -/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned - by yylex, with out-of-bounds checking. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 402 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM - as returned by yylex, without out-of-bounds checking. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 159, 161, 2, 153, 162, 154, 148, 2, 2, 150, - 151, 152, 2, 2, 2, 2, 2, 2, 155, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 149, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 156, 2, 2, 2, 2, 2, - 157, 158, 2, 160, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147 -}; - -#if YYDEBUG - /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 206, 206, 206, 206, 206, 206, 206, 207, 207, - 207, 208, 211, 211, 212, 212, 212, 213, 216, 216, - 216, 216, 217, 217, 217, 217, 218, 218, 218, 219, - 219, 219, 223, 227, 227, 229, 231, 233, 233, 235, - 235, 237, 239, 241, 243, 245, 245, 247, 247, 249, - 249, 249, 249, 251, 251, 255, 257, 261, 262, 263, - 265, 265, 267, 269, 271, 273, 277, 278, 281, 282, - 284, 286, 288, 291, 292, 293, 295, 297, 299, 299, - 301, 304, 305, 307, 307, 312, 312, 314, 314, 316, - 318, 320, 324, 325, 328, 329, 330, 332, 332, 333, - 336, 337, 341, 342, 343, 347, 348, 349, 350, 352, - 356, 358, 361, 363, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 383, - 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 401, 403, 405, 409, 414, 416, - 418, 420, 422, 426, 431, 432, 434, 436, 438, 442, - 446, 448, 448, 450, 450, 455, 460, 461, 462, 463, - 464, 465, 466, 468, 470, 472, 472, 474, 474, 476, - 478, 480, 482, 484, 486, 490, 492, 496, 496, 499, - 502, 507, 507, 507, 507, 507, 510, 515, 515, 515, - 515, 518, 522, 523, 525, 541, 545, 546, 548, 548, - 550, 550, 556, 556, 558, 560, 567, 567, 567, 569, - 576, 577, 578, 579, 581, 588, 595, 596, 597, 599, - 601, 601, 601, 601, 601, 601, 601, 601, 601, 604, - 604, 604, 606, 606, 608, 608, 608, 610, 615, 621, - 626, 629, 632, 633, 634, 635, 636, 637, 638, 639, - 640, 643, 644, 645, 646, 647, 648, 649, 650, 653, - 654, 655, 656, 657, 658, 659, 660, 663, 664, 667, - 668, 669, 670, 675, 676, 677, 678, 679, 680, 681, - 682, 683, 686, 687, 688, 689, 692, 693, 694, 695, - 698, 699, 702, 703, 708, 709, 712, 713, 714, 715, - 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, - 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, - 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, - 748, 749, 750, 751, 752, 753, 755, 758, 760, 762, - 764, 766, 768, 784, 784, 786, 794, 795, 797, 798, - 800, 808, 809, 811, 813, 815, 820, 821, 823, 825, - 827, 829, 831, 833, 835, 840, 844, 846, 849, 852, - 853, 854, 856, 857, 859, 864, 865, 867, 867, 869, - 873, 873, 873, 873, 875, 883, 891, 900, 910, 911, - 913, 915, 915, 917, 917, 920, 921, 925, 931, 932, - 933, 935, 935, 937, 939, 941, 945, 950, 950, 952, - 955, 956, 960, 965, 965, 965, 967, 969, 970, 971, - 972, 974, 977, 979, 983, 989, 989, 993, 993, 995, - 1000, 1001, 1002, 1003, 1005, 1011, 1011, 1013, 1015, 1019, - 1027, 1028, 1030, 1032, 1034, 1038, 1038, 1040, 1042, 1047, - 1048, 1050, 1052, 1054, 1056, 1060, 1060, 1062, 1068, 1075, - 1075, 1078, 1085, 1086, 1087, 1088, 1089, 1091, 1095, 1097, - 1099, 1099, 1103, 1108, 1108, 1108, 1112, 1117, 1117, 1119, - 1123, 1123, 1127, 1132, 1134, 1138, 1138, 1142, 1147, 1149, - 1153, 1154, 1155, 1156, 1157, 1159, 1159, 1161, 1164, 1166, - 1166, 1168, 1170, 1172, 1176, 1183, 1183, 1185, 1186, 1187, - 1188, 1190, 1192, 1196, 1201, 1203, 1206, 1211, 1215, 1221, - 1221, 1221, 1221, 1221, 1221, 1225, 1230, 1232, 1238, 1245, - 1255, 1261, 1263, 1265, 1270, 1275, 1281, 1281, 1283, 1286, - 1290, 1295, 1301, 1304, 1309, 1315, 1318, 1323, 1329, 1332, - 1337, 1343, 1344, 1345, 1346, 1347, 1349, 1351, 1353, 1353, - 1353, 1355, 1355, 1360, 1363, 1363, 1366, 1367, 1368, 1370, - 1374, 1375, 1377, 1379, 1379, 1380, 1380, 1381, 1381, 1381, - 1382, 1382, 1383, 1383, 1384, 1384, 1385, 1385, 1387, 1387, - 1388, 1388, 1389, 1389, 1390, 1390, 1394, 1401, 1402, 1403, - 1404, 1405, 1406, 1407, 1409, 1411, 1413, 1415, 1417, 1419, - 1421, 1423, 1425, 1427, 1432, 1439, 1440, 1441, 1442, 1443, - 1445, 1450, 1458, 1458, 1458, 1460, 1461, 1462, 1463, 1465, - 1467, 1472, 1478, 1480, 1487, 1487, 1489, 1490, 1491, 1492, - 1494, 1496 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || 1 -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "\"end of string\"", "error", "$undefined", "\"PROJECTION\"", - "\"DATUM\"", "\"SPHEROID\"", "\"PRIMEM\"", "\"UNIT\"", "\"AXIS\"", - "\"PARAMETER\"", "\"GEODCRS\"", "\"LENGTHUNIT\"", "\"ANGLEUNIT\"", - "\"SCALEUNIT\"", "\"TIMEUNIT\"", "\"ELLIPSOID\"", "\"CS\"", "\"ID\"", - "\"PROJCRS\"", "\"BASEGEODCRS\"", "\"MERIDIAN\"", "\"BEARING\"", - "\"ORDER\"", "\"ANCHOR\"", "\"CONVERSION\"", "\"METHOD\"", "\"REMARK\"", - "\"GEOGCRS\"", "\"BASEGEOGCRS\"", "\"SCOPE\"", "\"AREA\"", "\"BBOX\"", - "\"CITATION\"", "\"URI\"", "\"VERTCRS\"", "\"VDATUM\"", "\"GEOIDMODEL\"", - "\"COMPOUNDCRS\"", "\"PARAMETERFILE\"", "\"COORDINATEOPERATION\"", - "\"SOURCECRS\"", "\"TARGETCRS\"", "\"INTERPOLATIONCRS\"", - "\"OPERATIONACCURACY\"", "\"CONCATENATEDOPERATION\"", "\"STEP\"", - "\"BOUNDCRS\"", "\"ABRIDGEDTRANSFORMATION\"", "\"DERIVINGCONVERSION\"", - "\"TDATUM\"", "\"CALENDAR\"", "\"TIMEORIGIN\"", "\"TIMECRS\"", - "\"VERTICALEXTENT\"", "\"TIMEEXTENT\"", "\"USAGE\"", "\"DYNAMIC\"", - "\"FRAMEEPOCH\"", "\"MODEL\"", "\"VELOCITYGRID\"", "\"ENSEMBLE\"", - "\"MEMBER\"", "\"ENSEMBLEACCURACY\"", "\"DERIVEDPROJCRS\"", - "\"BASEPROJCRS\"", "\"EDATUM\"", "\"ENGCRS\"", "\"PDATUM\"", - "\"PARAMETRICCRS\"", "\"PARAMETRICUNIT\"", "\"BASEVERTCRS\"", - "\"BASEENGCRS\"", "\"BASEPARAMCRS\"", "\"BASETIMECRS\"", "\"EPOCH\"", - "\"COORDEPOCH\"", "\"COORDINATEMETADATA\"", "\"POINTMOTIONOPERATION\"", - "\"GEODETICCRS\"", "\"GEODETICDATUM\"", "\"PROJECTEDCRS\"", - "\"PRIMEMERIDIAN\"", "\"GEOGRAPHICCRS\"", "\"TRF\"", "\"VERTICALCRS\"", - "\"VERTICALDATUM\"", "\"VRF\"", "\"TIMEDATUM\"", "\"TEMPORALQUANTITY\"", - "\"ENGINEERINGDATUM\"", "\"ENGINEERINGCRS\"", "\"PARAMETRICDATUM\"", - "\"affine\"", "\"Cartesian\"", "\"cylindrical\"", "\"ellipsoidal\"", - "\"linear\"", "\"parametric\"", "\"polar\"", "\"spherical\"", - "\"vertical\"", "\"temporal\"", "\"temporalCount\"", - "\"temporalMeasure\"", "\"ordinal\"", "\"temporalDateTime\"", - "\"north\"", "\"northNorthEast\"", "\"northEast\"", "\"eastNorthEast\"", - "\"east\"", "\"eastSouthEast\"", "\"southEast\"", "\"southSouthEast\"", - "\"south\"", "\"southSouthWest\"", "\"southWest\"", "\"westSouthWest\"", - "\"west\"", "\"westNorthWest\"", "\"northWest\"", "\"northNorthWest\"", - "\"up\"", "\"down\"", "\"geocentricX\"", "\"geocentricY\"", - "\"geocentricZ\"", "\"columnPositive\"", "\"columnNegative\"", - "\"rowPositive\"", "\"rowNegative\"", "\"displayRight\"", - "\"displayLeft\"", "\"displayUp\"", "\"displayDown\"", "\"forward\"", - "\"aft\"", "\"port\"", "\"starboard\"", "\"clockwise\"", - "\"counterClockwise\"", "\"towards\"", "\"awayFrom\"", "\"future\"", - "\"part\"", "\"unspecified\"", "\"string\"", "\"unsigned integer\"", - "'.'", "'E'", "'1'", "'2'", "'3'", "'+'", "'-'", "':'", "'T'", "'Z'", - "'['", "'('", "']'", "')'", "','", "$accept", "input", "datum", "crs", - "period", "number", "signed_numeric_literal_with_sign", - "signed_numeric_literal", "unsigned_numeric_literal", "opt_sign", - "approximate_numeric_literal", "mantissa", "exponent", "signed_integer", - "exact_numeric_literal", "opt_period_unsigned_integer", - "unsigned_integer", "sign", "colon", "hyphen", "datetime", - "opt_24_hour_clock", "year", "month", "day", "_24_hour_clock", - "opt_colon_minute_colon_second_time_zone_designator", - "opt_colon_second_time_zone_designator", "time_designator", "hour", - "minute", "second_time_zone_designator", "seconds_integer", - "seconds_fraction", "time_zone_designator", "utc_designator", - "local_time_zone_designator", "opt_colon_minute", "left_delimiter", - "right_delimiter", "wkt_separator", "quoted_latin_text", - "quoted_unicode_text", "opt_separator_scope_extent_identifier_remark", - "no_opt_separator_scope_extent_identifier_remark", - "opt_identifier_list_remark", - "scope_extent_opt_identifier_list_opt_remark", - "scope_extent_opt_identifier_list_remark", - "usage_list_opt_identifier_list_remark", "usage", "usage_keyword", - "scope", "scope_keyword", "scope_text_description", "extent", - "extent_opt_identifier_list_remark", "area_description", - "area_description_keyword", "area_text_description", - "geographic_bounding_box", "geographic_bounding_box_keyword", - "lower_left_latitude", "lower_left_longitude", "upper_right_latitude", - "upper_right_longitude", "vertical_extent", "opt_separator_length_unit", - "vertical_extent_keyword", "vertical_extent_minimum_height", - "vertical_extent_maximum_height", "temporal_extent", - "temporal_extent_keyword", "temporal_extent_start", - "temporal_extent_end", "identifier", - "opt_version_authority_citation_uri", "identifier_keyword", - "authority_name", "authority_unique_identifier", "version", - "authority_citation", "citation_keyword", "citation", "id_uri", - "uri_keyword", "uri", "remark", "remark_keyword", "unit", "spatial_unit", - "angle_or_length_or_parametric_or_scale_unit", - "angle_or_length_or_parametric_or_scale_unit_keyword", - "angle_or_length_or_scale_unit", "angle_or_length_or_scale_unit_keyword", - "angle_unit", "opt_separator_identifier_list", "length_unit", - "time_unit", "opt_separator_conversion_factor_identifier_list", - "angle_unit_keyword", "length_unit_keyword", "time_unit_keyword", - "unit_name", "conversion_factor", - "coordinate_system_scope_extent_identifier_remark", - "spatial_cs_scope_extent_identifier_remark", - "opt_separator_spatial_axis_list_opt_separator_cs_unit_scope_extent_identifier_remark", - "temporalcountmeasure_cs_scope_extent_identifier_remark", - "ordinaldatetime_cs_scope_extent_identifier_remark", - "opt_separator_ordinaldatetime_axis_list_scope_extent_identifier_remark", - "cs_keyword", "spatial_cs_type", "temporalcountmeasure_cs_type", - "ordinaldatetime_cs_type", "dimension", "spatial_axis", - "temporalcountmeasure_axis", "ordinaldatetime_axis", "axis_keyword", - "axis_name_abbrev", - "axis_direction_opt_axis_order_spatial_unit_identifier_list", - "north_south_options_spatial_unit", - "clockwise_counter_clockwise_options_spatial_unit", - "axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list", - "axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list_options", - "axis_direction_opt_axis_order_identifier_list", "north_south_options", - "clockwise_counter_clockwise_options", - "axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list", - "axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list_options", - "opt_separator_axis_time_unit_identifier_list", - "axis_direction_except_n_s_cw_ccw_opt_axis_time_unit_identifier_list_options", - "axis_direction_except_n_s_cw_ccw", "meridian", "meridian_keyword", - "bearing", "bearing_keyword", "axis_order", "axis_order_keyword", - "cs_unit", "datum_ensemble", "geodetic_datum_ensemble_without_pm", - "datum_ensemble_member_list_ellipsoid_accuracy_identifier_list", - "opt_separator_datum_ensemble_identifier_list", - "vertical_datum_ensemble", - "datum_ensemble_member_list_accuracy_identifier_list", - "datum_ensemble_keyword", "datum_ensemble_name", "datum_ensemble_member", - "opt_datum_ensemble_member_identifier_list", - "datum_ensemble_member_keyword", "datum_ensemble_member_name", - "datum_ensemble_member_identifier", "datum_ensemble_accuracy", - "datum_ensemble_accuracy_keyword", "accuracy", - "datum_ensemble_identifier", "dynamic_crs", "dynamic_crs_keyword", - "frame_reference_epoch", "frame_reference_epoch_keyword", - "reference_epoch", "opt_separator_deformation_model_id", - "deformation_model_id", "opt_separator_identifier", - "deformation_model_id_keyword", "deformation_model_name", "geodetic_crs", - "static_geodetic_crs", "static_geographic_crs", "dynamic_geodetic_crs", - "dynamic_geographic_crs", - "opt_prime_meridian_coordinate_system_scope_extent_identifier_remark", - "crs_name", "geodetic_crs_keyword", "geographic_crs_keyword", - "geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm", - "ellipsoid", "opt_separator_length_unit_identifier_list", - "ellipsoid_keyword", "ellipsoid_name", "semi_major_axis", - "inverse_flattening", "prime_meridian", "prime_meridian_keyword", - "prime_meridian_name", "irm_longitude_opt_separator_identifier_list", - "geodetic_reference_frame_without_pm", - "geodetic_reference_frame_keyword", "datum_name", - "opt_separator_datum_anchor_identifier_list", "datum_anchor", - "datum_anchor_keyword", "datum_anchor_description", "projected_crs", - "projected_crs_keyword", "base_geodetic_crs", "base_static_geodetic_crs", - "opt_separator_pm_ellipsoidal_cs_unit", "base_dynamic_geodetic_crs", - "base_geodetic_crs_keyword", "base_crs_name", "ellipsoidal_cs_unit", - "map_projection", "parameter_list_identifier_list", - "map_projection_keyword", "map_projection_name", "map_projection_method", - "map_projection_method_keyword", "map_projection_method_name", - "map_projection_parameter", "opt_separator_param_unit_identifier_list", - "parameter_keyword", "parameter_name", "parameter_value", - "map_projection_parameter_unit", "vertical_crs", "static_vertical_crs", - "dynamic_vertical_crs", - "vertical_reference_frame_or_vertical_datum_ensemble", - "vertical_cs_opt_geoid_model_id_scope_extent_identifier_remark", - "opt_separator_cs_unit_opt_geoid_model_id_scope_extent_identifier_remark", - "geoid_model_id", "geoid_model_keyword", "geoid_model_name", - "vertical_crs_keyword", "vertical_reference_frame", - "vertical_reference_frame_keyword", "engineering_crs", - "engineering_crs_keyword", "engineering_datum", - "engineering_datum_keyword", "parametric_crs", "parametric_crs_keyword", - "parametric_datum", "parametric_datum_keyword", "temporal_crs", - "temporal_crs_keyword", "temporal_datum", - "opt_separator_temporal_datum_end", "temporal_datum_keyword", - "temporal_origin", "temporal_origin_keyword", - "temporal_origin_description", "calendar", "calendar_keyword", - "calendar_identifier", "deriving_conversion", - "parameter_or_parameter_file", "opt_separator_deriving_conversion_end", - "deriving_conversion_keyword", "deriving_conversion_name", - "operation_method", "operation_method_keyword", "operation_method_name", - "operation_parameter", "parameter_unit", - "length_or_angle_or_scale_or_time_or_parametric_unit", - "length_or_angle_or_scale_or_time_or_parametric_unit_keyword", - "operation_parameter_file", "parameter_file_keyword", - "parameter_file_name", "derived_geodetic_crs", "derived_geographic_crs", - "derived_projected_crs", "derived_projected_crs_keyword", - "derived_crs_name", "base_projected_crs", "base_projected_crs_keyword", - "derived_vertical_crs", "base_vertical_crs", "base_static_vertical_crs", - "base_dynamic_vertical_crs", "base_vertical_crs_keyword", - "derived_engineering_crs", "base_engineering_crs", - "base_engineering_crs_keyword", "derived_parametric_crs", - "base_parametric_crs", "base_parametric_crs_keyword", - "derived_temporal_crs", "base_temporal_crs", "base_temporal_crs_keyword", - "compound_crs", "compound_crs_other_components", "compound_crs_keyword", - "compound_crs_name", "horizontal_crs", "geographic2D_crs", - "metadata_coordinate_epoch", "coordinate_epoch_keyword", - "coordinate_epoch", "coordinate_metadata", "coordinate_metadata_crs", - "coordinate_metadata_keyword", "static_crs", - "dynamic_crs_coordinate_metadata", "coordinate_operation", - "opt_coordinate_operation_end", "operation_keyword", "operation_name", - "source_crs", "source_crs_keyword", "target_crs", "target_crs_keyword", - "interpolation_crs", "interpolation_crs_keyword", "operation_accuracy", - "operation_accuracy_keyword", "point_motion_operation", - "opt_point_motion_operation_end", "point_motion_keyword", - "concatenated_operation", "step", "opt_concatenated_operation_end", - "concatenated_operation_keyword", "step_keyword", "bound_crs", - "bound_crs_keyword", "abridged_coordinate_transformation", - "abridged_parameter_or_parameter_file", - "opt_end_abridged_coordinate_transformation", - "abridged_transformation_keyword", "abridged_transformation_parameter", YY_NULLPTR -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[NUM] -- (External) token number corresponding to the - (internal) symbol number NUM (which must be that of a token). */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 401, 402, 46, 69, - 49, 50, 51, 43, 45, 58, 84, 90, 91, 40, - 93, 41, 44 -}; -# endif - -#define YYPACT_NINF -1109 - -#define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-1109))) - -#define YYTABLE_NINF -606 - -#define yytable_value_is_error(Yytable_value) \ - 0 - - /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -static const yytype_int16 yypact[] = -{ - 782, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, 77, -1109, -1109, - -1109, 367, -1109, -1109, -1109, 367, -1109, -1109, -1109, -1109, - -1109, 367, 367, -1109, 367, -1109, 367, -1109, 367, -1109, - 367, -1109, -1109, -1109, 367, -1109, 367, -1109, 367, -1109, - 367, -1109, 367, -1109, 367, -1109, 367, -1109, 367, -1109, - -1109, -1109, 367, -1109, -1109, -1109, -1109, -1109, 367, -1109, - 367, -1109, 367, -1109, 367, -1109, 367, -1109, 367, -1109, - -1109, -1109, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - 681, -44, -44, -44, 239, -1109, -1109, 175, -1109, 175, - -1109, 175, 175, -1109, 175, -1109, 175, 175, -1109, 175, - 175, 175, 175, 175, 175, 175, 175, 175, -1109, 175, - -1109, 175, -1109, -1109, -1109, -1109, 190, -1109, -1109, -1109, - -1109, -1109, 207, 218, 223, 249, -1109, -1109, -1109, -1109, - 409, -1109, 175, -1109, 175, 175, 175, -1109, 175, 367, - -1109, 933, 234, 467, 467, 788, 269, 209, 132, 654, - 295, 409, 56, 409, 391, 409, 299, 312, 409, 354, - 324, -1109, -1109, -1109, 509, 239, 239, 239, 406, 681, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, 644, -1109, -1109, - -1109, -1109, 274, 283, 279, 788, -1109, 175, -1109, 175, - 367, -1109, -1109, -1109, -1109, 367, 175, 367, 175, -1109, - 175, -1109, -1109, 367, 175, 175, 175, -1109, 175, 175, - 175, -1109, -1109, 175, 367, -1109, -1109, 367, 175, 175, - -1109, 175, -1109, -1109, 367, -1109, 175, 175, 367, -1109, - -1109, 175, 175, 367, -1109, -1109, 175, 175, 367, -1109, - -1109, 175, 175, 367, -1109, -1109, 175, 175, 367, 175, - 367, -1109, -1109, 175, 367, -1109, -1109, 367, -1109, -1109, - 367, 175, -1109, -1109, -1109, -1109, 367, 175, 175, 175, - -1109, 175, 367, 409, -1109, 444, 644, -1109, -1109, 298, - 409, 155, 409, 409, -44, -44, 119, 400, 102, 414, - -44, 119, 102, 414, 788, 409, 452, 483, -44, -44, - 99, 497, 414, -44, 499, -1109, 499, -44, 497, 414, - -44, 497, 414, -44, 497, 414, -44, -1109, -1109, 591, - 129, -1109, -44, 414, -44, -44, -44, 289, 644, 406, - 505, 406, 493, 681, -1109, 644, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, 175, 175, 367, -1109, 367, -1109, - -1109, 175, 175, 367, 175, -1109, -1109, -1109, 175, 175, - 175, -1109, 175, 367, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, 367, 409, 175, 367, -1109, 175, 367, -1109, 175, - 175, 409, 175, -1109, 175, -1109, 175, -1109, 409, 175, - 367, -1109, 175, 175, 175, 367, 409, 175, 175, 175, - 175, -1109, 409, 409, 175, 175, 409, 175, 175, 409, - 175, 175, -1109, -1109, 331, -1109, 409, 175, -1109, 409, - 175, 175, 175, 175, 175, 367, 175, 367, 175, 367, - 409, 279, 409, 175, -1109, 175, 367, 175, -1109, 175, - 367, 409, -1109, 515, 527, -44, -44, -1109, -1109, 499, - -1109, 1202, 526, 499, 409, 234, 102, 587, 409, 644, - 1171, -1109, 497, -44, 497, -44, 222, 102, -1109, 497, - 448, 409, 497, -1109, 225, -1109, -44, 409, 234, 497, - 1364, -1109, 497, 323, -1109, -1109, -1109, -1109, 497, 275, - -1109, 497, 345, -1109, 497, 95, -1109, -1109, 644, -1109, - -1109, 644, -1109, -1109, -1109, 497, 209, 83, 275, 960, - -1109, -44, 960, -1109, -44, 826, -1109, -44, -1109, 644, - -1109, 505, 91, -44, 520, 409, -44, -1109, 175, -1109, - -1109, 409, -1109, 409, -1109, 175, -1109, 409, 175, -1109, - 175, -1109, 175, 409, -1109, -1109, -1109, 367, -1109, 279, - 409, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, -1109, 175, 175, 175, -1109, -1109, - 175, 409, -1109, 175, 175, 175, 409, 409, -1109, -1109, - 175, 175, 367, -1109, 409, -1109, -1109, 175, -1109, 175, - 409, 175, 409, 175, 409, 409, 409, 409, 409, 409, - 409, 402, 439, -1109, 958, 409, 175, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, 175, 367, - 175, 367, -1109, 175, 367, 175, 367, 175, 367, 175, - 367, 175, -1109, 367, 175, 175, 175, 175, 175, -1109, - 175, -1109, 367, 175, -1109, -1109, 367, -1109, 175, -1109, - 367, -1109, 175, 527, -1109, -1109, -1109, -1109, -1109, -1109, - 278, -1109, -44, 644, -1109, 386, 386, 386, 444, -1109, - 505, 70, 126, 409, -1109, -1109, -1109, -1109, -44, -1109, - 444, 605, -1109, 386, -1109, 213, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, 644, -1109, -1109, 644, 644, -1109, - 449, -1109, -1109, -1109, -1109, 452, 93, 597, 453, -1109, - -44, 549, -1109, -44, 300, -1109, 1202, 377, -1109, 1202, - 390, -1109, 591, -1109, 471, -1109, 382, -1109, 345, 95, - 91, -44, 888, 409, -44, 499, 409, 92, 505, -1109, - 175, -1109, 175, -1109, -1109, -1109, -1109, 175, 175, 175, - 175, 788, 409, 175, 175, -1109, -1109, -1109, 367, 175, - -1109, -1109, -1109, 175, -1109, 175, 175, 175, 409, -1109, - 464, 449, -1109, 958, 644, -1109, 409, -1109, 175, -1109, - 175, -1109, 175, -1109, -1109, 409, 175, 175, 175, -1109, - 409, 175, 175, -1109, 175, 175, -1109, 175, -1109, -1109, - 175, -1109, 409, 175, 175, -1109, -1109, 175, 175, 175, - 367, -1109, 175, -1109, -1109, -1109, -1109, -1109, 409, 175, - 409, 409, 409, 409, 135, -1109, -1109, -1109, 91, 409, - -44, 229, 788, 621, 409, 409, -1109, -1109, -1109, 644, - -1109, -1109, -1109, -1109, -1109, 443, -1109, -1109, 300, -1109, - 377, -1109, -1109, -1109, 377, -1109, -1109, 1202, -1109, 1202, - 591, -1109, 869, 409, 444, -1109, -1109, -1109, 1202, -44, - 175, 91, -1109, 175, 175, 175, 175, 175, -1109, 175, - -1109, -1109, 175, -1109, -1109, -1109, -1109, -1109, 367, 175, - -1109, 175, -1109, -1109, 1154, 409, 175, 175, 175, -1109, - 175, 175, 175, 175, -1109, 175, -1109, 175, -1109, -1109, - 409, -1109, -1109, 175, 175, 175, 367, 175, -1109, 175, - 409, -1109, 175, 520, 367, -1109, 175, -1109, 632, 632, - 632, -1109, 327, 409, 788, 409, -44, -1109, 632, 627, - -1109, -1109, 261, 619, 602, 377, -1109, -1109, -1109, -1109, - 1202, 348, 409, -1109, -1109, -1109, 1035, -1109, 681, -1109, - 550, -1109, 409, 367, -44, 920, 409, -1109, 175, 367, - 175, 367, 175, 367, 175, 175, 175, -1109, 175, -1109, - 175, 175, 503, 627, -1109, 175, 175, -1109, 175, -1109, - -1109, 175, -1109, 175, -1109, -1109, 175, 409, -1109, -1109, - -1109, -1109, -1109, -1109, 175, -1109, 367, -1109, 92, 175, - -1109, 175, 175, -1109, 560, -1109, -44, -1109, -44, 675, - -1109, -44, -1109, -1109, -1109, 409, 788, 624, -1109, -1109, - 619, 602, 602, -1109, 1202, -1109, -1109, 409, -44, 409, - 444, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, 367, -1109, 367, 175, 175, -1109, - 175, 175, -1109, 175, 175, -1109, 175, -1109, -1109, 175, - 175, 367, 175, -1109, -1109, -1109, -1109, 409, -1109, 175, - 175, 175, -44, -44, -1109, -1109, 1117, 1310, -1109, 1271, - 409, 1065, -1109, -1109, -44, 602, -1109, 788, 409, 784, - 409, 409, 175, 175, 175, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, 175, -1109, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, 175, 175, -1109, - -1109, -1109, -1109, -1109, 409, -1109, 175, 175, 175, 175, - 175, 175, 409, -1109, 175, -1109, 175, -1109, 175, -1109, - 175, -1109, -1109, 175, 367, -1109, -1109, 788, 409, 408, - 408, 507, 507, -1109, 371, 141, 409, 565, 408, 500, - 500, -1109, 353, -1109, 409, -1109, -1109, 92, 175, -1109, - -1109, -1109, 175, 175, -1109, 175, 367, 175, 367, -1109, - -1109, 175, 175, -1109, 175, 367, 175, -1109, 175, 175, - -1109, 175, 175, 175, -1109, 175, -1109, 175, -1109, 175, - 175, -1109, 175, -1109, 175, 175, -1109, 175, -1109, 175, - -1109, 409, 409, -1109, -1109, 371, -1109, 1202, 588, -1109, - 644, -1109, -1109, 371, -1109, 1202, 588, -1109, -1109, -1109, - 588, -1109, -1109, -1109, 103, -1109, -1109, 353, -1109, -1109, - -1109, 353, -1109, -1109, -1109, -1109, 175, -1109, 175, 175, - 175, 175, 409, 175, 175, 409, 175, 175, 175, 175, - 175, -1109, -1109, 588, -1109, 229, -1109, -1109, -1109, 588, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, 175, 409, 175, - -1109, -1109, -1109 -}; - - /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE does not specify something else to do. Zero - means the default is an error. */ -static const yytype_uint16 yydefact[] = -{ - 0, 423, 412, 401, 411, 173, 435, 452, 403, 480, - 483, 566, 614, 639, 642, 505, 498, 363, 541, 490, - 487, 495, 493, 582, 630, 402, 425, 436, 404, 424, - 481, 485, 484, 506, 491, 488, 496, 0, 4, 5, - 2, 0, 13, 353, 354, 0, 18, 390, 391, 392, - 393, 0, 0, 3, 0, 12, 0, 19, 0, 11, - 0, 20, 465, 466, 0, 14, 0, 21, 0, 15, - 0, 22, 0, 16, 0, 23, 0, 17, 0, 24, - 25, 26, 0, 27, 28, 29, 30, 31, 0, 7, - 0, 8, 0, 9, 0, 10, 0, 6, 0, 1, - 85, 86, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 90, 174, 0, 364, 0, - 400, 0, 0, 413, 0, 426, 0, 0, 453, 0, - 0, 427, 0, 427, 0, 427, 0, 500, 542, 0, - 567, 0, 583, 584, 598, 599, 585, 586, 601, 587, - 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, - 0, 580, 0, 615, 0, 0, 0, 617, 0, 0, - 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 87, 88, 579, 0, 0, 0, 0, 0, 0, - 52, 32, 49, 50, 51, 53, 54, 0, 175, 33, - 34, 38, 0, 37, 47, 0, 176, 166, 368, 0, - 0, 445, 446, 376, 406, 0, 0, 0, 0, 405, - 0, 437, 438, 0, 0, 0, 0, 414, 0, 427, - 0, 456, 455, 0, 0, 550, 470, 0, 0, 0, - 469, 0, 546, 547, 0, 432, 202, 428, 0, 482, - 553, 0, 0, 0, 489, 556, 0, 0, 0, 494, - 559, 0, 0, 0, 512, 508, 202, 202, 0, 202, - 0, 499, 544, 0, 0, 571, 572, 0, 569, 570, - 0, 0, 568, 574, 575, 581, 0, 0, 0, 0, - 619, 0, 0, 0, 46, 39, 0, 45, 35, 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, 429, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 504, 503, 0, - 0, 501, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 616, 0, 41, 43, 40, 48, - 180, 183, 177, 178, 167, 170, 0, 172, 0, 165, - 372, 0, 358, 0, 0, 355, 360, 369, 366, 0, - 0, 378, 382, 0, 417, 229, 418, 399, 216, 217, - 218, 0, 0, 0, 0, 521, 0, 0, 447, 0, - 0, 0, 0, 415, 408, 422, 0, 461, 0, 202, - 0, 457, 202, 0, 0, 0, 0, 0, 0, 202, - 202, 433, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 62, 509, 60, 510, 0, 202, 513, 0, - 0, 0, 0, 0, 92, 0, 92, 0, 92, 0, - 0, 576, 0, 0, 524, 0, 0, 0, 650, 92, - 0, 0, 44, 0, 0, 0, 0, 357, 362, 0, - 361, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 394, 0, 0, 0, 0, 0, 0, 395, 0, - 0, 0, 0, 449, 0, 450, 0, 0, 0, 0, - 0, 467, 0, 0, 203, 430, 431, 486, 0, 0, - 492, 0, 0, 497, 0, 0, 56, 70, 0, 57, - 61, 0, 507, 502, 511, 0, 0, 0, 0, 0, - 561, 0, 0, 562, 0, 0, 563, 0, 560, 577, - 573, 0, 0, 0, 0, 0, 0, 618, 168, 171, - 181, 0, 184, 0, 374, 358, 373, 0, 358, 370, - 366, 365, 0, 0, 387, 388, 383, 0, 375, 379, - 0, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 0, 0, 0, 398, 419, - 0, 0, 522, 0, 0, 440, 0, 0, 211, 210, - 202, 202, 0, 407, 0, 451, 462, 0, 454, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 60, 0, 71, 0, 0, 0, 186, 112, 145, - 148, 156, 160, 110, 93, 94, 100, 101, 105, 0, - 97, 0, 104, 97, 0, 97, 0, 97, 0, 97, - 0, 97, 96, 0, 92, 0, 92, 0, 0, 578, - 0, 536, 0, 625, 515, 516, 0, 525, 385, 640, - 0, 641, 0, 0, 179, 182, 359, 371, 356, 367, - 0, 396, 0, 380, 377, 0, 0, 0, 39, 538, - 0, 0, 0, 0, 397, 539, 410, 409, 0, 434, - 39, 0, 468, 0, 545, 0, 548, 551, 552, 554, - 555, 557, 558, 58, 0, 55, 80, 0, 0, 65, - 83, 67, 78, 79, 540, 0, 0, 0, 0, 103, - 0, 0, 129, 0, 0, 130, 0, 0, 131, 0, - 0, 132, 0, 95, 0, 564, 0, 565, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, - 0, 389, 385, 381, 244, 245, 246, 202, 202, 202, - 202, 0, 0, 0, 440, 209, 208, 448, 0, 441, - 443, 439, 214, 0, 463, 459, 0, 202, 0, 64, - 60, 83, 72, 0, 0, 82, 0, 108, 97, 106, - 0, 102, 97, 99, 113, 0, 97, 97, 97, 146, - 0, 97, 97, 149, 0, 97, 157, 0, 161, 162, - 0, 91, 0, 607, 0, 623, 629, 625, 625, 92, - 0, 624, 0, 386, 523, 634, 632, 633, 0, 0, - 0, 0, 0, 0, 0, 421, 36, 416, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 59, 81, 0, - 66, 69, 84, 543, 107, 0, 98, 111, 0, 133, - 0, 134, 135, 144, 0, 136, 137, 0, 138, 0, - 0, 185, 0, 0, 39, 626, 627, 628, 0, 0, - 0, 0, 384, 0, 0, 0, 202, 517, 444, 0, - 442, 215, 202, 200, 198, 197, 199, 464, 0, 202, - 458, 0, 76, 68, 0, 0, 114, 115, 116, 117, - 97, 97, 97, 97, 150, 0, 158, 154, 163, 164, - 0, 621, 613, 607, 607, 92, 0, 92, 606, 0, - 0, 537, 385, 0, 0, 645, 646, 644, 0, 0, - 0, 420, 0, 0, 0, 0, 0, 460, 0, 0, - 75, 109, 0, 0, 0, 0, 139, 140, 141, 142, - 0, 0, 0, 159, 608, 609, 0, 610, 0, 612, - 0, 622, 0, 0, 0, 0, 0, 250, 220, 0, - 92, 0, 226, 0, 385, 517, 517, 514, 202, 204, - 0, 472, 77, 0, 73, 118, 119, 120, 121, 122, - 123, 97, 151, 0, 155, 153, 92, 0, 534, 529, - 530, 531, 532, 533, 385, 527, 0, 535, 0, 0, - 649, 646, 646, 643, 0, 219, 0, 224, 0, 0, - 225, 0, 520, 518, 519, 0, 0, 0, 471, 74, - 0, 0, 0, 143, 0, 611, 620, 0, 0, 0, - 39, 648, 647, 195, 192, 191, 194, 212, 193, 213, - 223, 352, 187, 189, 0, 188, 0, 220, 92, 251, - 0, 0, 228, 226, 0, 201, 202, 478, 476, 92, - 92, 0, 124, 125, 126, 127, 152, 0, 526, 206, - 635, 202, 0, 0, 222, 221, 0, 0, 227, 0, - 0, 0, 473, 475, 0, 0, 147, 0, 0, 0, - 0, 0, 0, 206, 253, 310, 311, 312, 313, 314, - 315, 316, 255, 317, 318, 319, 320, 321, 322, 323, - 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, - 334, 335, 336, 337, 338, 339, 340, 257, 259, 341, - 342, 343, 344, 345, 0, 252, 277, 304, 284, 286, - 288, 290, 0, 283, 300, 196, 92, 479, 385, 128, - 202, 528, 638, 92, 0, 631, 651, 0, 0, 0, - 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, - 0, 249, 0, 474, 0, 207, 637, 0, 202, 205, - 347, 351, 202, 202, 254, 202, 0, 202, 0, 256, - 349, 202, 202, 258, 202, 0, 202, 260, 202, 202, - 278, 202, 202, 202, 305, 202, 248, 202, 285, 202, - 202, 287, 202, 289, 202, 202, 291, 202, 301, 202, - 477, 0, 0, 261, 268, 0, 265, 0, 0, 267, - 0, 269, 276, 0, 273, 0, 0, 275, 279, 282, - 0, 280, 306, 309, 0, 307, 292, 0, 294, 295, - 296, 0, 298, 299, 302, 303, 635, 190, 202, 202, - 0, 202, 0, 202, 202, 0, 202, 202, 202, 202, - 202, 636, 264, 0, 262, 0, 266, 350, 272, 0, - 270, 348, 274, 281, 308, 293, 297, 202, 0, 202, - 263, 346, 271 -}; - - /* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -1109, -1109, -1109, -205, -212, -178, -1109, -57, -184, 344, - -1109, -1109, -1109, -1109, -1109, -1109, -203, -310, -558, 28, - -673, -542, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -493, - -153, -1109, -1109, -1109, -757, -1109, -1109, -136, -43, 1622, - 897, 2179, -1109, -414, -678, -541, -1109, -1109, -59, -1109, - -1109, -53, -1109, -1109, -1109, -58, -187, -1109, -1109, -707, - -1109, -1109, -1109, -1109, -1109, -679, -1109, -1109, -1109, -1109, - -675, -1109, -1109, -1109, 0, -1109, -1109, -1109, -1109, -1109, - 217, -1109, -1109, -421, -1109, -1109, -282, -1109, -1109, -962, - -1109, -1109, -1109, -1109, -844, 1726, -289, -1090, -436, -1109, - -1109, -1109, -790, -905, 140, -1109, -388, -1109, -1109, -392, - -280, 196, -1109, -1109, -208, -880, -1109, -339, -854, -838, - -1109, -709, -489, -1109, -1109, -1109, -1109, -488, -1109, -1109, - -1109, -1109, -847, -490, -1109, -494, -1109, -1108, -1109, -333, - -1109, 736, -351, -253, 745, -363, 7, -188, -287, 170, - -1109, -1109, -1109, 264, -1109, -150, -1109, -157, -1109, -1109, - -1109, -1109, -1109, -1109, -744, -1109, -1109, -1109, 647, -36, - 649, -29, -231, -46, -1109, 583, -93, 57, -1109, -1109, - -1109, -1109, -1109, 73, -1109, -1109, -1109, 6, -1109, 651, - -48, -1109, -1109, -1109, -27, -1109, -141, -1109, -6, -1109, - -1109, 189, -73, -306, 294, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -319, -693, -819, -1109, 451, 691, 704, 485, - 311, -1109, -299, -1109, -1109, 466, 10, -1109, -24, 635, - 19, -1109, -78, 469, 22, -1109, -96, -296, 16, -1109, - -1109, 480, -1109, -1109, -1109, -1109, -1109, 655, -687, -263, - -1109, -1109, -511, -1109, -1109, -714, -1109, -1109, -1109, -699, - -1109, -1109, 721, 724, 726, -1109, -1109, -1109, -1109, 731, - -1109, -1109, -1109, -1109, 733, -1109, -1109, 734, -1109, -1109, - 743, -1109, -1109, 750, -1109, -1109, -1109, -1109, -1109, -1109, - -1109, -1109, -1109, -1109, -1109, -1109, -1109, 874, -151, -1109, - -86, 475, -1109, 133, -1109, -1109, -1109, -842, -1109, -1109, - -25, 875, -1109, -981, -430, -1109, -875, -1109, -1109, -1109, - -1109, -247, -1109, -128 -}; - - /* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 37, 38, 39, 217, 576, 219, 804, 220, 791, - 221, 222, 376, 377, 223, 317, 224, 225, 814, 538, - 453, 539, 454, 642, 810, 540, 739, 880, 541, 740, - 813, 933, 934, 1023, 741, 742, 743, 815, 102, 203, - 344, 130, 842, 550, 654, 749, 655, 656, 657, 658, - 659, 660, 661, 825, 935, 662, 663, 664, 830, 665, - 666, 834, 945, 1033, 1117, 667, 992, 668, 837, 947, - 669, 670, 840, 950, 439, 320, 41, 127, 227, 384, - 385, 386, 571, 387, 388, 573, 672, 673, 1091, 1233, - 1093, 1094, 927, 928, 797, 345, 621, 1095, 1138, 798, - 622, 1096, 803, 922, 407, 408, 1055, 409, 410, 1060, - 411, 605, 606, 607, 787, 1008, 1010, 1012, 1009, 1100, - 1184, 1234, 1243, 1185, 1250, 1192, 1258, 1263, 1193, 1268, - 1216, 1254, 1186, 1235, 1236, 1244, 1245, 1237, 1238, 1098, - 42, 234, 322, 490, 256, 323, 235, 129, 229, 494, - 230, 398, 580, 392, 393, 577, 575, 244, 237, 402, - 403, 590, 498, 586, 776, 587, 782, 46, 47, 48, - 49, 50, 412, 131, 51, 52, 245, 394, 511, 54, - 134, 248, 424, 413, 414, 610, 792, 239, 56, 136, - 191, 267, 268, 442, 57, 58, 240, 241, 713, 242, - 243, 419, 800, 59, 428, 60, 139, 253, 254, 432, - 429, 874, 682, 627, 805, 929, 61, 62, 63, 259, - 436, 1068, 1110, 1111, 1198, 64, 260, 66, 67, 68, - 271, 70, 71, 72, 276, 74, 75, 76, 281, 198, - 78, 287, 288, 456, 289, 290, 459, 855, 683, 973, - 417, 613, 475, 476, 688, 684, 1044, 1045, 1046, 685, - 686, 962, 79, 80, 81, 82, 149, 293, 294, 83, - 261, 262, 263, 264, 84, 272, 273, 85, 277, 278, - 86, 282, 283, 87, 470, 88, 151, 301, 302, 305, - 306, 472, 89, 170, 90, 171, 172, 856, 903, 92, - 174, 178, 179, 311, 312, 955, 956, 849, 850, 93, - 773, 857, 95, 858, 1140, 96, 690, 97, 98, 479, - 966, 1006, 480, 967 -}; - - /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule whose - number is the opposite. If YYTABLE_NINF, syntax error. */ -static const yytype_int16 yytable[] = -{ - 40, 247, 103, 218, 313, 378, 55, 45, 104, 105, - 65, 106, 316, 107, 314, 108, 77, 109, 430, 69, - 916, 110, 73, 111, 161, 112, 236, 113, 488, 114, - 426, 115, 258, 116, 391, 117, 175, 176, 860, 118, - 487, 318, 160, 246, 826, 119, 250, 120, 644, 121, - 680, 122, 553, 123, 556, 124, 881, 53, 847, 132, - 957, 435, 137, 569, 140, 565, 142, 1079, 144, 1018, - 146, 469, 827, 848, 1, 831, 828, 99, 844, 832, - 919, 852, 835, 843, 153, 959, 738, 1, 1003, 838, - 238, 155, 1092, 156, 846, 193, 159, 195, 1021, 733, - 427, 421, 125, 1246, 1246, 1092, 1251, 1255, 404, 1260, - 5, 1265, 1265, 379, 1269, 1011, 1013, 1087, 405, 647, - 5, 19, 752, 1, 755, 1253, 758, 270, 761, 681, - 763, 12, 404, 795, 10, 251, 209, 399, 796, 233, - 415, 382, 795, 17, 15, 34, 5, 796, 653, 26, - 423, 433, 5, 29, 1036, 1087, 452, 252, 5, 17, - 2, 1106, 26, 1231, 295, 471, 29, 1309, 481, 24, - 4, 296, 482, 298, 1097, 1314, 299, 980, 937, 17, - 285, 917, 33, 406, 31, 32, 1020, 324, 953, 1319, - 266, 1089, 325, 1320, 327, 430, 257, 286, 26, 793, - 330, 335, 29, 954, 1318, 1013, 938, 406, 582, 940, - 939, 338, 965, 941, 339, 942, 228, 390, 1002, 943, - 1101, 343, 1024, 1104, 952, 347, 1, 948, 231, 1089, - 350, 629, 1200, 400, 427, 353, 795, 232, 420, 435, - 356, 796, 5, 249, 811, 359, 1271, 362, 10, 1242, - 1242, 364, 1249, 469, 365, 879, 469, 366, 1015, 559, - 765, 1121, 767, 368, 1204, 583, 1069, 859, 877, 373, - 1062, 468, 779, 1016, 2, 1025, 616, 884, 233, 177, - 1187, 886, 1194, 2, 4, 889, 891, 892, 1119, 466, - 895, 896, 650, 4, 898, 228, 589, 1203, 31, 32, - 1077, 26, 1228, 1026, 1028, 29, 1051, 1027, 1029, 1030, - 1031, 1049, 5, 1308, 651, 652, 1311, 5, 265, 462, - 463, 1313, 696, 9, 1316, 698, 647, 1050, 1317, 5, - 380, 381, 1142, 1143, 737, 641, 427, 180, 643, 228, - 19, 16, 6, 485, 5, 486, 440, 257, 15, 614, - 491, 8, -600, 651, 652, 618, 679, 22, 10, 619, - 499, 1337, 284, 285, 34, 681, 633, 1339, 500, -602, - 5, 503, 280, 30, 505, 1231, 1090, 703, 1083, 233, - -603, 1102, 1084, 1085, 1086, -604, 33, 516, 5, 1108, - 20, 1112, 520, 1231, 5, 1113, 1114, 1115, 378, 986, - 987, 988, 989, 647, 27, 646, 28, 5, 31, 32, - 378, -605, 21, 780, 35, 1083, 647, 10, 292, 1084, - 1085, 1086, 551, 315, 554, 5, 557, 211, 1230, 487, - 1231, 652, -42, 563, 806, 907, 36, 566, 233, 816, - 1088, 643, 17, 488, 125, 210, 211, 310, 212, 213, - 214, 215, 216, 674, 1224, 618, 676, 401, 21, 619, - 1199, 1202, 415, 275, 819, 5, 823, 31, 32, 823, - 5, 1, 823, 649, 650, 823, 7, 1088, 823, 647, - 692, 1338, 36, 649, 650, 536, 231, 537, 443, 574, - 1073, 446, 427, 579, 449, 232, 651, 652, 788, 789, - 783, 1239, 473, 737, 477, 675, 651, 652, 677, 1261, - 620, 678, 615, 405, 1083, 807, 5, 5, 1084, 1085, - 1086, 1240, 1231, 233, 5, 100, 101, 17, 1240, 1231, - 474, 809, 438, 634, 643, 812, 784, 785, 786, 445, - 478, 997, 448, 999, 702, 451, 26, 380, 636, 671, - 29, 640, 671, 461, 638, 671, -63, 1038, 537, 452, - 381, 1039, 1040, 1041, 1042, 689, 5, 1083, 1007, 201, - 202, 1084, 1085, 1086, 1087, 647, 1088, 5, 833, 718, - 650, 836, 5, 303, 304, 1230, 647, 1231, 390, 648, - 649, 650, 964, 536, 378, 1083, 1057, 215, 216, 1084, - 1085, 1086, 651, 652, 735, 5, 823, 866, 823, 258, - 643, 812, 823, 651, 652, 653, 747, 841, 750, 1043, - 537, 753, 1075, 756, 737, 759, 648, 762, 923, 1088, - 764, 1083, 924, 925, 926, 1084, 1085, 1086, 1087, 771, - 1007, 5, 608, 774, 611, 584, 585, 777, 1089, 617, - 647, 790, 624, 648, 649, 650, 652, 1088, -71, 375, - 1107, 882, 632, -71, -71, -71, 228, 390, 635, 737, - 734, 637, 651, 652, 639, 878, 932, 651, 652, 653, - 307, 308, 309, 1007, 1125, 645, 964, 817, 921, 10, - 821, 3, 5, 1088, 820, 1132, 1133, 452, 936, 6, - 568, 647, 1034, 823, 648, 649, 650, 1208, 8, 1124, - 233, 1128, 1089, 737, 17, 9, 631, 794, 11, 944, - 1103, 946, 979, 1247, 255, 1264, 1264, 1259, 651, 652, - 653, 643, 1266, 16, 1109, 808, 43, 125, 210, 31, - 32, 212, 213, 214, 18, 44, 818, 20, 822, 22, - 699, 822, 1063, 1064, 822, 870, 578, 822, 960, 25, - 822, 27, 141, 28, 143, 30, 145, 152, 147, 154, - 378, 35, 671, 257, 210, 853, 1022, 212, 213, 214, - 215, 216, 1223, 297, 736, 799, 1, 2, 869, 1226, - 921, 210, 3, 1037, 212, 213, 214, 4, 920, 5, - 6, 5, 994, 995, 1081, 1082, 7, 908, 625, 8, - 647, 157, 1032, 648, 649, 650, 9, 10, 464, 11, - 643, 12, 905, 906, 158, 434, 13, 845, 14, 689, - 630, 15, 1196, 465, 16, 300, 467, 651, 652, 653, - 457, 162, 17, 5, 163, 18, 164, 19, 20, 21, - 22, 165, 647, 166, 167, 648, 649, 650, 23, 24, - 25, 26, 27, 168, 28, 29, 30, 31, 32, 33, - 169, 34, 35, 36, 91, 94, 1321, 1052, 427, 651, - 652, 653, 921, 0, 0, 976, 5, 0, 822, 0, - 822, 0, 0, 0, 822, 647, 1116, 427, 648, 649, - 650, 0, 671, 0, 0, 5, 0, 681, 0, 0, - 0, 951, 845, 998, 647, 0, 0, 648, 649, 650, - 0, 1004, 651, 652, 653, 0, 681, 0, 0, 427, - 0, 845, 0, 0, 0, 210, 211, 5, 212, 213, - 214, 651, 652, 653, 0, 0, 647, 0, 0, 648, - 649, 650, 0, 921, 0, 0, 0, 0, 681, 0, - 1048, 0, 0, 0, 0, 0, 1056, 0, 1058, 0, - 1061, 0, 1014, 651, 652, 653, 0, 5, 0, 0, - 0, 0, 0, 0, 416, 822, 647, 0, 422, 648, - 649, 650, 0, 0, 0, 0, 671, 437, 0, 0, - 0, 0, 0, 1078, 444, 671, 0, 447, 0, 0, - 450, 0, 16, 651, 652, 653, 0, 0, 460, 0, - 0, 0, 0, 921, 181, 0, 182, 0, 183, 184, - 0, 185, 0, 186, 187, 0, 188, 189, 190, 192, - 190, 194, 190, 196, 197, 0, 199, 0, 200, 0, - 0, 1122, 5, 1123, 671, 0, 0, 0, 0, 671, - 0, 647, 0, 0, 648, 649, 650, 671, 1134, 204, - 0, 205, 206, 207, 0, 208, 0, 1312, 845, 125, - 210, 211, 5, 212, 213, 214, 215, 216, 651, 652, - 653, 647, 0, 0, 648, 649, 650, 0, 0, 1310, - 0, 1107, 0, 0, 0, 210, 0, 1315, 212, 213, - 214, 215, 216, 735, 0, 736, 0, 0, 651, 652, - 653, 0, 0, 0, 319, 0, 321, 0, 0, 0, - 0, 671, 0, 326, 0, 328, 0, 329, 0, 671, - 0, 331, 332, 333, 0, 334, 190, 336, 0, 0, - 337, 0, 0, 0, 0, 340, 341, 0, 342, 0, - 0, 1227, 0, 0, 346, 0, 0, 0, 348, 349, - 0, 0, 0, 351, 352, 0, 0, 0, 354, 355, - 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, - 363, 0, 0, 1277, 0, 1280, 0, 0, 367, 0, - 0, 0, 1285, 0, 369, 370, 371, 0, 372, 1232, - 1232, 1241, 1241, 0, 1248, 1252, 0, 1257, 1232, 1262, - 1262, 0, 1267, 1144, 1145, 1146, 1147, 1148, 1149, 1150, - 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, - 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, - 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, - 1181, 1182, 1183, 591, 592, 593, 594, 595, 596, 597, - 598, 599, 600, 601, 602, 603, 604, 0, 0, 0, - 0, 483, 484, 0, 0, 0, 0, 0, 321, 489, - 0, 492, 0, 0, 0, 493, 495, 496, 0, 497, - 0, 210, 211, 0, 212, 213, 214, 215, 216, 0, - 502, 736, 0, 504, 0, 0, 506, 507, 0, 509, - 0, 510, 0, 512, 0, 0, 514, 0, 0, 0, - 518, 519, 0, 0, 522, 523, 0, 0, 0, 0, - 0, 528, 529, 0, 531, 532, 0, 534, 535, 210, - 211, 0, 212, 213, 214, 215, 216, 545, 546, 547, - 548, 549, 0, 552, 0, 555, 0, 0, 0, 0, - 561, 0, 562, 0, 564, 0, 555, 1188, 1145, 1146, - 1147, 1148, 1149, 1150, 1151, 1189, 1153, 1154, 1155, 1156, - 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, - 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, - 1190, 1191, 1179, 1180, 1181, 1182, 1183, 1145, 1146, 1147, - 1148, 1149, 1150, 1151, 0, 1153, 1154, 1155, 1156, 1157, - 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, - 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 0, - 0, 1179, 1180, 1181, 1182, 1183, 591, 592, 593, 594, - 595, 596, 597, 598, 599, 693, 0, 0, 0, 0, - 0, 0, 489, 0, 0, 489, 0, 493, 0, 700, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 705, 706, 707, 0, 0, 708, 0, 0, - 710, 711, 712, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 720, 0, 721, 0, 723, 0, - 725, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 745, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 746, 0, 748, 0, 0, - 751, 0, 754, 0, 757, 0, 760, 0, 760, 0, - 0, 555, 766, 555, 768, 769, 0, 770, 0, 0, - 772, 0, 0, 0, 0, 775, 0, 0, 0, 778, - 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, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 700, 0, 775, - 0, 0, 0, 0, 0, 0, 0, 864, 0, 0, - 868, 712, 0, 0, 0, 0, 871, 0, 0, 0, - 872, 0, 873, 721, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 760, 0, 885, 0, 760, - 0, 0, 0, 888, 890, 760, 0, 0, 894, 760, - 0, 897, 760, 0, 899, 0, 0, 900, 0, 0, - 902, 904, 0, 0, 772, 772, 555, 0, 0, 909, - 0, 0, 0, 0, 0, 0, 911, 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, 963, 0, 0, - 968, 969, 970, 269, 972, 274, 974, 279, 0, 0, - 291, 0, 0, 0, 0, 0, 0, 0, 978, 0, - 0, 0, 0, 982, 983, 984, 0, 985, 760, 760, - 760, 0, 990, 0, 991, 0, 0, 0, 0, 0, - 902, 902, 996, 0, 555, 0, 1000, 0, 0, 775, - 0, 0, 0, 1005, 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, 1054, 0, 555, 0, 1059, - 0, 775, 972, 972, 0, 0, 0, 1066, 1067, 0, - 0, 0, 1070, 1071, 0, 1072, 0, 0, 760, 0, - 1074, 0, 0, 555, 0, 374, 0, 0, 0, 0, - 0, 775, 389, 0, 395, 396, 1080, 0, 1005, 1005, - 0, 0, 0, 0, 0, 0, 0, 425, 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, 1054, 555, 0, 1126, 1127, 0, - 1059, 1129, 0, 0, 0, 0, 1131, 555, 0, 1135, - 0, 0, 357, 358, 0, 361, 1137, 1139, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 501, 0, 0, 0, 0, 1207, - 1137, 1209, 0, 508, 0, 0, 0, 0, 0, 1210, - 513, 0, 0, 0, 0, 0, 0, 0, 521, 0, - 0, 0, 0, 0, 526, 527, 0, 0, 530, 0, - 0, 533, 0, 0, 1211, 1212, 0, 0, 542, 0, - 0, 544, 0, 1214, 1215, 1217, 1218, 1219, 1220, 0, - 0, 1222, 558, 555, 560, 775, 0, 0, 0, 0, - 555, 0, 0, 567, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 581, 0, 0, 0, - 588, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1275, 623, 1278, 0, 0, 0, 0, 628, - 0, 1283, 0, 1286, 0, 0, 0, 0, 1290, 0, - 0, 0, 1294, 0, 0, 515, 1297, 0, 517, 0, - 0, 1301, 0, 0, 0, 524, 525, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 543, 0, 0, 0, 691, 0, 0, - 0, 0, 0, 694, 0, 695, 0, 0, 0, 697, - 0, 0, 0, 1139, 0, 701, 1323, 1325, 0, 0, - 0, 1329, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 709, 0, 0, 0, 0, 714, 715, - 0, 0, 0, 0, 0, 0, 719, 0, 0, 0, - 0, 0, 722, 0, 724, 0, 726, 727, 728, 729, - 730, 731, 732, 0, 0, 0, 0, 744, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 126, 128, 0, 0, 133, 135, 0, 138, 0, - 135, 0, 135, 0, 135, 0, 135, 148, 150, 0, - 173, 173, 173, 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, 801, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 716, 717, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 226, 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, 851, 0, 0, 854, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 867, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 876, 0, 0, 0, 0, 0, 0, 0, 883, 0, - 0, 0, 0, 0, 0, 0, 0, 887, 0, 0, - 0, 0, 893, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 901, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 910, 0, 912, 913, 914, 915, 0, 0, 0, 0, - 0, 918, 0, 0, 0, 0, 930, 931, 383, 0, - 0, 0, 0, 397, 128, 0, 0, 0, 0, 418, - 0, 0, 0, 861, 862, 863, 865, 431, 128, 0, - 0, 0, 418, 0, 0, 958, 441, 0, 0, 418, - 0, 0, 418, 875, 0, 418, 0, 0, 455, 0, - 0, 458, 0, 418, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 981, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 993, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1001, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1017, 0, 1019, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1035, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1047, 0, 0, 0, 1053, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 971, 0, 0, 0, 0, 0, 975, 0, - 0, 0, 0, 0, 0, 977, 0, 0, 0, 1076, - 0, 0, 0, 0, 570, 572, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 609, 0, 612, 0, 0, 1105, 0, 0, - 0, 0, 0, 0, 0, 626, 0, 0, 0, 1118, - 0, 1120, 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, 1136, - 0, 0, 687, 0, 1065, 173, 0, 0, 0, 0, - 0, 0, 1195, 0, 0, 0, 0, 0, 0, 0, - 1201, 0, 1205, 1206, 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, 1213, 0, 0, 0, - 0, 0, 0, 0, 1221, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1229, 0, 1130, 0, 0, 0, 0, 0, 1256, 0, - 0, 0, 0, 0, 0, 0, 1270, 1141, 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, 781, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1306, 1307, 0, 0, 802, 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, 1225, 0, 0, 824, - 0, 0, 829, 0, 1327, 0, 0, 1331, 0, 0, - 0, 839, 0, 0, 0, 0, 0, 0, 0, 0, - 626, 0, 0, 626, 1272, 0, 0, 0, 1273, 1274, - 1341, 1276, 0, 1279, 0, 0, 0, 1281, 1282, 0, - 1284, 0, 1287, 0, 1288, 1289, 0, 1291, 1292, 1293, - 0, 1295, 0, 1296, 0, 1298, 1299, 0, 1300, 0, - 1302, 1303, 0, 1304, 0, 1305, 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, 1322, 1324, 0, 1326, 0, 1328, - 1330, 0, 1332, 1333, 1334, 1335, 1336, 0, 0, 802, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1340, 0, 1342, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 949, - 0, 0, 0, 0, 0, 0, 0, 0, 961, 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, 802, 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, 626, 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, 1099, 0, 1099, 0, 0, - 1099, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 802, 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, 802, 802, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1197 -}; - -static const yytype_int16 yycheck[] = -{ - 0, 185, 45, 181, 209, 315, 0, 0, 51, 52, - 0, 54, 224, 56, 217, 58, 0, 60, 337, 0, - 864, 64, 0, 66, 120, 68, 183, 70, 391, 72, - 336, 74, 189, 76, 321, 78, 122, 123, 782, 82, - 391, 225, 120, 184, 751, 88, 187, 90, 541, 92, - 561, 94, 466, 96, 468, 98, 813, 0, 772, 105, - 902, 341, 108, 484, 110, 479, 112, 1048, 114, 974, - 116, 367, 751, 772, 4, 754, 751, 0, 771, 754, - 870, 774, 757, 770, 120, 904, 644, 4, 963, 762, - 183, 120, 1054, 120, 772, 143, 120, 145, 978, 641, - 9, 332, 146, 1211, 1212, 1067, 1214, 1215, 6, 1217, - 17, 1219, 1220, 316, 1222, 969, 970, 14, 16, 26, - 17, 65, 663, 4, 665, 1215, 667, 71, 669, 38, - 671, 39, 6, 7, 35, 3, 179, 325, 12, 56, - 48, 319, 7, 60, 49, 89, 17, 12, 55, 79, - 334, 339, 17, 83, 996, 14, 359, 25, 17, 60, - 5, 1066, 79, 22, 200, 368, 83, 1275, 373, 77, - 15, 200, 375, 200, 1054, 1283, 200, 934, 885, 60, - 51, 868, 87, 81, 85, 86, 976, 230, 902, 1297, - 190, 88, 235, 1301, 237, 514, 189, 197, 79, 710, - 243, 249, 83, 902, 1294, 1059, 885, 81, 495, 888, - 885, 254, 911, 888, 257, 890, 61, 62, 962, 894, - 1058, 264, 979, 1061, 902, 268, 4, 900, 19, 88, - 273, 518, 1137, 326, 9, 278, 7, 28, 331, 519, - 283, 12, 17, 186, 737, 288, 1227, 290, 35, 1211, - 1212, 294, 1214, 549, 297, 813, 552, 300, 972, 471, - 674, 1080, 676, 306, 1139, 496, 1023, 778, 810, 312, - 1014, 367, 693, 972, 5, 982, 507, 818, 56, 40, - 1127, 822, 1129, 5, 15, 826, 827, 828, 1078, 367, - 831, 832, 31, 15, 835, 61, 499, 1139, 85, 86, - 1044, 79, 1207, 982, 983, 83, 1005, 982, 983, 984, - 985, 1004, 17, 1275, 53, 54, 1278, 17, 23, 365, - 366, 1283, 575, 34, 1286, 578, 26, 1005, 1290, 17, - 32, 33, 1122, 1123, 644, 538, 9, 162, 541, 61, - 65, 52, 18, 386, 17, 388, 346, 340, 49, 506, - 393, 27, 162, 53, 54, 7, 559, 68, 35, 11, - 403, 1323, 50, 51, 89, 38, 523, 1329, 411, 162, - 17, 414, 73, 84, 417, 22, 1054, 589, 7, 56, - 162, 1059, 11, 12, 13, 162, 87, 430, 17, 1067, - 66, 1070, 435, 22, 17, 1070, 1071, 1072, 708, 940, - 941, 942, 943, 26, 80, 546, 82, 17, 85, 86, - 720, 162, 67, 700, 90, 7, 26, 35, 64, 11, - 12, 13, 465, 149, 467, 17, 469, 148, 20, 780, - 22, 54, 149, 476, 721, 849, 91, 480, 56, 745, - 69, 644, 60, 806, 146, 147, 148, 41, 150, 151, - 152, 153, 154, 549, 1198, 7, 552, 57, 67, 11, - 1135, 1139, 48, 72, 746, 17, 748, 85, 86, 751, - 17, 4, 754, 30, 31, 757, 24, 69, 760, 26, - 566, 1325, 91, 30, 31, 154, 19, 156, 348, 489, - 1031, 351, 9, 493, 354, 28, 53, 54, 706, 707, - 703, 1210, 369, 813, 371, 551, 53, 54, 554, 1218, - 510, 557, 506, 16, 7, 723, 17, 17, 11, 12, - 13, 21, 22, 56, 17, 158, 159, 60, 21, 22, - 25, 734, 343, 523, 737, 738, 150, 151, 152, 350, - 47, 955, 353, 957, 587, 356, 79, 32, 529, 549, - 83, 535, 552, 364, 532, 555, 154, 7, 156, 762, - 33, 11, 12, 13, 14, 45, 17, 7, 8, 160, - 161, 11, 12, 13, 14, 26, 69, 17, 756, 622, - 31, 759, 17, 74, 75, 20, 26, 22, 62, 29, - 30, 31, 911, 154, 904, 7, 1010, 153, 154, 11, - 12, 13, 53, 54, 155, 17, 888, 791, 890, 766, - 813, 814, 894, 53, 54, 55, 659, 146, 661, 69, - 156, 664, 1036, 666, 934, 668, 29, 670, 7, 69, - 673, 7, 11, 12, 13, 11, 12, 13, 14, 682, - 8, 17, 502, 686, 504, 58, 59, 690, 88, 509, - 26, 708, 512, 29, 30, 31, 54, 69, 155, 315, - 36, 814, 522, 160, 161, 162, 61, 62, 528, 979, - 642, 531, 53, 54, 534, 811, 879, 53, 54, 55, - 205, 206, 207, 8, 1098, 545, 1005, 746, 872, 35, - 748, 10, 17, 69, 747, 1109, 1110, 900, 885, 18, - 483, 26, 991, 985, 29, 30, 31, 1143, 27, 1097, - 56, 1103, 88, 1023, 60, 34, 520, 711, 37, 897, - 1059, 899, 934, 1212, 70, 1219, 1220, 1217, 53, 54, - 55, 934, 1220, 52, 1067, 725, 0, 146, 147, 85, - 86, 150, 151, 152, 63, 0, 746, 66, 748, 68, - 580, 751, 1015, 1016, 754, 798, 492, 757, 908, 78, - 760, 80, 111, 82, 113, 84, 115, 120, 117, 120, - 1080, 90, 772, 766, 147, 775, 979, 150, 151, 152, - 153, 154, 1196, 200, 157, 712, 4, 5, 794, 1203, - 974, 147, 10, 998, 150, 151, 152, 15, 871, 17, - 18, 17, 953, 954, 1051, 1052, 24, 850, 514, 27, - 26, 120, 990, 29, 30, 31, 34, 35, 367, 37, - 1023, 39, 847, 848, 120, 340, 44, 43, 46, 45, - 519, 49, 1131, 367, 52, 200, 367, 53, 54, 55, - 360, 120, 60, 17, 120, 63, 120, 65, 66, 67, - 68, 120, 26, 120, 120, 29, 30, 31, 76, 77, - 78, 79, 80, 120, 82, 83, 84, 85, 86, 87, - 120, 89, 90, 91, 0, 0, 1306, 1005, 9, 53, - 54, 55, 1066, -1, -1, 928, 17, -1, 888, -1, - 890, -1, -1, -1, 894, 26, 1074, 9, 29, 30, - 31, -1, 902, -1, -1, 17, -1, 38, -1, -1, - -1, 42, 43, 956, 26, -1, -1, 29, 30, 31, - -1, 964, 53, 54, 55, -1, 38, -1, -1, 9, - -1, 43, -1, -1, -1, 147, 148, 17, 150, 151, - 152, 53, 54, 55, -1, -1, 26, -1, -1, 29, - 30, 31, -1, 1137, -1, -1, -1, -1, 38, -1, - 1003, -1, -1, -1, -1, -1, 1009, -1, 1011, -1, - 1013, -1, 972, 53, 54, 55, -1, 17, -1, -1, - -1, -1, -1, -1, 329, 985, 26, -1, 333, 29, - 30, 31, -1, -1, -1, -1, 996, 342, -1, -1, - -1, -1, -1, 1046, 349, 1005, -1, 352, -1, -1, - 355, -1, 52, 53, 54, 55, -1, -1, 363, -1, - -1, -1, -1, 1207, 127, -1, 129, -1, 131, 132, - -1, 134, -1, 136, 137, -1, 139, 140, 141, 142, - 143, 144, 145, 146, 147, -1, 149, -1, 151, -1, - -1, 1094, 17, 1096, 1054, -1, -1, -1, -1, 1059, - -1, 26, -1, -1, 29, 30, 31, 1067, 1111, 172, - -1, 174, 175, 176, -1, 178, -1, 1280, 43, 146, - 147, 148, 17, 150, 151, 152, 153, 154, 53, 54, - 55, 26, -1, -1, 29, 30, 31, -1, -1, 1277, - -1, 36, -1, -1, -1, 147, -1, 1285, 150, 151, - 152, 153, 154, 155, -1, 157, -1, -1, 53, 54, - 55, -1, -1, -1, 227, -1, 229, -1, -1, -1, - -1, 1131, -1, 236, -1, 238, -1, 240, -1, 1139, - -1, 244, 245, 246, -1, 248, 249, 250, -1, -1, - 253, -1, -1, -1, -1, 258, 259, -1, 261, -1, - -1, 1204, -1, -1, 267, -1, -1, -1, 271, 272, - -1, -1, -1, 276, 277, -1, -1, -1, 281, 282, - -1, -1, -1, -1, -1, -1, 289, -1, -1, -1, - 293, -1, -1, 1236, -1, 1238, -1, -1, 301, -1, - -1, -1, 1245, -1, 307, 308, 309, -1, 311, 1209, - 1210, 1211, 1212, -1, 1214, 1215, -1, 1217, 1218, 1219, - 1220, -1, 1222, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, -1, -1, -1, - -1, 384, 385, -1, -1, -1, -1, -1, 391, 392, - -1, 394, -1, -1, -1, 398, 399, 400, -1, 402, - -1, 147, 148, -1, 150, 151, 152, 153, 154, -1, - 413, 157, -1, 416, -1, -1, 419, 420, -1, 422, - -1, 424, -1, 426, -1, -1, 429, -1, -1, -1, - 433, 434, -1, -1, 437, 438, -1, -1, -1, -1, - -1, 444, 445, -1, 447, 448, -1, 450, 451, 147, - 148, -1, 150, 151, 152, 153, 154, 460, 461, 462, - 463, 464, -1, 466, -1, 468, -1, -1, -1, -1, - 473, -1, 475, -1, 477, -1, 479, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 107, 108, 109, - 110, 111, 112, 113, -1, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, -1, - -1, 141, 142, 143, 144, 145, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 568, -1, -1, -1, -1, - -1, -1, 575, -1, -1, 578, -1, 580, -1, 582, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 605, 606, 607, -1, -1, 610, -1, -1, - 613, 614, 615, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 627, -1, 629, -1, 631, -1, - 633, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 646, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 658, -1, 660, -1, -1, - 663, -1, 665, -1, 667, -1, 669, -1, 671, -1, - -1, 674, 675, 676, 677, 678, -1, 680, -1, -1, - 683, -1, -1, -1, -1, 688, -1, -1, -1, 692, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 780, -1, 782, - -1, -1, -1, -1, -1, -1, -1, 790, -1, -1, - 793, 794, -1, -1, -1, -1, 799, -1, -1, -1, - 803, -1, 805, 806, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 818, -1, 820, -1, 822, - -1, -1, -1, 826, 827, 828, -1, -1, 831, 832, - -1, 834, 835, -1, 837, -1, -1, 840, -1, -1, - 843, 844, -1, -1, 847, 848, 849, -1, -1, 852, - -1, -1, -1, -1, -1, -1, 859, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 910, -1, -1, - 913, 914, 915, 191, 917, 193, 919, 195, -1, -1, - 198, -1, -1, -1, -1, -1, -1, -1, 931, -1, - -1, -1, -1, 936, 937, 938, -1, 940, 941, 942, - 943, -1, 945, -1, 947, -1, -1, -1, -1, -1, - 953, 954, 955, -1, 957, -1, 959, -1, -1, 962, - -1, -1, -1, 966, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 1008, -1, 1010, -1, 1012, - -1, 1014, 1015, 1016, -1, -1, -1, 1020, 1021, -1, - -1, -1, 1025, 1026, -1, 1028, -1, -1, 1031, -1, - 1033, -1, -1, 1036, -1, 313, -1, -1, -1, -1, - -1, 1044, 320, -1, 322, 323, 1049, -1, 1051, 1052, - -1, -1, -1, -1, -1, -1, -1, 335, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 1097, 1098, -1, 1100, 1101, -1, - 1103, 1104, -1, -1, -1, -1, 1109, 1110, -1, 1112, - -1, -1, 286, 287, -1, 289, 1119, 1120, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 412, -1, -1, -1, -1, 1142, - 1143, 1144, -1, 421, -1, -1, -1, -1, -1, 1152, - 428, -1, -1, -1, -1, -1, -1, -1, 436, -1, - -1, -1, -1, -1, 442, 443, -1, -1, 446, -1, - -1, 449, -1, -1, 1177, 1178, -1, -1, 456, -1, - -1, 459, -1, 1186, 1187, 1188, 1189, 1190, 1191, -1, - -1, 1194, 470, 1196, 472, 1198, -1, -1, -1, -1, - 1203, -1, -1, 481, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 494, -1, -1, -1, - 498, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 1235, 511, 1237, -1, -1, -1, -1, 517, - -1, 1244, -1, 1246, -1, -1, -1, -1, 1251, -1, - -1, -1, 1255, -1, -1, 429, 1259, -1, 432, -1, - -1, 1264, -1, -1, -1, 439, 440, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 457, -1, -1, -1, 565, -1, -1, - -1, -1, -1, 571, -1, 573, -1, -1, -1, 577, - -1, -1, -1, 1306, -1, 583, 1309, 1310, -1, -1, - -1, 1314, 590, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 611, -1, -1, -1, -1, 616, 617, - -1, -1, -1, -1, -1, -1, 624, -1, -1, -1, - -1, -1, 630, -1, 632, -1, 634, 635, 636, 637, - 638, 639, 640, -1, -1, -1, -1, 645, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 102, 103, -1, -1, 106, 107, -1, 109, -1, - 111, -1, 113, -1, 115, -1, 117, 118, 119, -1, - 121, 122, 123, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 713, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 620, 621, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 181, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 773, -1, -1, 776, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 792, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 808, -1, -1, -1, -1, -1, -1, -1, 816, -1, - -1, -1, -1, -1, -1, -1, -1, 825, -1, -1, - -1, -1, 830, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 842, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 858, -1, 860, 861, 862, 863, -1, -1, -1, -1, - -1, 869, -1, -1, -1, -1, 874, 875, 319, -1, - -1, -1, -1, 324, 325, -1, -1, -1, -1, 330, - -1, -1, -1, 787, 788, 789, 790, 338, 339, -1, - -1, -1, 343, -1, -1, 903, 347, -1, -1, 350, - -1, -1, 353, 807, -1, 356, -1, -1, 359, -1, - -1, 362, -1, 364, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 935, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 950, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 960, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 973, -1, 975, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 992, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 1002, -1, -1, -1, 1006, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 916, -1, -1, -1, -1, -1, 922, -1, - -1, -1, -1, -1, -1, 929, -1, -1, -1, 1037, - -1, -1, -1, -1, 485, 486, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 503, -1, 505, -1, -1, 1065, -1, -1, - -1, -1, -1, -1, -1, 516, -1, -1, -1, 1077, - -1, 1079, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 1117, - -1, -1, 563, -1, 1018, 566, -1, -1, -1, -1, - -1, -1, 1130, -1, -1, -1, -1, -1, -1, -1, - 1138, -1, 1140, 1141, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 1184, -1, -1, -1, - -1, -1, -1, -1, 1192, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1208, -1, 1106, -1, -1, -1, -1, -1, 1216, -1, - -1, -1, -1, -1, -1, -1, 1224, 1121, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 702, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1271, 1272, -1, -1, 718, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 1200, -1, -1, 750, - -1, -1, 753, -1, 1312, -1, -1, 1315, -1, -1, - -1, 762, -1, -1, -1, -1, -1, -1, -1, -1, - 771, -1, -1, 774, 1228, -1, -1, -1, 1232, 1233, - 1338, 1235, -1, 1237, -1, -1, -1, 1241, 1242, -1, - 1244, -1, 1246, -1, 1248, 1249, -1, 1251, 1252, 1253, - -1, 1255, -1, 1257, -1, 1259, 1260, -1, 1262, -1, - 1264, 1265, -1, 1267, -1, 1269, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 1308, 1309, -1, 1311, -1, 1313, - 1314, -1, 1316, 1317, 1318, 1319, 1320, -1, -1, 870, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1337, -1, 1339, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 900, - -1, -1, -1, -1, -1, -1, -1, -1, 909, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 976, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1004, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 1056, -1, 1058, -1, -1, - 1061, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1078, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1122, 1123, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1134 -}; - - /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint16 yystos[] = -{ - 0, 4, 5, 10, 15, 17, 18, 24, 27, 34, - 35, 37, 39, 44, 46, 49, 52, 60, 63, 65, - 66, 67, 68, 76, 77, 78, 79, 80, 82, 83, - 84, 85, 86, 87, 89, 90, 91, 164, 165, 166, - 237, 239, 303, 304, 307, 309, 330, 331, 332, 333, - 334, 337, 338, 340, 342, 350, 351, 357, 358, 366, - 368, 379, 380, 381, 388, 389, 390, 391, 392, 393, - 394, 395, 396, 397, 398, 399, 400, 401, 403, 425, - 426, 427, 428, 432, 437, 440, 443, 446, 448, 455, - 457, 460, 462, 472, 474, 475, 478, 480, 481, 0, - 158, 159, 201, 201, 201, 201, 201, 201, 201, 201, - 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, - 201, 201, 201, 201, 201, 146, 204, 240, 204, 310, - 204, 336, 336, 204, 343, 204, 352, 336, 204, 369, - 336, 352, 336, 352, 336, 352, 336, 352, 204, 429, - 204, 449, 331, 332, 333, 334, 357, 380, 381, 391, - 395, 399, 425, 426, 427, 432, 437, 440, 443, 446, - 456, 458, 459, 204, 463, 463, 463, 40, 464, 465, - 162, 203, 203, 203, 203, 203, 203, 203, 203, 203, - 203, 353, 203, 353, 203, 353, 203, 203, 402, 203, - 203, 160, 161, 202, 203, 203, 203, 203, 203, 201, - 147, 148, 150, 151, 152, 153, 154, 167, 168, 169, - 171, 173, 174, 177, 179, 180, 204, 241, 61, 311, - 313, 19, 28, 56, 304, 309, 320, 321, 339, 350, - 359, 360, 362, 363, 320, 339, 359, 171, 344, 340, - 359, 3, 25, 370, 371, 70, 307, 309, 320, 382, - 389, 433, 434, 435, 436, 23, 237, 354, 355, 202, - 71, 393, 438, 439, 202, 72, 397, 441, 442, 202, - 73, 401, 444, 445, 50, 51, 237, 404, 405, 407, - 408, 202, 64, 430, 431, 332, 334, 338, 357, 391, - 392, 450, 451, 74, 75, 452, 453, 464, 464, 464, - 41, 466, 467, 166, 179, 149, 167, 178, 171, 203, - 238, 203, 305, 308, 201, 201, 203, 201, 203, 203, - 201, 203, 203, 203, 203, 353, 203, 203, 201, 201, - 203, 203, 203, 201, 203, 258, 203, 201, 203, 203, - 201, 203, 203, 201, 203, 203, 201, 258, 258, 201, - 203, 258, 201, 203, 201, 201, 201, 203, 201, 203, - 203, 203, 203, 201, 202, 172, 175, 176, 180, 179, - 32, 33, 168, 204, 242, 243, 244, 246, 247, 202, - 62, 311, 316, 317, 340, 202, 202, 204, 314, 310, - 339, 57, 322, 323, 6, 16, 81, 267, 268, 270, - 271, 273, 335, 346, 347, 48, 410, 413, 204, 364, - 339, 335, 410, 171, 345, 202, 366, 9, 367, 373, - 375, 204, 372, 310, 382, 273, 383, 410, 364, 237, - 237, 204, 356, 267, 410, 364, 267, 410, 364, 267, - 410, 364, 179, 183, 185, 204, 406, 404, 204, 409, - 410, 364, 336, 336, 379, 388, 395, 396, 399, 400, - 447, 179, 454, 466, 25, 415, 416, 466, 47, 482, - 485, 166, 179, 203, 203, 201, 201, 305, 308, 203, - 306, 201, 203, 203, 312, 203, 203, 203, 325, 201, - 201, 202, 203, 201, 203, 201, 203, 203, 202, 203, - 203, 341, 203, 202, 203, 258, 201, 258, 203, 203, - 201, 202, 203, 203, 258, 258, 202, 202, 203, 203, - 202, 203, 203, 202, 203, 203, 154, 156, 182, 184, - 188, 191, 202, 258, 202, 203, 203, 203, 203, 203, - 206, 201, 203, 206, 201, 203, 206, 201, 202, 167, - 202, 203, 203, 201, 203, 206, 201, 202, 243, 246, - 204, 245, 204, 248, 237, 319, 168, 318, 316, 237, - 315, 202, 311, 335, 58, 59, 326, 328, 202, 179, - 324, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 274, 275, 276, 267, 204, - 348, 267, 204, 414, 320, 350, 335, 267, 7, 11, - 237, 259, 263, 202, 267, 367, 204, 376, 202, 311, - 383, 274, 267, 320, 389, 267, 393, 267, 397, 267, - 401, 179, 186, 179, 192, 267, 359, 26, 29, 30, - 31, 53, 54, 55, 207, 209, 210, 211, 212, 213, - 214, 215, 218, 219, 220, 222, 223, 228, 230, 233, - 234, 237, 249, 250, 399, 336, 399, 336, 336, 179, - 415, 38, 375, 411, 418, 422, 423, 204, 417, 45, - 479, 202, 463, 203, 202, 202, 306, 202, 306, 312, - 203, 202, 201, 167, 202, 203, 203, 203, 203, 202, - 203, 203, 203, 361, 202, 202, 258, 258, 201, 202, - 203, 203, 202, 203, 202, 203, 202, 202, 202, 202, - 202, 202, 202, 184, 182, 155, 157, 180, 181, 189, - 192, 197, 198, 199, 202, 203, 203, 201, 203, 208, - 201, 203, 208, 201, 203, 208, 201, 203, 208, 201, - 203, 208, 201, 208, 201, 206, 203, 206, 203, 203, - 203, 201, 203, 473, 201, 203, 327, 201, 203, 246, - 311, 204, 329, 179, 150, 151, 152, 277, 277, 277, - 170, 172, 349, 415, 350, 7, 12, 257, 262, 346, - 365, 202, 204, 265, 170, 377, 311, 277, 389, 179, - 187, 192, 179, 193, 181, 200, 366, 211, 237, 249, - 214, 218, 237, 249, 204, 216, 222, 228, 233, 204, - 221, 228, 233, 168, 224, 233, 168, 231, 183, 204, - 235, 146, 205, 411, 376, 43, 207, 418, 422, 470, - 471, 202, 376, 237, 202, 410, 460, 474, 476, 415, - 327, 258, 258, 258, 203, 258, 171, 202, 203, 361, - 201, 203, 203, 203, 374, 258, 202, 184, 200, 181, - 190, 197, 193, 202, 208, 203, 208, 202, 203, 208, - 203, 208, 208, 202, 203, 208, 208, 203, 208, 203, - 203, 202, 203, 461, 203, 473, 473, 206, 201, 203, - 202, 203, 202, 202, 202, 202, 257, 411, 202, 265, - 365, 171, 266, 7, 11, 12, 13, 255, 256, 378, - 202, 202, 179, 194, 195, 217, 219, 222, 228, 233, - 228, 233, 233, 233, 168, 225, 168, 232, 183, 204, - 236, 42, 207, 418, 422, 468, 469, 470, 202, 377, - 318, 204, 424, 203, 375, 422, 483, 486, 203, 203, - 203, 258, 203, 412, 203, 258, 201, 258, 203, 167, - 197, 202, 203, 203, 203, 203, 208, 208, 208, 208, - 203, 203, 229, 202, 461, 461, 203, 206, 201, 206, - 203, 202, 327, 479, 201, 203, 484, 8, 278, 281, - 279, 281, 280, 281, 237, 418, 422, 202, 266, 202, - 265, 278, 179, 196, 197, 222, 228, 233, 228, 233, - 233, 233, 168, 226, 259, 202, 470, 166, 7, 11, - 12, 13, 14, 69, 419, 420, 421, 202, 201, 376, - 207, 422, 486, 202, 203, 269, 201, 206, 201, 203, - 272, 201, 327, 412, 412, 258, 203, 203, 384, 197, - 203, 203, 203, 208, 203, 206, 202, 327, 201, 476, - 203, 484, 484, 7, 11, 12, 13, 14, 69, 88, - 207, 251, 252, 253, 254, 260, 264, 278, 302, 204, - 282, 282, 207, 280, 282, 202, 266, 36, 207, 302, - 385, 386, 228, 233, 233, 233, 168, 227, 202, 265, - 202, 377, 201, 201, 269, 206, 203, 203, 272, 203, - 258, 203, 206, 206, 201, 203, 202, 203, 261, 203, - 477, 258, 265, 265, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 283, 286, 295, 295, 106, 114, - 139, 140, 288, 291, 295, 202, 385, 204, 387, 233, - 266, 202, 207, 470, 479, 202, 202, 203, 261, 203, - 203, 203, 203, 202, 203, 203, 293, 203, 203, 203, - 203, 202, 203, 206, 327, 258, 206, 201, 266, 202, - 20, 22, 237, 252, 284, 296, 297, 300, 301, 284, - 21, 237, 252, 285, 298, 299, 300, 285, 237, 252, - 287, 300, 237, 260, 294, 300, 202, 237, 289, 296, - 300, 284, 237, 290, 298, 300, 290, 237, 292, 300, - 202, 476, 258, 258, 258, 203, 258, 201, 203, 258, - 201, 258, 258, 203, 258, 201, 203, 258, 258, 258, - 203, 258, 258, 258, 203, 258, 258, 203, 258, 258, - 258, 203, 258, 258, 258, 258, 202, 202, 252, 300, - 168, 252, 179, 252, 300, 168, 252, 252, 260, 300, - 300, 477, 258, 203, 258, 203, 258, 202, 258, 203, - 258, 202, 258, 258, 258, 258, 258, 252, 257, 252, - 258, 202, 258 -}; - - /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint16 yyr1[] = -{ - 0, 163, 164, 164, 164, 164, 164, 164, 164, 164, - 164, 164, 165, 165, 165, 165, 165, 165, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 167, 168, 168, 169, 170, 171, 171, 172, - 172, 173, 174, 175, 176, 177, 177, 178, 178, 179, - 179, 179, 179, 180, 180, 181, 182, 183, 183, 183, - 184, 184, 185, 186, 187, 188, 189, 189, 190, 190, - 191, 192, 193, 194, 194, 194, 195, 196, 197, 197, - 198, 199, 199, 200, 200, 201, 201, 202, 202, 203, - 204, 205, 206, 206, 207, 207, 207, 208, 208, 208, - 209, 209, 210, 210, 210, 211, 211, 211, 211, 212, - 213, 214, 215, 216, 217, 217, 217, 217, 217, 217, - 217, 217, 217, 217, 217, 217, 217, 217, 217, 218, - 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, - 218, 218, 218, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, - 234, 235, 235, 236, 236, 237, 238, 238, 238, 238, - 238, 238, 238, 239, 240, 241, 241, 242, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 251, 252, - 253, 254, 254, 254, 254, 254, 255, 256, 256, 256, - 256, 257, 258, 258, 259, 260, 261, 261, 262, 262, - 263, 263, 264, 264, 265, 266, 267, 267, 267, 268, - 269, 269, 269, 269, 270, 271, 272, 272, 272, 273, - 274, 274, 274, 274, 274, 274, 274, 274, 274, 275, - 275, 275, 276, 276, 277, 277, 277, 278, 279, 280, - 281, 282, 283, 283, 283, 283, 283, 283, 283, 283, - 283, 284, 284, 284, 284, 284, 284, 284, 284, 285, - 285, 285, 285, 285, 285, 285, 285, 286, 286, 287, - 287, 287, 287, 288, 288, 288, 288, 288, 288, 288, - 288, 288, 289, 289, 289, 289, 290, 290, 290, 290, - 291, 291, 292, 292, 293, 293, 294, 294, 294, 294, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, - 295, 295, 295, 295, 295, 295, 296, 297, 298, 299, - 300, 301, 302, 303, 303, 304, 305, 305, 306, 306, - 307, 308, 308, 309, 310, 311, 312, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 324, 324, 325, 325, 326, 327, 327, 328, 328, 329, - 330, 330, 330, 330, 331, 332, 333, 334, 335, 335, - 336, 337, 337, 338, 338, 339, 339, 340, 341, 341, - 341, 342, 342, 343, 344, 345, 346, 347, 347, 348, - 349, 349, 350, 351, 351, 351, 352, 353, 353, 353, - 353, 354, 355, 356, 357, 358, 358, 359, 359, 360, - 361, 361, 361, 361, 362, 363, 363, 364, 365, 366, - 367, 367, 368, 369, 370, 371, 371, 372, 373, 374, - 374, 375, 376, 377, 378, 379, 379, 380, 381, 382, - 382, 383, 384, 384, 384, 384, 384, 385, 386, 387, - 388, 388, 389, 390, 390, 390, 391, 392, 392, 393, - 394, 394, 395, 396, 397, 398, 398, 399, 400, 401, - 402, 402, 402, 402, 402, 403, 403, 404, 405, 406, - 406, 407, 408, 409, 410, 411, 411, 412, 412, 412, - 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, - 421, 421, 421, 421, 421, 422, 423, 424, 425, 426, - 427, 428, 429, 430, 431, 432, 433, 433, 434, 435, - 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 447, 447, 447, 447, 448, 449, 450, 450, - 450, 451, 451, 452, 453, 453, 454, 454, 454, 455, - 456, 456, 457, 458, 458, 458, 458, 458, 458, 458, - 458, 458, 458, 458, 458, 458, 458, 458, 459, 459, - 459, 459, 459, 459, 459, 459, 460, 461, 461, 461, - 461, 461, 461, 461, 462, 463, 464, 465, 466, 467, - 468, 469, 470, 471, 472, 473, 473, 473, 473, 473, - 474, 475, 476, 476, 476, 477, 477, 477, 477, 478, - 479, 480, 481, 482, 483, 483, 484, 484, 484, 484, - 485, 486 -}; - - /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 2, 1, 1, 0, - 1, 3, 1, 1, 2, 2, 2, 0, 2, 1, - 1, 1, 1, 1, 1, 1, 1, 2, 4, 6, - 0, 1, 1, 1, 1, 3, 3, 1, 2, 1, - 1, 1, 1, 3, 4, 2, 1, 1, 1, 1, - 1, 3, 2, 0, 2, 1, 1, 1, 1, 1, - 1, 1, 0, 2, 1, 2, 1, 0, 3, 2, - 1, 1, 3, 2, 1, 1, 3, 4, 3, 6, - 1, 4, 1, 1, 1, 1, 1, 1, 3, 3, - 3, 3, 3, 3, 5, 5, 5, 5, 7, 2, - 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, - 6, 6, 6, 8, 4, 1, 1, 10, 1, 1, - 1, 1, 1, 7, 0, 2, 1, 1, 1, 6, - 1, 1, 1, 1, 1, 7, 0, 2, 4, 6, - 2, 4, 2, 1, 1, 1, 1, 1, 1, 4, - 1, 1, 4, 1, 1, 4, 1, 1, 1, 1, - 7, 1, 1, 1, 1, 1, 7, 1, 1, 1, - 1, 7, 0, 3, 7, 5, 0, 3, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, - 0, 3, 3, 2, 10, 10, 0, 3, 2, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 6, 7, 6, - 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, - 3, 2, 4, 6, 4, 2, 4, 2, 2, 2, - 4, 6, 4, 2, 4, 2, 2, 1, 3, 2, - 2, 4, 2, 1, 1, 3, 1, 3, 1, 3, - 1, 3, 2, 4, 2, 2, 2, 4, 2, 2, - 1, 3, 2, 2, 0, 2, 2, 2, 4, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 6, 1, 4, 1, - 4, 1, 1, 1, 1, 7, 5, 3, 0, 3, - 7, 3, 3, 1, 1, 5, 0, 3, 1, 1, - 1, 4, 1, 1, 1, 5, 1, 4, 1, 1, - 2, 3, 0, 2, 5, 0, 2, 1, 1, 1, - 1, 1, 1, 1, 8, 8, 10, 10, 3, 1, - 1, 1, 1, 1, 1, 1, 1, 9, 0, 3, - 3, 1, 1, 1, 1, 1, 6, 1, 1, 1, - 4, 2, 7, 1, 1, 1, 1, 0, 2, 3, - 5, 4, 1, 1, 10, 1, 1, 1, 1, 7, - 0, 2, 4, 2, 9, 1, 1, 1, 1, 8, - 2, 3, 1, 1, 5, 1, 1, 1, 7, 0, - 3, 1, 1, 1, 1, 1, 1, 8, 10, 1, - 1, 10, 0, 3, 5, 3, 2, 5, 1, 1, - 1, 1, 5, 1, 1, 1, 8, 1, 1, 5, - 1, 1, 8, 1, 5, 1, 1, 8, 1, 5, - 0, 3, 5, 3, 3, 1, 1, 4, 1, 1, - 1, 4, 1, 1, 9, 1, 1, 0, 3, 3, - 3, 1, 1, 5, 1, 1, 9, 1, 5, 1, - 1, 1, 1, 1, 1, 7, 1, 1, 10, 10, - 10, 1, 1, 8, 1, 10, 1, 1, 6, 8, - 1, 10, 6, 1, 10, 6, 1, 10, 6, 1, - 8, 2, 2, 2, 4, 4, 1, 1, 1, 1, - 1, 1, 1, 4, 1, 1, 1, 2, 3, 4, - 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 13, 0, 3, 3, - 3, 5, 3, 2, 1, 1, 4, 1, 4, 1, - 4, 1, 4, 1, 11, 0, 3, 3, 3, 2, - 1, 19, 1, 1, 1, 0, 6, 3, 2, 1, - 1, 9, 1, 9, 1, 1, 0, 3, 3, 2, - 1, 7 -}; - - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (context, YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (0) - -/* Error token number */ -#define YYTERROR 1 -#define YYERRCODE 256 - - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - -/* This macro is provided for backward compatibility. */ -#ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -#endif - - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value, context); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - - -/*----------------------------------------. -| Print this symbol's value on YYOUTPUT. | -`----------------------------------------*/ - -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt2_parse_context *context) -{ - FILE *yyo = yyoutput; - YYUSE (yyo); - YYUSE (context); - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - YYUSE (yytype); -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt2_parse_context *context) -{ - YYFPRINTF (yyoutput, "%s %s (", - yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep, context); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -static void -yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, pj_wkt2_parse_context *context) -{ - unsigned long int yylno = yyrline[yyrule]; - int yynrhs = yyr2[yyrule]; - int yyi; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, - yystos[yyssp[yyi + 1 - yynrhs]], - &(yyvsp[(yyi + 1) - (yynrhs)]) - , context); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyssp, yyvsp, Rule, context); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -yystrlen (const char *yystr) -{ - YYSIZE_T yylen; - for (yylen = 0; yystr && yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -yystpcpy (char *yydest, const char *yysrc) -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) -{ - YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = YY_NULLPTR; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - { - YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } - } - - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } - - { - YYSIZE_T yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } - - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; -} -#endif /* YYERROR_VERBOSE */ - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, pj_wkt2_parse_context *context) -{ - YYUSE (yyvaluep); - YYUSE (context); - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yytype); - YY_IGNORE_MAYBE_UNINITIALIZED_END -} - - - - -/*----------. -| yyparse. | -`----------*/ - -int -yyparse (pj_wkt2_parse_context *context) -{ -/* The lookahead symbol. */ -int yychar; - - -/* The semantic value of the lookahead symbol. */ -/* Default value used for initialization, for pacifying older GCCs - or non-GCC compilers. */ -YY_INITIAL_VALUE (static YYSTYPE yyval_default;) -YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); - - /* Number of syntax errors so far. */ - int yynerrs; - - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - 'yyss': related to states. - 'yyvs': related to semantic values. - - Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - - int yyn; - int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - yyssp = yyss = yyssa; - yyvsp = yyvs = yyvsa; - yystacksize = YYINITDEPTH; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = (yytype_int16)yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = yylex (&yylval, context); - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yytable_value_is_error (yyn)) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the lookahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token. */ - yychar = YYEMPTY; - - yystate = yyn; - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - '$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - - - default: break; - } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - /* Now 'shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*--------------------------------------. -| yyerrlab -- here on detecting error. | -`--------------------------------------*/ -yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (context, YY_("syntax error")); -#else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) - { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (context, yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; - } -# undef YYSYNTAX_ERROR -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval, context); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -#if 0 -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule whose action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -#endif -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp, context); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - *++yyvsp = yylval; - YY_IGNORE_MAYBE_UNINITIALIZED_END - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#if !defined yyoverflow || YYERROR_VERBOSE -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (context, YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval, context); - } - /* Do not reclaim the symbols of the rule whose action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp, context); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - return yyresult; -} diff --git a/src/pj_wkt2_generated_parser.h b/src/pj_wkt2_generated_parser.h deleted file mode 100644 index f9d17ea0..00000000 --- a/src/pj_wkt2_generated_parser.h +++ /dev/null @@ -1,208 +0,0 @@ -/* A Bison parser, made by GNU Bison 3.0.4. */ - -/* Bison interface for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -#ifndef YY_PJ_WKT2_SRC_PJ_WKT2_GENERATED_PARSER_H_INCLUDED -# define YY_PJ_WKT2_SRC_PJ_WKT2_GENERATED_PARSER_H_INCLUDED -/* Debug traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif -#if YYDEBUG -extern int pj_wkt2_debug; -#endif - -/* Token type. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - enum yytokentype - { - END = 0, - T_PROJECTION = 258, - T_DATUM = 259, - T_SPHEROID = 260, - T_PRIMEM = 261, - T_UNIT = 262, - T_AXIS = 263, - T_PARAMETER = 264, - T_GEODCRS = 265, - T_LENGTHUNIT = 266, - T_ANGLEUNIT = 267, - T_SCALEUNIT = 268, - T_TIMEUNIT = 269, - T_ELLIPSOID = 270, - T_CS = 271, - T_ID = 272, - T_PROJCRS = 273, - T_BASEGEODCRS = 274, - T_MERIDIAN = 275, - T_BEARING = 276, - T_ORDER = 277, - T_ANCHOR = 278, - T_CONVERSION = 279, - T_METHOD = 280, - T_REMARK = 281, - T_GEOGCRS = 282, - T_BASEGEOGCRS = 283, - T_SCOPE = 284, - T_AREA = 285, - T_BBOX = 286, - T_CITATION = 287, - T_URI = 288, - T_VERTCRS = 289, - T_VDATUM = 290, - T_GEOIDMODEL = 291, - T_COMPOUNDCRS = 292, - T_PARAMETERFILE = 293, - T_COORDINATEOPERATION = 294, - T_SOURCECRS = 295, - T_TARGETCRS = 296, - T_INTERPOLATIONCRS = 297, - T_OPERATIONACCURACY = 298, - T_CONCATENATEDOPERATION = 299, - T_STEP = 300, - T_BOUNDCRS = 301, - T_ABRIDGEDTRANSFORMATION = 302, - T_DERIVINGCONVERSION = 303, - T_TDATUM = 304, - T_CALENDAR = 305, - T_TIMEORIGIN = 306, - T_TIMECRS = 307, - T_VERTICALEXTENT = 308, - T_TIMEEXTENT = 309, - T_USAGE = 310, - T_DYNAMIC = 311, - T_FRAMEEPOCH = 312, - T_MODEL = 313, - T_VELOCITYGRID = 314, - T_ENSEMBLE = 315, - T_MEMBER = 316, - T_ENSEMBLEACCURACY = 317, - T_DERIVEDPROJCRS = 318, - T_BASEPROJCRS = 319, - T_EDATUM = 320, - T_ENGCRS = 321, - T_PDATUM = 322, - T_PARAMETRICCRS = 323, - T_PARAMETRICUNIT = 324, - T_BASEVERTCRS = 325, - T_BASEENGCRS = 326, - T_BASEPARAMCRS = 327, - T_BASETIMECRS = 328, - T_EPOCH = 329, - T_COORDEPOCH = 330, - T_COORDINATEMETADATA = 331, - T_POINTMOTIONOPERATION = 332, - T_GEODETICCRS = 333, - T_GEODETICDATUM = 334, - T_PROJECTEDCRS = 335, - T_PRIMEMERIDIAN = 336, - T_GEOGRAPHICCRS = 337, - T_TRF = 338, - T_VERTICALCRS = 339, - T_VERTICALDATUM = 340, - T_VRF = 341, - T_TIMEDATUM = 342, - T_TEMPORALQUANTITY = 343, - T_ENGINEERINGDATUM = 344, - T_ENGINEERINGCRS = 345, - T_PARAMETRICDATUM = 346, - T_AFFINE = 347, - T_CARTESIAN = 348, - T_CYLINDRICAL = 349, - T_ELLIPSOIDAL = 350, - T_LINEAR = 351, - T_PARAMETRIC = 352, - T_POLAR = 353, - T_SPHERICAL = 354, - T_VERTICAL = 355, - T_TEMPORAL = 356, - T_TEMPORALCOUNT = 357, - T_TEMPORALMEASURE = 358, - T_ORDINAL = 359, - T_TEMPORALDATETIME = 360, - T_NORTH = 361, - T_NORTHNORTHEAST = 362, - T_NORTHEAST = 363, - T_EASTNORTHEAST = 364, - T_EAST = 365, - T_EASTSOUTHEAST = 366, - T_SOUTHEAST = 367, - T_SOUTHSOUTHEAST = 368, - T_SOUTH = 369, - T_SOUTHSOUTHWEST = 370, - T_SOUTHWEST = 371, - T_WESTSOUTHWEST = 372, - T_WEST = 373, - T_WESTNORTHWEST = 374, - T_NORTHWEST = 375, - T_NORTHNORTHWEST = 376, - T_UP = 377, - T_DOWN = 378, - T_GEOCENTRICX = 379, - T_GEOCENTRICY = 380, - T_GEOCENTRICZ = 381, - T_COLUMNPOSITIVE = 382, - T_COLUMNNEGATIVE = 383, - T_ROWPOSITIVE = 384, - T_ROWNEGATIVE = 385, - T_DISPLAYRIGHT = 386, - T_DISPLAYLEFT = 387, - T_DISPLAYUP = 388, - T_DISPLAYDOWN = 389, - T_FORWARD = 390, - T_AFT = 391, - T_PORT = 392, - T_STARBOARD = 393, - T_CLOCKWISE = 394, - T_COUNTERCLOCKWISE = 395, - T_TOWARDS = 396, - T_AWAYFROM = 397, - T_FUTURE = 398, - T_PAST = 399, - T_UNSPECIFIED = 400, - T_STRING = 401, - T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE = 402 - }; -#endif - -/* Value type. */ -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef int YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define YYSTYPE_IS_DECLARED 1 -#endif - - - -int pj_wkt2_parse (pj_wkt2_parse_context *context); - -#endif /* !YY_PJ_WKT2_SRC_PJ_WKT2_GENERATED_PARSER_H_INCLUDED */ diff --git a/src/pj_wkt2_grammar.y b/src/pj_wkt2_grammar.y deleted file mode 100644 index 2c8393e2..00000000 --- a/src/pj_wkt2_grammar.y +++ /dev/null @@ -1,1499 +0,0 @@ -%{ -/****************************************************************************** - * Project: PROJ - * Purpose: WKT2 parser grammar - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2018 Even Rouault, - * - * 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. - ****************************************************************************/ - -#include "pj_wkt2_parser.h" - -%} - -%define api.pure -%define parse.error verbose -%require "3.0" - -%parse-param {pj_wkt2_parse_context *context} -%lex-param {pj_wkt2_parse_context *context} - -/* From WKT1 */ -%token T_PROJECTION "PROJECTION" -%token T_DATUM "DATUM" -%token T_SPHEROID "SPHEROID" -%token T_PRIMEM "PRIMEM" -%token T_UNIT "UNIT" -%token T_AXIS "AXIS" -%token T_PARAMETER "PARAMETER" - -/* WKT2 preferred */ -%token T_GEODCRS "GEODCRS"; -%token T_LENGTHUNIT "LENGTHUNIT"; -%token T_ANGLEUNIT "ANGLEUNIT"; -%token T_SCALEUNIT "SCALEUNIT"; -%token T_TIMEUNIT "TIMEUNIT"; -%token T_ELLIPSOID "ELLIPSOID"; -%token T_CS "CS"; -%token T_ID "ID"; -%token T_PROJCRS "PROJCRS"; -%token T_BASEGEODCRS "BASEGEODCRS"; -%token T_MERIDIAN "MERIDIAN"; -%token T_BEARING "BEARING"; -%token T_ORDER "ORDER"; -%token T_ANCHOR "ANCHOR"; -%token T_CONVERSION "CONVERSION"; -%token T_METHOD "METHOD"; -%token T_REMARK "REMARK"; -%token T_GEOGCRS "GEOGCRS"; -%token T_BASEGEOGCRS "BASEGEOGCRS"; -%token T_SCOPE "SCOPE"; -%token T_AREA "AREA"; -%token T_BBOX "BBOX"; -%token T_CITATION "CITATION"; -%token T_URI "URI"; -%token T_VERTCRS "VERTCRS"; -%token T_VDATUM "VDATUM"; -%token T_GEOIDMODEL "GEOIDMODEL"; -%token T_COMPOUNDCRS "COMPOUNDCRS"; -%token T_PARAMETERFILE "PARAMETERFILE"; -%token T_COORDINATEOPERATION "COORDINATEOPERATION"; -%token T_SOURCECRS "SOURCECRS"; -%token T_TARGETCRS "TARGETCRS"; -%token T_INTERPOLATIONCRS "INTERPOLATIONCRS"; -%token T_OPERATIONACCURACY "OPERATIONACCURACY"; -%token T_CONCATENATEDOPERATION "CONCATENATEDOPERATION"; -%token T_STEP "STEP"; -%token T_BOUNDCRS "BOUNDCRS"; -%token T_ABRIDGEDTRANSFORMATION "ABRIDGEDTRANSFORMATION"; -%token T_DERIVINGCONVERSION "DERIVINGCONVERSION"; -%token T_TDATUM "TDATUM"; -%token T_CALENDAR "CALENDAR"; -%token T_TIMEORIGIN "TIMEORIGIN"; -%token T_TIMECRS "TIMECRS"; -%token T_VERTICALEXTENT "VERTICALEXTENT"; -%token T_TIMEEXTENT "TIMEEXTENT"; -%token T_USAGE "USAGE"; -%token T_DYNAMIC "DYNAMIC"; -%token T_FRAMEEPOCH "FRAMEEPOCH"; -%token T_MODEL "MODEL"; -%token T_VELOCITYGRID "VELOCITYGRID"; -%token T_ENSEMBLE "ENSEMBLE"; -%token T_MEMBER "MEMBER"; -%token T_ENSEMBLEACCURACY "ENSEMBLEACCURACY"; -%token T_DERIVEDPROJCRS "DERIVEDPROJCRS"; -%token T_BASEPROJCRS "BASEPROJCRS"; -%token T_EDATUM "EDATUM"; -%token T_ENGCRS "ENGCRS"; -%token T_PDATUM "PDATUM"; -%token T_PARAMETRICCRS "PARAMETRICCRS"; -%token T_PARAMETRICUNIT "PARAMETRICUNIT"; -%token T_BASEVERTCRS "BASEVERTCRS"; -%token T_BASEENGCRS "BASEENGCRS"; -%token T_BASEPARAMCRS "BASEPARAMCRS"; -%token T_BASETIMECRS "BASETIMECRS"; -%token T_EPOCH "EPOCH" -%token T_COORDEPOCH "COORDEPOCH" -%token T_COORDINATEMETADATA "COORDINATEMETADATA" -%token T_POINTMOTIONOPERATION "POINTMOTIONOPERATION" - -/* WKT2 alternate (longer or shorter) */ -%token T_GEODETICCRS "GEODETICCRS"; -%token T_GEODETICDATUM "GEODETICDATUM"; -%token T_PROJECTEDCRS "PROJECTEDCRS"; -%token T_PRIMEMERIDIAN "PRIMEMERIDIAN"; -%token T_GEOGRAPHICCRS "GEOGRAPHICCRS"; -%token T_TRF "TRF"; -%token T_VERTICALCRS "VERTICALCRS"; -%token T_VERTICALDATUM "VERTICALDATUM"; -%token T_VRF "VRF"; -%token T_TIMEDATUM "TIMEDATUM"; -%token T_TEMPORALQUANTITY "TEMPORALQUANTITY"; -%token T_ENGINEERINGDATUM "ENGINEERINGDATUM"; -%token T_ENGINEERINGCRS "ENGINEERINGCRS"; -%token T_PARAMETRICDATUM "PARAMETRICDATUM"; - - -/* CS types */ -%token T_AFFINE "affine"; -%token T_CARTESIAN "Cartesian"; -%token T_CYLINDRICAL "cylindrical"; -%token T_ELLIPSOIDAL "ellipsoidal"; -%token T_LINEAR "linear"; -%token T_PARAMETRIC "parametric"; -%token T_POLAR "polar"; -%token T_SPHERICAL "spherical"; -%token T_VERTICAL "vertical"; -%token T_TEMPORAL "temporal"; // WKT2_2015 only -%token T_TEMPORALCOUNT "temporalCount"; -%token T_TEMPORALMEASURE "temporalMeasure"; -%token T_ORDINAL "ordinal"; -%token T_TEMPORALDATETIME "temporalDateTime"; - -/* Axis directions */ -%token T_NORTH "north"; -%token T_NORTHNORTHEAST "northNorthEast"; -%token T_NORTHEAST "northEast"; -%token T_EASTNORTHEAST "eastNorthEast"; -%token T_EAST "east"; -%token T_EASTSOUTHEAST "eastSouthEast"; -%token T_SOUTHEAST "southEast"; -%token T_SOUTHSOUTHEAST "southSouthEast"; -%token T_SOUTH "south"; -%token T_SOUTHSOUTHWEST "southSouthWest"; -%token T_SOUTHWEST "southWest"; -%token T_WESTSOUTHWEST "westSouthWest"; -%token T_WEST "west"; -%token T_WESTNORTHWEST "westNorthWest"; -%token T_NORTHWEST "northWest"; -%token T_NORTHNORTHWEST "northNorthWest"; -%token T_UP "up"; -%token T_DOWN "down"; -%token T_GEOCENTRICX "geocentricX"; -%token T_GEOCENTRICY "geocentricY"; -%token T_GEOCENTRICZ "geocentricZ"; -%token T_COLUMNPOSITIVE "columnPositive"; -%token T_COLUMNNEGATIVE "columnNegative"; -%token T_ROWPOSITIVE "rowPositive"; -%token T_ROWNEGATIVE "rowNegative"; -%token T_DISPLAYRIGHT "displayRight"; -%token T_DISPLAYLEFT "displayLeft"; -%token T_DISPLAYUP "displayUp"; -%token T_DISPLAYDOWN "displayDown"; -%token T_FORWARD "forward"; -%token T_AFT "aft"; -%token T_PORT "port"; -%token T_STARBOARD "starboard"; -%token T_CLOCKWISE "clockwise"; -%token T_COUNTERCLOCKWISE "counterClockwise"; -%token T_TOWARDS "towards"; -%token T_AWAYFROM "awayFrom"; -%token T_FUTURE "future"; -%token T_PAST "part"; -%token T_UNSPECIFIED "unspecified"; - - -%token T_STRING "string" -%token T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE "unsigned integer" - -%token END 0 "end of string" - -%% - -/* Derived from BNF grammar in OGC 18-010r3 (WKT2:2018), with a few back - additions from GC 12-063r5 (WKT2:2015) */ - -input: - identifier | ellipsoid | datum | crs | bound_crs | coordinate_metadata | - coordinate_operation | point_motion_operation | concatenated_operation | - map_projection - -datum: - geodetic_reference_frame_without_pm | datum_ensemble | - vertical_reference_frame | engineering_datum | parametric_datum | - temporal_datum - -crs: - geodetic_crs | projected_crs | vertical_crs | engineering_crs | - parametric_crs | temporal_crs | derived_geodetic_crs | derived_geographic_crs | - derived_projected_crs | derived_vertical_crs | derived_engineering_crs | - derived_parametric_crs | derived_temporal_crs | compound_crs - -// Basic characters - -period: '.' - -// Numbers - -number: signed_numeric_literal_with_sign | unsigned_numeric_literal - -signed_numeric_literal_with_sign: sign unsigned_numeric_literal - -signed_numeric_literal: opt_sign unsigned_numeric_literal - -unsigned_numeric_literal: exact_numeric_literal | approximate_numeric_literal - -opt_sign: | sign - -approximate_numeric_literal: mantissa 'E' exponent - -mantissa: exact_numeric_literal - -exponent: signed_integer - -signed_integer: opt_sign unsigned_integer - -exact_numeric_literal: unsigned_integer opt_period_unsigned_integer | period unsigned_integer - -opt_period_unsigned_integer: | period unsigned_integer - -unsigned_integer: '1' | '2' | '3' | T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE - -sign: '+' | '-' - -// Date and time - -colon: ':' - -hyphen: '-' - -// Significantly modified to avoid shift-reduce ambiguities for Bison -datetime: - year opt_24_hour_clock - | year hyphen unsigned_integer opt_24_hour_clock - | year hyphen month hyphen day opt_24_hour_clock - -opt_24_hour_clock: | _24_hour_clock - -year: unsigned_integer - -month: unsigned_integer - -day: unsigned_integer - -_24_hour_clock: time_designator hour - opt_colon_minute_colon_second_time_zone_designator - -opt_colon_minute_colon_second_time_zone_designator: - colon minute opt_colon_second_time_zone_designator - | time_zone_designator - -opt_colon_second_time_zone_designator: - colon second_time_zone_designator - | time_zone_designator - -time_designator: 'T' - -hour: unsigned_integer - -minute: unsigned_integer - -second_time_zone_designator: - seconds_integer period time_zone_designator - | seconds_integer period seconds_fraction time_zone_designator - | seconds_integer time_zone_designator - -seconds_integer: unsigned_integer - -seconds_fraction: unsigned_integer - -time_zone_designator: utc_designator | local_time_zone_designator - -utc_designator: 'Z' - -local_time_zone_designator: - sign hour opt_colon_minute - | hour opt_colon_minute - -opt_colon_minute: | colon minute - - -// CRS WKT characters - -left_delimiter: '[' | '(' - -right_delimiter: ']' | ')' - -wkt_separator: ',' - -quoted_latin_text: T_STRING - -quoted_unicode_text: T_STRING - -// Scope, extent, identifier and remark - -opt_separator_scope_extent_identifier_remark: - | wkt_separator no_opt_separator_scope_extent_identifier_remark - -no_opt_separator_scope_extent_identifier_remark: - scope_extent_opt_identifier_list_opt_remark - | identifier opt_identifier_list_remark - | remark - -opt_identifier_list_remark: | wkt_separator identifier opt_identifier_list_remark - | wkt_separator remark - -scope_extent_opt_identifier_list_opt_remark: - scope_extent_opt_identifier_list_remark - | usage_list_opt_identifier_list_remark - -// WKT2-2015 way -scope_extent_opt_identifier_list_remark: - scope wkt_separator extent_opt_identifier_list_remark - | scope opt_identifier_list_remark - | extent_opt_identifier_list_remark - -// WKT2-2018 way -usage_list_opt_identifier_list_remark: - usage - | usage wkt_separator remark - | usage wkt_separator identifier opt_identifier_list_remark - | usage wkt_separator usage_list_opt_identifier_list_remark - -usage: usage_keyword left_delimiter - scope wkt_separator extent - right_delimiter - -usage_keyword: T_USAGE - -scope: scope_keyword left_delimiter - scope_text_description right_delimiter - -scope_keyword: T_SCOPE - -scope_text_description: quoted_latin_text - -extent: - area_description - | geographic_bounding_box - | vertical_extent - | temporal_extent - | area_description wkt_separator geographic_bounding_box - | area_description wkt_separator vertical_extent - | area_description wkt_separator temporal_extent - | geographic_bounding_box wkt_separator vertical_extent - | geographic_bounding_box wkt_separator temporal_extent - | vertical_extent wkt_separator temporal_extent - | area_description wkt_separator geographic_bounding_box wkt_separator vertical_extent - | area_description wkt_separator geographic_bounding_box wkt_separator temporal_extent - | area_description wkt_separator vertical_extent wkt_separator temporal_extent - | geographic_bounding_box wkt_separator vertical_extent wkt_separator temporal_extent - | area_description wkt_separator geographic_bounding_box wkt_separator vertical_extent wkt_separator temporal_extent - -extent_opt_identifier_list_remark: - area_description opt_identifier_list_remark - | geographic_bounding_box opt_identifier_list_remark - | vertical_extent opt_identifier_list_remark - | temporal_extent opt_identifier_list_remark - | area_description wkt_separator geographic_bounding_box opt_identifier_list_remark - | area_description wkt_separator vertical_extent opt_identifier_list_remark - | area_description wkt_separator temporal_extent opt_identifier_list_remark - | geographic_bounding_box wkt_separator vertical_extent opt_identifier_list_remark - | geographic_bounding_box wkt_separator temporal_extent opt_identifier_list_remark - | vertical_extent wkt_separator temporal_extent opt_identifier_list_remark - | area_description wkt_separator geographic_bounding_box wkt_separator vertical_extent opt_identifier_list_remark - | area_description wkt_separator geographic_bounding_box wkt_separator temporal_extent opt_identifier_list_remark - | area_description wkt_separator vertical_extent wkt_separator temporal_extent opt_identifier_list_remark - | geographic_bounding_box wkt_separator vertical_extent wkt_separator temporal_extent opt_identifier_list_remark - | area_description wkt_separator geographic_bounding_box wkt_separator vertical_extent wkt_separator temporal_extent opt_identifier_list_remark - -// Area description - -area_description: area_description_keyword left_delimiter area_text_description right_delimiter - -area_description_keyword: T_AREA - -area_text_description: quoted_latin_text - -// Geographic bounding box - -geographic_bounding_box: geographic_bounding_box_keyword left_delimiter - lower_left_latitude wkt_separator lower_left_longitude - wkt_separator upper_right_latitude wkt_separator - upper_right_longitude right_delimiter - -geographic_bounding_box_keyword: T_BBOX - -lower_left_latitude: number - -lower_left_longitude: number - -upper_right_latitude: number - -upper_right_longitude: number - -// Vertical extent - -vertical_extent: vertical_extent_keyword left_delimiter - vertical_extent_minimum_height wkt_separator - vertical_extent_maximum_height - opt_separator_length_unit right_delimiter - -opt_separator_length_unit: - | wkt_separator length_unit - -vertical_extent_keyword: T_VERTICALEXTENT - -vertical_extent_minimum_height: number - -vertical_extent_maximum_height: number - -// Temporal extent - -temporal_extent: temporal_extent_keyword left_delimiter - temporal_extent_start wkt_separator - temporal_extent_end right_delimiter - -temporal_extent_keyword: T_TIMEEXTENT - -temporal_extent_start: datetime | quoted_latin_text - -temporal_extent_end: datetime | quoted_latin_text - - -// Identifier - -identifier: identifier_keyword left_delimiter authority_name - wkt_separator authority_unique_identifier - opt_version_authority_citation_uri - right_delimiter - -opt_version_authority_citation_uri: - | wkt_separator version - | wkt_separator version wkt_separator authority_citation - | wkt_separator version wkt_separator authority_citation wkt_separator id_uri - | wkt_separator authority_citation - | wkt_separator authority_citation wkt_separator id_uri - | wkt_separator id_uri - -identifier_keyword: T_ID - -authority_name: quoted_latin_text - -authority_unique_identifier: number | quoted_latin_text - -version: number | quoted_latin_text - -authority_citation: citation_keyword left_delimiter citation right_delimiter - -citation_keyword: T_CITATION - -citation: quoted_latin_text - -id_uri: uri_keyword left_delimiter uri right_delimiter - -uri_keyword: T_URI - -uri: quoted_latin_text - -// Remark - -remark: remark_keyword left_delimiter quoted_unicode_text right_delimiter - -remark_keyword: T_REMARK - -// Unit - -unit: spatial_unit | time_unit - -//spatial_unit: angle_unit | length_unit | parametric_unit | scale_unit -spatial_unit: angle_or_length_or_parametric_or_scale_unit - -angle_or_length_or_parametric_or_scale_unit: - angle_or_length_or_parametric_or_scale_unit_keyword - left_delimiter unit_name - wkt_separator conversion_factor - opt_separator_identifier_list right_delimiter - -angle_or_length_or_parametric_or_scale_unit_keyword: T_ANGLEUNIT | T_LENGTHUNIT | T_PARAMETRICUNIT | T_SCALEUNIT | T_UNIT - -angle_or_length_or_scale_unit: - angle_or_length_or_scale_unit_keyword - left_delimiter unit_name - wkt_separator conversion_factor - opt_separator_identifier_list right_delimiter - -angle_or_length_or_scale_unit_keyword: T_ANGLEUNIT | T_LENGTHUNIT | T_SCALEUNIT | T_UNIT - - -angle_unit: angle_unit_keyword left_delimiter unit_name - wkt_separator conversion_factor - opt_separator_identifier_list right_delimiter - -opt_separator_identifier_list: - | wkt_separator identifier opt_separator_identifier_list - -length_unit: length_unit_keyword left_delimiter unit_name - wkt_separator conversion_factor - opt_separator_identifier_list right_delimiter - -/* -parametric_unit: parametric_unit_keyword left_delimiter unit_name - wkt_separator conversion_factor - opt_separator_identifier_list right_delimiter -*/ - -/* -scale_unit: scale_unit_keyword left_delimiter unit_name - wkt_separator conversion_factor - opt_separator_identifier_list right_delimiter -*/ - -time_unit: time_unit_keyword left_delimiter unit_name - opt_separator_conversion_factor_identifier_list - right_delimiter - -opt_separator_conversion_factor_identifier_list: - | wkt_separator conversion_factor opt_separator_identifier_list - -angle_unit_keyword: T_ANGLEUNIT | T_UNIT - -length_unit_keyword: T_LENGTHUNIT | T_UNIT - -// parametric_unit_keyword: T_PARAMETRICUNIT - -// scale_unit_keyword: T_SCALEUNIT | T_UNIT - -time_unit_keyword: T_TIMEUNIT | T_TEMPORALQUANTITY - -unit_name: quoted_latin_text - -conversion_factor: unsigned_numeric_literal - - -// Coordinate system - -// coordinate_system: spatial_cs | temporalcountmeasure_cs | ordinatedatetime_cs - -coordinate_system_scope_extent_identifier_remark: spatial_cs_scope_extent_identifier_remark | temporalcountmeasure_cs_scope_extent_identifier_remark | ordinaldatetime_cs_scope_extent_identifier_remark - -spatial_cs_scope_extent_identifier_remark: cs_keyword left_delimiter spatial_cs_type - wkt_separator dimension - opt_separator_identifier_list - right_delimiter - wkt_separator spatial_axis - opt_separator_spatial_axis_list_opt_separator_cs_unit_scope_extent_identifier_remark - -opt_separator_spatial_axis_list_opt_separator_cs_unit_scope_extent_identifier_remark: - | wkt_separator cs_unit opt_separator_scope_extent_identifier_remark - | wkt_separator spatial_axis opt_separator_spatial_axis_list_opt_separator_cs_unit_scope_extent_identifier_remark - | wkt_separator no_opt_separator_scope_extent_identifier_remark - -temporalcountmeasure_cs_scope_extent_identifier_remark: cs_keyword left_delimiter temporalcountmeasure_cs_type - wkt_separator dimension - opt_separator_identifier_list - right_delimiter - wkt_separator temporalcountmeasure_axis - opt_separator_scope_extent_identifier_remark - -ordinaldatetime_cs_scope_extent_identifier_remark: cs_keyword left_delimiter ordinaldatetime_cs_type - wkt_separator dimension - opt_separator_identifier_list - right_delimiter - wkt_separator ordinaldatetime_axis - opt_separator_ordinaldatetime_axis_list_scope_extent_identifier_remark - -opt_separator_ordinaldatetime_axis_list_scope_extent_identifier_remark: - | wkt_separator ordinaldatetime_axis opt_separator_ordinaldatetime_axis_list_scope_extent_identifier_remark - | wkt_separator no_opt_separator_scope_extent_identifier_remark - -cs_keyword: T_CS - -spatial_cs_type: T_AFFINE | T_CARTESIAN | T_CYLINDRICAL | T_ELLIPSOIDAL | T_LINEAR | T_PARAMETRIC | T_POLAR | T_SPHERICAL | T_VERTICAL - -// T_TEMPORAL: WKT2_2015 -temporalcountmeasure_cs_type: T_TEMPORAL | T_TEMPORALCOUNT | T_TEMPORALMEASURE - -ordinaldatetime_cs_type: T_ORDINAL | T_TEMPORALDATETIME - -dimension: '1' | '2' | '3' - -spatial_axis: axis_keyword left_delimiter axis_name_abbrev - wkt_separator - axis_direction_opt_axis_order_spatial_unit_identifier_list - right_delimiter - -temporalcountmeasure_axis: axis_keyword left_delimiter axis_name_abbrev - wkt_separator - axis_direction_except_n_s_cw_ccw - opt_separator_axis_time_unit_identifier_list - right_delimiter - -ordinaldatetime_axis: axis_keyword left_delimiter axis_name_abbrev - wkt_separator - axis_direction_opt_axis_order_identifier_list - right_delimiter - -axis_keyword: T_AXIS - -// Approximation of { | | } -axis_name_abbrev: quoted_latin_text - -axis_direction_opt_axis_order_spatial_unit_identifier_list: - axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list - | T_NORTH - | T_NORTH wkt_separator north_south_options_spatial_unit - | T_SOUTH - | T_SOUTH wkt_separator north_south_options_spatial_unit - | T_CLOCKWISE - | T_CLOCKWISE wkt_separator clockwise_counter_clockwise_options_spatial_unit - | T_COUNTERCLOCKWISE - | T_COUNTERCLOCKWISE wkt_separator clockwise_counter_clockwise_options_spatial_unit - -north_south_options_spatial_unit: - identifier opt_separator_identifier_list - | meridian wkt_separator axis_order opt_separator_identifier_list - | meridian wkt_separator axis_order wkt_separator spatial_unit opt_separator_identifier_list - | meridian wkt_separator spatial_unit opt_separator_identifier_list - | meridian opt_separator_identifier_list - | axis_order wkt_separator spatial_unit opt_separator_identifier_list - | axis_order opt_separator_identifier_list - | spatial_unit opt_separator_identifier_list - -clockwise_counter_clockwise_options_spatial_unit: - identifier opt_separator_identifier_list - | bearing wkt_separator axis_order opt_separator_identifier_list - | bearing wkt_separator axis_order wkt_separator spatial_unit opt_separator_identifier_list - | bearing wkt_separator spatial_unit opt_separator_identifier_list - | bearing opt_separator_identifier_list - | axis_order wkt_separator spatial_unit opt_separator_identifier_list - | axis_order opt_separator_identifier_list - | spatial_unit opt_separator_identifier_list - -axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list: - axis_direction_except_n_s_cw_ccw - | axis_direction_except_n_s_cw_ccw wkt_separator axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list_options - -axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list_options: - identifier opt_separator_identifier_list - | axis_order opt_separator_identifier_list - | axis_order wkt_separator spatial_unit opt_separator_identifier_list - | spatial_unit opt_separator_identifier_list - - - -axis_direction_opt_axis_order_identifier_list: - axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list - | T_NORTH - | T_NORTH wkt_separator north_south_options - | T_SOUTH - | T_SOUTH wkt_separator north_south_options_spatial_unit - | T_CLOCKWISE - | T_CLOCKWISE wkt_separator clockwise_counter_clockwise_options - | T_COUNTERCLOCKWISE - | T_COUNTERCLOCKWISE wkt_separator clockwise_counter_clockwise_options - -north_south_options: - identifier opt_separator_identifier_list - | meridian wkt_separator axis_order opt_separator_identifier_list - | meridian opt_separator_identifier_list - | axis_order opt_separator_identifier_list - -clockwise_counter_clockwise_options: - identifier opt_separator_identifier_list - | bearing wkt_separator axis_order opt_separator_identifier_list - | bearing opt_separator_identifier_list - | axis_order opt_separator_identifier_list - -axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list: - axis_direction_except_n_s_cw_ccw - | axis_direction_except_n_s_cw_ccw wkt_separator axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list_options - -axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list_options: - identifier opt_separator_identifier_list - | axis_order opt_separator_identifier_list - - - - -opt_separator_axis_time_unit_identifier_list: - | wkt_separator axis_direction_except_n_s_cw_ccw_opt_axis_time_unit_identifier_list_options - -axis_direction_except_n_s_cw_ccw_opt_axis_time_unit_identifier_list_options: - identifier opt_separator_identifier_list - | axis_order opt_separator_identifier_list - | axis_order wkt_separator time_unit opt_separator_identifier_list - | time_unit opt_separator_identifier_list - -axis_direction_except_n_s_cw_ccw: - T_NORTHNORTHEAST - | T_NORTHEAST - | T_EASTNORTHEAST - | T_EAST - | T_EASTSOUTHEAST - | T_SOUTHEAST - | T_SOUTHSOUTHEAST - | T_SOUTHSOUTHWEST - | T_SOUTHWEST - | T_WESTSOUTHWEST - | T_WEST - | T_WESTNORTHWEST - | T_NORTHWEST - | T_NORTHNORTHWEST - | T_UP - | T_DOWN - | T_GEOCENTRICX - | T_GEOCENTRICY - | T_GEOCENTRICZ - | T_COLUMNPOSITIVE - | T_COLUMNNEGATIVE - | T_ROWPOSITIVE - | T_ROWNEGATIVE - | T_DISPLAYRIGHT - | T_DISPLAYLEFT - | T_DISPLAYUP - | T_DISPLAYDOWN - | T_FORWARD - | T_AFT - | T_PORT - | T_STARBOARD - | T_TOWARDS - | T_AWAYFROM - | T_FUTURE - | T_PAST - | T_UNSPECIFIED - -meridian: meridian_keyword left_delimiter number - wkt_separator angle_unit right_delimiter - -meridian_keyword: T_MERIDIAN - -bearing: bearing_keyword left_delimiter number right_delimiter - -bearing_keyword: T_BEARING - -axis_order: axis_order_keyword left_delimiter unsigned_integer right_delimiter - -axis_order_keyword: T_ORDER - -cs_unit: unit - -/* -ellipsoidal_2D_coordinate_system: cs_keyword left_delimiter ellipsoidal_2D_cs_type - wkt_separator ellipsoidal_2D_dimension - opt_separator_identifier_list right_delimiter - separator_spatial_axis_list - opt_separator_cs_unit - -ellipsoidal_2D_cs_type: T_ELLIPSOIDAL - -ellipsoidal_2D_dimension: '2' -*/ - -// Datum ensemble - -datum_ensemble: geodetic_datum_ensemble_without_pm | vertical_datum_ensemble - -geodetic_datum_ensemble_without_pm: datum_ensemble_keyword - left_delimiter - datum_ensemble_name - wkt_separator datum_ensemble_member - datum_ensemble_member_list_ellipsoid_accuracy_identifier_list - right_delimiter - -datum_ensemble_member_list_ellipsoid_accuracy_identifier_list: - wkt_separator ellipsoid wkt_separator datum_ensemble_accuracy opt_separator_datum_ensemble_identifier_list - | wkt_separator datum_ensemble_member datum_ensemble_member_list_ellipsoid_accuracy_identifier_list - -opt_separator_datum_ensemble_identifier_list: - | wkt_separator datum_ensemble_identifier opt_separator_datum_ensemble_identifier_list - -vertical_datum_ensemble: datum_ensemble_keyword - left_delimiter - datum_ensemble_name - wkt_separator datum_ensemble_member - datum_ensemble_member_list_accuracy_identifier_list - right_delimiter - -datum_ensemble_member_list_accuracy_identifier_list: - wkt_separator datum_ensemble_accuracy opt_separator_datum_ensemble_identifier_list - | wkt_separator datum_ensemble_member datum_ensemble_member_list_accuracy_identifier_list - -datum_ensemble_keyword: T_ENSEMBLE - -datum_ensemble_name: quoted_latin_text - -datum_ensemble_member: datum_ensemble_member_keyword left_delimiter - datum_ensemble_member_name - opt_datum_ensemble_member_identifier_list - right_delimiter - -opt_datum_ensemble_member_identifier_list: - | wkt_separator datum_ensemble_member_identifier opt_datum_ensemble_member_identifier_list - -datum_ensemble_member_keyword: T_MEMBER - -datum_ensemble_member_name: quoted_latin_text - -datum_ensemble_member_identifier: identifier - -datum_ensemble_accuracy: datum_ensemble_accuracy_keyword left_delimiter accuracy right_delimiter - -datum_ensemble_accuracy_keyword: T_ENSEMBLEACCURACY - -accuracy: number - -datum_ensemble_identifier: identifier - - -// Dynamic coordinate reference systems - -dynamic_crs: dynamic_crs_keyword left_delimiter frame_reference_epoch - opt_separator_deformation_model_id - right_delimiter - -dynamic_crs_keyword: T_DYNAMIC - -frame_reference_epoch: frame_reference_epoch_keyword left_delimiter - reference_epoch right_delimiter - -frame_reference_epoch_keyword: T_FRAMEEPOCH - -reference_epoch: - unsigned_integer - | unsigned_integer period - | unsigned_integer period unsigned_integer - -opt_separator_deformation_model_id: - | wkt_separator deformation_model_id - -deformation_model_id: deformation_model_id_keyword left_delimiter - deformation_model_name - opt_separator_identifier - right_delimiter - -opt_separator_identifier: - | wkt_separator identifier - -deformation_model_id_keyword: T_MODEL | T_VELOCITYGRID - -deformation_model_name: quoted_latin_text - -// Geodetic CRS - -geodetic_crs: static_geodetic_crs | static_geographic_crs | dynamic_geodetic_crs | dynamic_geographic_crs - -static_geodetic_crs: geodetic_crs_keyword - left_delimiter crs_name - wkt_separator - geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm - wkt_separator - opt_prime_meridian_coordinate_system_scope_extent_identifier_remark - right_delimiter - -static_geographic_crs: geographic_crs_keyword - left_delimiter crs_name - wkt_separator - geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm - wkt_separator - opt_prime_meridian_coordinate_system_scope_extent_identifier_remark - right_delimiter - -dynamic_geodetic_crs: geodetic_crs_keyword - left_delimiter crs_name - wkt_separator dynamic_crs - wkt_separator - geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm - wkt_separator - opt_prime_meridian_coordinate_system_scope_extent_identifier_remark - right_delimiter - -dynamic_geographic_crs: geographic_crs_keyword - left_delimiter crs_name - wkt_separator dynamic_crs - wkt_separator - geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm - wkt_separator - opt_prime_meridian_coordinate_system_scope_extent_identifier_remark - right_delimiter - -opt_prime_meridian_coordinate_system_scope_extent_identifier_remark: - prime_meridian wkt_separator coordinate_system_scope_extent_identifier_remark - | coordinate_system_scope_extent_identifier_remark - -crs_name: quoted_latin_text - -geodetic_crs_keyword: T_GEODCRS | T_GEODETICCRS - -geographic_crs_keyword: T_GEOGCRS | T_GEOGRAPHICCRS - -geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm: - geodetic_reference_frame_without_pm - | geodetic_datum_ensemble_without_pm - -// Ellipsoid - -ellipsoid: ellipsoid_keyword left_delimiter ellipsoid_name - wkt_separator semi_major_axis - wkt_separator inverse_flattening - opt_separator_length_unit_identifier_list - right_delimiter - -opt_separator_length_unit_identifier_list: - | wkt_separator length_unit opt_separator_identifier_list - | wkt_separator identifier opt_separator_identifier_list - -ellipsoid_keyword: T_ELLIPSOID | T_SPHEROID - -ellipsoid_name: quoted_latin_text - -semi_major_axis: unsigned_numeric_literal - -inverse_flattening: unsigned_numeric_literal - -// Prime meridian - -prime_meridian: prime_meridian_keyword left_delimiter - prime_meridian_name wkt_separator - irm_longitude_opt_separator_identifier_list - right_delimiter - -prime_meridian_keyword: T_PRIMEM | T_PRIMEMERIDIAN - -prime_meridian_name: quoted_latin_text - -irm_longitude_opt_separator_identifier_list: - signed_numeric_literal wkt_separator angle_unit opt_separator_identifier_list - | signed_numeric_literal opt_separator_identifier_list - -// Geodetic reference frame - -geodetic_reference_frame_without_pm: geodetic_reference_frame_keyword - left_delimiter datum_name wkt_separator ellipsoid - opt_separator_datum_anchor_identifier_list - right_delimiter - -geodetic_reference_frame_keyword: T_DATUM | T_TRF | T_GEODETICDATUM - -datum_name: quoted_latin_text - -opt_separator_datum_anchor_identifier_list: - | wkt_separator datum_anchor - | wkt_separator identifier opt_separator_identifier_list - | wkt_separator datum_anchor wkt_separator identifier opt_separator_identifier_list - -datum_anchor: datum_anchor_keyword left_delimiter - datum_anchor_description right_delimiter - -datum_anchor_keyword: T_ANCHOR - -datum_anchor_description: quoted_latin_text - -// Projected CRS - -projected_crs: projected_crs_keyword left_delimiter crs_name - wkt_separator base_geodetic_crs - wkt_separator map_projection - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -projected_crs_keyword: T_PROJCRS | T_PROJECTEDCRS - -// Base CRS - -base_geodetic_crs: base_static_geodetic_crs | base_dynamic_geodetic_crs - -base_static_geodetic_crs: base_geodetic_crs_keyword left_delimiter base_crs_name - wkt_separator geodetic_reference_frame_without_pm - opt_separator_pm_ellipsoidal_cs_unit - right_delimiter - -opt_separator_pm_ellipsoidal_cs_unit: - | wkt_separator prime_meridian - | wkt_separator prime_meridian wkt_separator ellipsoidal_cs_unit - | wkt_separator ellipsoidal_cs_unit - -base_dynamic_geodetic_crs: base_geodetic_crs_keyword left_delimiter base_crs_name - wkt_separator dynamic_crs - wkt_separator geodetic_reference_frame_without_pm - opt_separator_pm_ellipsoidal_cs_unit - right_delimiter - -base_geodetic_crs_keyword: T_BASEGEODCRS | T_BASEGEOGCRS - -base_crs_name: quoted_latin_text - -ellipsoidal_cs_unit: angle_unit - -// Map projection - -map_projection: map_projection_keyword left_delimiter - map_projection_name - wkt_separator map_projection_method - wkt_separator - parameter_list_identifier_list - right_delimiter - -parameter_list_identifier_list: - map_projection_parameter opt_separator_identifier_list - | map_projection_parameter wkt_separator parameter_list_identifier_list - -map_projection_keyword: T_CONVERSION - -map_projection_name: quoted_latin_text - -map_projection_method: map_projection_method_keyword left_delimiter - map_projection_method_name - opt_separator_identifier_list right_delimiter - -map_projection_method_keyword: T_METHOD | T_PROJECTION - -map_projection_method_name: quoted_latin_text - -map_projection_parameter: parameter_keyword left_delimiter parameter_name - wkt_separator parameter_value - opt_separator_param_unit_identifier_list - right_delimiter - -opt_separator_param_unit_identifier_list: - | wkt_separator map_projection_parameter_unit opt_separator_identifier_list - -parameter_keyword: T_PARAMETER - -parameter_name: quoted_latin_text - -parameter_value: signed_numeric_literal - -map_projection_parameter_unit: angle_or_length_or_scale_unit - -// Vertical CRS - -vertical_crs: static_vertical_crs | dynamic_vertical_crs - -static_vertical_crs: vertical_crs_keyword left_delimiter crs_name - wkt_separator vertical_reference_frame_or_vertical_datum_ensemble - wkt_separator - vertical_cs_opt_geoid_model_id_scope_extent_identifier_remark - right_delimiter - -dynamic_vertical_crs: vertical_crs_keyword left_delimiter crs_name - wkt_separator dynamic_crs - wkt_separator vertical_reference_frame_or_vertical_datum_ensemble - wkt_separator - vertical_cs_opt_geoid_model_id_scope_extent_identifier_remark - right_delimiter - -vertical_reference_frame_or_vertical_datum_ensemble: vertical_reference_frame | vertical_datum_ensemble - -vertical_cs_opt_geoid_model_id_scope_extent_identifier_remark: - cs_keyword left_delimiter spatial_cs_type - wkt_separator dimension - opt_separator_identifier_list - right_delimiter - wkt_separator spatial_axis - opt_separator_cs_unit_opt_geoid_model_id_scope_extent_identifier_remark - -opt_separator_cs_unit_opt_geoid_model_id_scope_extent_identifier_remark: - | wkt_separator cs_unit opt_separator_scope_extent_identifier_remark - | wkt_separator cs_unit wkt_separator geoid_model_id opt_separator_scope_extent_identifier_remark - | wkt_separator geoid_model_id opt_separator_scope_extent_identifier_remark - | wkt_separator no_opt_separator_scope_extent_identifier_remark - -geoid_model_id: geoid_model_keyword left_delimiter - geoid_model_name opt_separator_identifier - right_delimiter - -geoid_model_keyword: T_GEOIDMODEL - -geoid_model_name: quoted_latin_text - -vertical_crs_keyword: T_VERTCRS | T_VERTICALCRS - -// Vertical reference frame - -vertical_reference_frame: vertical_reference_frame_keyword left_delimiter - datum_name - opt_separator_datum_anchor_identifier_list - right_delimiter - -vertical_reference_frame_keyword: T_VDATUM | T_VRF | T_VERTICALDATUM - -// Engineering CRS - -engineering_crs: engineering_crs_keyword left_delimiter crs_name - wkt_separator engineering_datum - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -engineering_crs_keyword: T_ENGCRS | T_ENGINEERINGCRS - -engineering_datum: engineering_datum_keyword left_delimiter datum_name - opt_separator_datum_anchor_identifier_list - right_delimiter - -engineering_datum_keyword: T_EDATUM | T_ENGINEERINGDATUM - -// Parametric CRS - -parametric_crs: parametric_crs_keyword left_delimiter crs_name - wkt_separator parametric_datum - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -parametric_crs_keyword: T_PARAMETRICCRS - -parametric_datum: parametric_datum_keyword left_delimiter datum_name - opt_separator_datum_anchor_identifier_list - right_delimiter - -parametric_datum_keyword: T_PDATUM | T_PARAMETRICDATUM - -// Temporal CRS - -temporal_crs: temporal_crs_keyword left_delimiter crs_name - wkt_separator temporal_datum - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -temporal_crs_keyword: T_TIMECRS - -temporal_datum: temporal_datum_keyword left_delimiter datum_name - opt_separator_temporal_datum_end - right_delimiter - -opt_separator_temporal_datum_end: - | wkt_separator calendar opt_separator_identifier_list - | wkt_separator calendar wkt_separator temporal_origin opt_separator_identifier_list - | wkt_separator temporal_origin opt_separator_identifier_list - | wkt_separator identifier opt_separator_identifier_list - -temporal_datum_keyword: T_TDATUM | T_TIMEDATUM - -temporal_origin: temporal_origin_keyword left_delimiter - temporal_origin_description right_delimiter - -temporal_origin_keyword: T_TIMEORIGIN - -temporal_origin_description: datetime | quoted_latin_text - -calendar: calendar_keyword left_delimiter calendar_identifier right_delimiter - -calendar_keyword: T_CALENDAR - -calendar_identifier: quoted_latin_text - -// Deriving conversion - -deriving_conversion: deriving_conversion_keyword left_delimiter - deriving_conversion_name wkt_separator - operation_method - wkt_separator parameter_or_parameter_file - opt_separator_deriving_conversion_end - right_delimiter - -parameter_or_parameter_file: operation_parameter | operation_parameter_file - -opt_separator_deriving_conversion_end: - | wkt_separator operation_parameter opt_separator_deriving_conversion_end - | wkt_separator operation_parameter_file opt_separator_deriving_conversion_end - | wkt_separator identifier opt_separator_identifier - -deriving_conversion_keyword: T_DERIVINGCONVERSION - -deriving_conversion_name: quoted_latin_text - -// Derived CRS conversion method - -operation_method: operation_method_keyword left_delimiter - operation_method_name - opt_separator_identifier - right_delimiter - -operation_method_keyword: T_METHOD - -operation_method_name: quoted_latin_text - -// Derived CRS conversion parameter -operation_parameter: parameter_keyword left_delimiter parameter_name - wkt_separator parameter_value wkt_separator parameter_unit - opt_separator_identifier - right_delimiter - -parameter_unit: length_or_angle_or_scale_or_time_or_parametric_unit - -// Approximate definition: conversion_factor should be optional only for a timeunit (but not easy to detect if UNIT keyword is used!) -length_or_angle_or_scale_or_time_or_parametric_unit: - length_or_angle_or_scale_or_time_or_parametric_unit_keyword - left_delimiter unit_name - opt_separator_conversion_factor_identifier_list - right_delimiter - -length_or_angle_or_scale_or_time_or_parametric_unit_keyword: - T_LENGTHUNIT | T_ANGLEUNIT | T_SCALEUNIT | T_TIMEUNIT | T_PARAMETRICUNIT | T_UNIT - -// Derived CRS conversion parameter file - -operation_parameter_file: parameter_file_keyword left_delimiter parameter_name - wkt_separator parameter_file_name - opt_separator_identifier - right_delimiter - -parameter_file_keyword: T_PARAMETERFILE - -parameter_file_name: quoted_latin_text - - -// Derived geodetic CRS and derived geographic CRS - -// Note: derived_geodetic_crs and derived_geographic_crs separated to avoid Bison shift/reduce conflicts -derived_geodetic_crs: geodetic_crs_keyword - left_delimiter crs_name - wkt_separator base_geodetic_crs - wkt_separator deriving_conversion - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -derived_geographic_crs: geographic_crs_keyword - left_delimiter crs_name - wkt_separator base_geodetic_crs - wkt_separator deriving_conversion - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - - -// Derived projected CRS - -derived_projected_crs: derived_projected_crs_keyword left_delimiter - derived_crs_name wkt_separator base_projected_crs - wkt_separator deriving_conversion - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -derived_projected_crs_keyword: T_DERIVEDPROJCRS - -derived_crs_name: quoted_latin_text - -base_projected_crs: base_projected_crs_keyword left_delimiter base_crs_name - wkt_separator base_geodetic_crs - wkt_separator map_projection - right_delimiter - -base_projected_crs_keyword: T_BASEPROJCRS - - -// Derived vertical CRS - -derived_vertical_crs: vertical_crs_keyword left_delimiter crs_name - wkt_separator base_vertical_crs - wkt_separator deriving_conversion - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -base_vertical_crs: base_static_vertical_crs | base_dynamic_vertical_crs - -base_static_vertical_crs: base_vertical_crs_keyword left_delimiter base_crs_name - wkt_separator vertical_reference_frame right_delimiter - -base_dynamic_vertical_crs: base_vertical_crs_keyword left_delimiter base_crs_name - wkt_separator dynamic_crs - wkt_separator vertical_reference_frame right_delimiter - -base_vertical_crs_keyword: T_BASEVERTCRS - - -// Derived engineering CRS - -derived_engineering_crs: engineering_crs_keyword left_delimiter crs_name - wkt_separator base_engineering_crs - wkt_separator deriving_conversion - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -base_engineering_crs: base_engineering_crs_keyword left_delimiter base_crs_name - wkt_separator engineering_datum right_delimiter - -base_engineering_crs_keyword: T_BASEENGCRS - - -// Derived parametric CRS - -derived_parametric_crs: parametric_crs_keyword left_delimiter crs_name - wkt_separator base_parametric_crs - wkt_separator deriving_conversion - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -base_parametric_crs: base_parametric_crs_keyword left_delimiter base_crs_name - wkt_separator parametric_datum right_delimiter - -base_parametric_crs_keyword: T_BASEPARAMCRS - - -// Derived temporal CRS - -derived_temporal_crs: temporal_crs_keyword left_delimiter crs_name - wkt_separator base_temporal_crs - wkt_separator deriving_conversion - wkt_separator coordinate_system_scope_extent_identifier_remark - right_delimiter - -base_temporal_crs: base_temporal_crs_keyword left_delimiter base_crs_name - wkt_separator temporal_datum right_delimiter - -base_temporal_crs_keyword: T_BASETIMECRS - - -// Compound CRS - -compound_crs: compound_crs_keyword left_delimiter compound_crs_name - wkt_separator horizontal_crs wkt_separator - compound_crs_other_components - right_delimiter - -compound_crs_other_components: - vertical_crs opt_separator_scope_extent_identifier_remark - | parametric_crs opt_separator_scope_extent_identifier_remark - | temporal_crs opt_separator_scope_extent_identifier_remark - | vertical_crs wkt_separator temporal_crs opt_separator_scope_extent_identifier_remark - | parametric_crs wkt_separator temporal_crs opt_separator_scope_extent_identifier_remark - -compound_crs_keyword: T_COMPOUNDCRS - -compound_crs_name: quoted_latin_text - -horizontal_crs: geographic2D_crs | projected_crs | engineering_crs - -geographic2D_crs: static_geographic_crs | dynamic_geographic_crs - - -// coordinate epoch and coordinate metadata - -metadata_coordinate_epoch: coordinate_epoch_keyword left_delimiter - coordinate_epoch right_delimiter - -coordinate_epoch_keyword: T_EPOCH | T_COORDEPOCH - -coordinate_epoch: - unsigned_integer - | unsigned_integer period - | unsigned_integer period unsigned_integer - -coordinate_metadata: coordinate_metadata_keyword left_delimiter - coordinate_metadata_crs right_delimiter - -coordinate_metadata_crs: - static_crs - | dynamic_crs_coordinate_metadata wkt_separator metadata_coordinate_epoch - -coordinate_metadata_keyword: T_COORDINATEMETADATA - -static_crs: static_geodetic_crs | static_geographic_crs | - projected_crs | static_vertical_crs | - engineering_crs | parametric_crs | temporal_crs | - derived_geodetic_crs | derived_geographic_crs | - derived_projected_crs | derived_vertical_crs | - derived_engineering_crs | derived_parametric_crs | - derived_temporal_crs | compound_crs - -dynamic_crs_coordinate_metadata: dynamic_geodetic_crs | dynamic_geographic_crs | - projected_crs | dynamic_vertical_crs | - derived_geodetic_crs | derived_geographic_crs | - derived_projected_crs | derived_vertical_crs - -// Coordinate operations - -coordinate_operation: operation_keyword left_delimiter operation_name - wkt_separator source_crs wkt_separator target_crs - wkt_separator operation_method - wkt_separator parameter_or_parameter_file - opt_coordinate_operation_end - right_delimiter - -opt_coordinate_operation_end: - | wkt_separator operation_parameter opt_coordinate_operation_end - | wkt_separator operation_parameter_file opt_coordinate_operation_end - | wkt_separator interpolation_crs opt_separator_scope_extent_identifier_remark - | wkt_separator interpolation_crs wkt_separator operation_accuracy opt_separator_scope_extent_identifier_remark - | wkt_separator operation_accuracy opt_separator_scope_extent_identifier_remark - | wkt_separator no_opt_separator_scope_extent_identifier_remark - -operation_keyword: T_COORDINATEOPERATION - -operation_name: quoted_latin_text - -source_crs: source_crs_keyword left_delimiter crs right_delimiter - -source_crs_keyword: T_SOURCECRS - -target_crs: target_crs_keyword left_delimiter crs right_delimiter - -target_crs_keyword: T_TARGETCRS - -interpolation_crs: interpolation_crs_keyword left_delimiter crs right_delimiter - -interpolation_crs_keyword: T_INTERPOLATIONCRS - -operation_accuracy: operation_accuracy_keyword left_delimiter accuracy right_delimiter - -operation_accuracy_keyword: T_OPERATIONACCURACY - - -// Point motion operation - -point_motion_operation: point_motion_keyword left_delimiter operation_name - wkt_separator source_crs - wkt_separator operation_method - wkt_separator parameter_or_parameter_file - opt_point_motion_operation_end - right_delimiter - -opt_point_motion_operation_end: - | wkt_separator operation_parameter opt_point_motion_operation_end - | wkt_separator operation_parameter_file opt_point_motion_operation_end - | wkt_separator operation_accuracy opt_separator_scope_extent_identifier_remark - | wkt_separator no_opt_separator_scope_extent_identifier_remark - -point_motion_keyword: T_POINTMOTIONOPERATION - - -// Concatenated operation - -concatenated_operation: concatenated_operation_keyword left_delimiter - operation_name - wkt_separator source_crs wkt_separator target_crs - wkt_separator step_keyword left_delimiter step right_delimiter - wkt_separator step_keyword left_delimiter step right_delimiter - opt_concatenated_operation_end - right_delimiter - -step: coordinate_operation | point_motion_keyword | deriving_conversion - -opt_concatenated_operation_end: - | wkt_separator step_keyword left_delimiter step right_delimiter opt_concatenated_operation_end - | wkt_separator operation_accuracy opt_separator_scope_extent_identifier_remark - | wkt_separator no_opt_separator_scope_extent_identifier_remark - -concatenated_operation_keyword: T_CONCATENATEDOPERATION - -step_keyword: T_STEP - - -// Bound CRS - -bound_crs: bound_crs_keyword left_delimiter - source_crs wkt_separator target_crs - wkt_separator abridged_coordinate_transformation - opt_separator_scope_extent_identifier_remark - right_delimiter - -bound_crs_keyword: T_BOUNDCRS - -abridged_coordinate_transformation: abridged_transformation_keyword left_delimiter - operation_name wkt_separator - operation_method wkt_separator - abridged_parameter_or_parameter_file - opt_end_abridged_coordinate_transformation - right_delimiter - -abridged_parameter_or_parameter_file: abridged_transformation_parameter | operation_parameter_file - -opt_end_abridged_coordinate_transformation: - | wkt_separator abridged_transformation_parameter opt_end_abridged_coordinate_transformation - | wkt_separator operation_parameter_file opt_end_abridged_coordinate_transformation - | wkt_separator no_opt_separator_scope_extent_identifier_remark - -abridged_transformation_keyword: T_ABRIDGEDTRANSFORMATION - -abridged_transformation_parameter: parameter_keyword left_delimiter - parameter_name wkt_separator parameter_value - opt_separator_identifier_list - right_delimiter diff --git a/src/pj_wkt2_parser.cpp b/src/pj_wkt2_parser.cpp deleted file mode 100644 index 0e898436..00000000 --- a/src/pj_wkt2_parser.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/****************************************************************************** - * Project: PROJ - * Purpose: WKT2 parser grammar - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2018 Even Rouault, - * - * 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. - ****************************************************************************/ - -#ifndef FROM_PROJ_CPP -#define FROM_PROJ_CPP -#endif - -#include "proj/internal/internal.hpp" - -#include -#include -#include -#include - -#include "pj_wkt2_parser.h" -#include "pj_wkt_parser.hpp" - -using namespace NS_PROJ::internal; - -//! @cond Doxygen_Suppress - -// --------------------------------------------------------------------------- - -struct pj_wkt2_parse_context : public pj_wkt_parse_context {}; - -// --------------------------------------------------------------------------- - -void pj_wkt2_error(pj_wkt2_parse_context *context, const char *msg) { - pj_wkt_error(context, msg); -} - -// --------------------------------------------------------------------------- - -std::string pj_wkt2_parse(const std::string &wkt) { - pj_wkt2_parse_context context; - context.pszInput = wkt.c_str(); - context.pszLastSuccess = wkt.c_str(); - context.pszNext = wkt.c_str(); - if (pj_wkt2_parse(&context) != 0) { - return context.errorMsg; - } - return std::string(); -} - -// --------------------------------------------------------------------------- - -typedef struct { - const char *pszToken; - int nTokenVal; -} wkt2_tokens; - -#define PAIR(X) \ - { #X, T_##X } - -static const wkt2_tokens tokens[] = { - PAIR(PARAMETER), PAIR(PROJECTION), PAIR(DATUM), PAIR(SPHEROID), - PAIR(PRIMEM), PAIR(UNIT), PAIR(AXIS), - - PAIR(GEODCRS), PAIR(LENGTHUNIT), PAIR(ANGLEUNIT), PAIR(SCALEUNIT), - PAIR(TIMEUNIT), PAIR(ELLIPSOID), PAIR(CS), PAIR(ID), PAIR(PROJCRS), - PAIR(BASEGEODCRS), PAIR(MERIDIAN), PAIR(BEARING), PAIR(ORDER), PAIR(ANCHOR), - PAIR(CONVERSION), PAIR(METHOD), PAIR(REMARK), PAIR(GEOGCRS), - PAIR(BASEGEOGCRS), PAIR(SCOPE), PAIR(AREA), PAIR(BBOX), PAIR(CITATION), - PAIR(URI), PAIR(VERTCRS), PAIR(VDATUM), PAIR(GEOIDMODEL), PAIR(COMPOUNDCRS), - PAIR(PARAMETERFILE), PAIR(COORDINATEOPERATION), PAIR(SOURCECRS), - PAIR(TARGETCRS), PAIR(INTERPOLATIONCRS), PAIR(OPERATIONACCURACY), - PAIR(CONCATENATEDOPERATION), PAIR(STEP), PAIR(BOUNDCRS), - PAIR(ABRIDGEDTRANSFORMATION), PAIR(DERIVINGCONVERSION), PAIR(TDATUM), - PAIR(CALENDAR), PAIR(TIMEORIGIN), PAIR(TIMECRS), PAIR(VERTICALEXTENT), - PAIR(TIMEEXTENT), PAIR(USAGE), PAIR(DYNAMIC), PAIR(FRAMEEPOCH), PAIR(MODEL), - PAIR(VELOCITYGRID), PAIR(ENSEMBLE), PAIR(MEMBER), PAIR(ENSEMBLEACCURACY), - PAIR(DERIVEDPROJCRS), PAIR(BASEPROJCRS), PAIR(EDATUM), PAIR(ENGCRS), - PAIR(PDATUM), PAIR(PARAMETRICCRS), PAIR(PARAMETRICUNIT), PAIR(BASEVERTCRS), - PAIR(BASEENGCRS), PAIR(BASEPARAMCRS), PAIR(BASETIMECRS), PAIR(GEODETICCRS), - PAIR(GEODETICDATUM), PAIR(PROJECTEDCRS), PAIR(PRIMEMERIDIAN), - PAIR(GEOGRAPHICCRS), PAIR(TRF), PAIR(VERTICALCRS), PAIR(VERTICALDATUM), - PAIR(VRF), PAIR(TIMEDATUM), PAIR(TEMPORALQUANTITY), PAIR(ENGINEERINGDATUM), - PAIR(ENGINEERINGCRS), PAIR(PARAMETRICDATUM), PAIR(EPOCH), PAIR(COORDEPOCH), - PAIR(COORDINATEMETADATA), PAIR(POINTMOTIONOPERATION), - - // CS types - PAIR(AFFINE), PAIR(CARTESIAN), PAIR(CYLINDRICAL), PAIR(ELLIPSOIDAL), - PAIR(LINEAR), PAIR(PARAMETRIC), PAIR(POLAR), PAIR(SPHERICAL), - PAIR(VERTICAL), PAIR(TEMPORAL), PAIR(TEMPORALCOUNT), PAIR(TEMPORALMEASURE), - PAIR(ORDINAL), PAIR(TEMPORALDATETIME), - - // Axis directions - PAIR(NORTH), PAIR(NORTHNORTHEAST), PAIR(NORTHEAST), PAIR(EASTNORTHEAST), - PAIR(EAST), PAIR(EASTSOUTHEAST), PAIR(SOUTHEAST), PAIR(SOUTHSOUTHEAST), - PAIR(SOUTH), PAIR(SOUTHSOUTHWEST), PAIR(SOUTHWEST), PAIR(WESTSOUTHWEST), - PAIR(WEST), PAIR(WESTNORTHWEST), PAIR(NORTHWEST), PAIR(NORTHNORTHWEST), - PAIR(UP), PAIR(DOWN), PAIR(GEOCENTRICX), PAIR(GEOCENTRICY), - PAIR(GEOCENTRICZ), PAIR(COLUMNPOSITIVE), PAIR(COLUMNNEGATIVE), - PAIR(ROWPOSITIVE), PAIR(ROWNEGATIVE), PAIR(DISPLAYRIGHT), PAIR(DISPLAYLEFT), - PAIR(DISPLAYUP), PAIR(DISPLAYDOWN), PAIR(FORWARD), PAIR(AFT), PAIR(PORT), - PAIR(STARBOARD), PAIR(CLOCKWISE), PAIR(COUNTERCLOCKWISE), PAIR(TOWARDS), - PAIR(AWAYFROM), PAIR(FUTURE), PAIR(PAST), PAIR(UNSPECIFIED), -}; - -// --------------------------------------------------------------------------- - -int pj_wkt2_lex(YYSTYPE * /*pNode */, pj_wkt2_parse_context *context) { - size_t i; - const char *pszInput = context->pszNext; - - /* -------------------------------------------------------------------- */ - /* Skip white space. */ - /* -------------------------------------------------------------------- */ - while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 || - *pszInput == 13) - pszInput++; - - context->pszLastSuccess = pszInput; - - if (*pszInput == '\0') { - context->pszNext = pszInput; - return EOF; - } - - /* -------------------------------------------------------------------- */ - /* Recognize node names. */ - /* -------------------------------------------------------------------- */ - if (isalpha(*pszInput)) { - for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) { - if (ci_starts_with(pszInput, tokens[i].pszToken) && - !isalpha(pszInput[strlen(tokens[i].pszToken)])) { - context->pszNext = pszInput + strlen(tokens[i].pszToken); - return tokens[i].nTokenVal; - } - } - } - - /* -------------------------------------------------------------------- */ - /* Recognize unsigned integer */ - /* -------------------------------------------------------------------- */ - - if (*pszInput >= '0' && *pszInput <= '9') { - - // Special case for 1, 2, 3 - if ((*pszInput == '1' || *pszInput == '2' || *pszInput == '3') && - !(pszInput[1] >= '0' && pszInput[1] <= '9')) { - context->pszNext = pszInput + 1; - return *pszInput; - } - - pszInput++; - while (*pszInput >= '0' && *pszInput <= '9') - pszInput++; - - context->pszNext = pszInput; - - return T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE; - } - - /* -------------------------------------------------------------------- */ - /* Recognize double quoted strings. */ - /* -------------------------------------------------------------------- */ - if (*pszInput == '"') { - pszInput++; - while (*pszInput != '\0') { - if (*pszInput == '"') { - if (pszInput[1] == '"') - pszInput++; - else - break; - } - pszInput++; - } - if (*pszInput == '\0') { - context->pszNext = pszInput; - return EOF; - } - context->pszNext = pszInput + 1; - return T_STRING; - } - - // As used in examples of OGC 12-063r5 - const char *startPrintedQuote = "\xE2\x80\x9C"; - const char *endPrintedQuote = "\xE2\x80\x9D"; - if (strncmp(pszInput, startPrintedQuote, 3) == 0) { - context->pszNext = strstr(pszInput, endPrintedQuote); - if (context->pszNext == nullptr) { - context->pszNext = pszInput + strlen(pszInput); - return EOF; - } - context->pszNext += 3; - return T_STRING; - } - - /* -------------------------------------------------------------------- */ - /* Handle special tokens. */ - /* -------------------------------------------------------------------- */ - context->pszNext = pszInput + 1; - return *pszInput; -} - -//! @endcond diff --git a/src/pj_wkt2_parser.h b/src/pj_wkt2_parser.h deleted file mode 100644 index 9229f2ff..00000000 --- a/src/pj_wkt2_parser.h +++ /dev/null @@ -1,54 +0,0 @@ -/****************************************************************************** - * Project: PROJ - * Purpose: WKT2 parser grammar - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2018 Even Rouault, - * - * 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. - ****************************************************************************/ - -#ifndef PJ_WKT2_PARSER_H_INCLUDED -#define PJ_WKT2_PARSER_H_INCLUDED - -#ifndef DOXYGEN_SKIP - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct pj_wkt2_parse_context pj_wkt2_parse_context; - -#include "pj_wkt2_generated_parser.h" - -void pj_wkt2_error( pj_wkt2_parse_context *context, const char *msg ); -int pj_wkt2_lex(YYSTYPE* pNode, pj_wkt2_parse_context *context); -int pj_wkt2_parse(pj_wkt2_parse_context *context); - -#ifdef __cplusplus -} - -std::string pj_wkt2_parse(const std::string& wkt); - -#endif - -#endif /* #ifndef DOXYGEN_SKIP */ - -#endif /* PJ_WKT2_PARSER_H_INCLUDED */ diff --git a/src/pj_wkt_parser.cpp b/src/pj_wkt_parser.cpp deleted file mode 100644 index ea8d2a29..00000000 --- a/src/pj_wkt_parser.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/****************************************************************************** - * Project: PROJ - * Purpose: WKT parser common routines - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2018 Even Rouault, - * - * 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. - ****************************************************************************/ - -#include "pj_wkt_parser.hpp" - -#include -#include - -// --------------------------------------------------------------------------- - -void pj_wkt_error(pj_wkt_parse_context *context, const char *msg) { - context->errorMsg = "Parsing error : "; - context->errorMsg += msg; - context->errorMsg += ". Error occurred around:\n"; - - std::string ctxtMsg; - const int n = static_cast(context->pszLastSuccess - context->pszInput); - int start_i = std::max(0, n - 40); - for (int i = start_i; i < n + 40 && context->pszInput[i]; i++) { - if (context->pszInput[i] == '\r' || context->pszInput[i] == '\n') { - if (i > n) { - break; - } else { - ctxtMsg.clear(); - start_i = i + 1; - } - } else { - ctxtMsg += context->pszInput[i]; - } - } - context->errorMsg += ctxtMsg; - context->errorMsg += '\n'; - for (int i = start_i; i < n; i++) - context->errorMsg += ' '; - context->errorMsg += '^'; -} diff --git a/src/pj_wkt_parser.hpp b/src/pj_wkt_parser.hpp deleted file mode 100644 index 0e7e9e8b..00000000 --- a/src/pj_wkt_parser.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/****************************************************************************** - * Project: PROJ - * Purpose: WKT parser common routines - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2018 Even Rouault, - * - * 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. - ****************************************************************************/ - -#ifndef PJ_WKT_PARSER_H_INCLUDED -#define PJ_WKT_PARSER_H_INCLUDED - -//! @cond Doxygen_Suppress - -#include - -struct pj_wkt_parse_context { - const char *pszInput = nullptr; - const char *pszLastSuccess = nullptr; - const char *pszNext = nullptr; - std::string errorMsg{}; - - pj_wkt_parse_context() = default; - pj_wkt_parse_context(const pj_wkt_parse_context &) = delete; - pj_wkt_parse_context &operator=(const pj_wkt_parse_context &) = delete; -}; - -void pj_wkt_error(pj_wkt_parse_context *context, const char *msg); - -//! @endcond - -#endif // PJ_WKT_PARSER_H_INCLUDED diff --git a/src/pj_zpoly1.cpp b/src/pj_zpoly1.cpp deleted file mode 100644 index bacb62ce..00000000 --- a/src/pj_zpoly1.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* evaluate complex polynomial */ -#include "projects.h" -/* note: coefficients are always from C_1 to C_n -** i.e. C_0 == (0., 0) -** n should always be >= 1 though no checks are made -*/ - COMPLEX -pj_zpoly1(COMPLEX z, const COMPLEX *C, int n) { - COMPLEX a; - double t; - - a = *(C += n); - while (n-- > 0) { - a.r = (--C)->r + z.r * (t = a.r) - z.i * a.i; - a.i = C->i + z.r * a.i + z.i * t; - } - a.r = z.r * (t = a.r) - z.i * a.i; - a.i = z.r * a.i + z.i * t; - return a; -} -/* evaluate complex polynomial and derivative */ - COMPLEX -pj_zpolyd1(COMPLEX z, const COMPLEX *C, int n, COMPLEX *der) { - COMPLEX a, b; - double t; - int first = 1; - - a = *(C += n); - b = a; - while (n-- > 0) { - if (first) { - first = 0; - } else { - b.r = a.r + z.r * (t = b.r) - z.i * b.i; - b.i = a.i + z.r * b.i + z.i * t; - } - a.r = (--C)->r + z.r * (t = a.r) - z.i * a.i; - a.i = C->i + z.r * a.i + z.i * t; - } - b.r = a.r + z.r * (t = b.r) - z.i * b.i; - b.i = a.i + z.r * b.i + z.i * t; - a.r = z.r * (t = a.r) - z.i * a.i; - a.i = z.r * a.i + z.i * t; - *der = b; - return a; -} diff --git a/src/pr_list.cpp b/src/pr_list.cpp new file mode 100644 index 00000000..b8ad2c04 --- /dev/null +++ b/src/pr_list.cpp @@ -0,0 +1,104 @@ +/* print projection's list of parameters */ + +#include +#include +#include + +#include "projects.h" + +#define LINE_LEN 72 + static int +pr_list(PJ *P, int not_used) { + paralist *t; + int l, n = 1, flag = 0; + + (void)putchar('#'); + for (t = P->params; t; t = t->next) + if ((!not_used && t->used) || (not_used && !t->used)) { + l = (int)strlen(t->param) + 1; + if (n + l > LINE_LEN) { + (void)fputs("\n#", stdout); + n = 2; + } + (void)putchar(' '); + if (*(t->param) != '+') + (void)putchar('+'); + (void)fputs(t->param, stdout); + n += l; + } else + flag = 1; + if (n > 1) + (void)putchar('\n'); + return flag; +} + void /* print link list of projection parameters */ +pj_pr_list(PJ *P) { + char const *s; + + (void)putchar('#'); + for (s = P->descr; *s ; ++s) { + (void)putchar(*s); + if (*s == '\n') + (void)putchar('#'); + } + (void)putchar('\n'); + if (pr_list(P, 0)) { + (void)fputs("#--- following specified but NOT used\n", stdout); + (void)pr_list(P, 1); + } +} + +/************************************************************************/ +/* pj_get_def() */ +/* */ +/* Returns the PROJ.4 command string that would produce this */ +/* definition expanded as much as possible. For instance, */ +/* +init= calls and +datum= definitions would be expanded. */ +/************************************************************************/ + +char *pj_get_def( PJ *P, int options ) + +{ + paralist *t; + int l; + char *definition; + size_t def_max = 10; + (void) options; + + definition = (char *) pj_malloc(def_max); + if (!definition) + return nullptr; + definition[0] = '\0'; + + for (t = P->params; t; t = t->next) + { + /* skip unused parameters ... mostly appended defaults and stuff */ + if (!t->used) + continue; + + /* grow the resulting string if needed */ + l = (int)strlen(t->param) + 1; + if( strlen(definition) + l + 5 > def_max ) + { + char *def2; + + def_max = def_max * 2 + l + 5; + def2 = (char *) pj_malloc(def_max); + if (def2) { + strcpy( def2, definition ); + pj_dalloc( definition ); + definition = def2; + } + else { + pj_dalloc( definition ); + return nullptr; + } + } + + /* append this parameter */ + strcat( definition, " +" ); + strcat( definition, t->param ); + } + + return definition; +} diff --git a/src/proj_4D_api.cpp b/src/proj_4D_api.cpp deleted file mode 100644 index 88210348..00000000 --- a/src/proj_4D_api.cpp +++ /dev/null @@ -1,1285 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implement a (currently minimalistic) proj API based primarily - * on the PJ_COORD 4D geodetic spatiotemporal data type. - * - * Author: Thomas Knudsen, thokn@sdfe.dk, 2016-06-09/2016-11-06 - * - ****************************************************************************** - * Copyright (c) 2016, 2017 Thomas Knudsen/SDFE - * - * 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. - *****************************************************************************/ - -#include -#include -#include -#include -#include -#ifndef _MSC_VER -#include -#endif - -#include "proj.h" -#include "proj_internal.h" -#include "proj_math.h" -#include "projects.h" -#include "geodesic.h" - - -/* Initialize PJ_COORD struct */ -PJ_COORD proj_coord (double x, double y, double z, double t) { - PJ_COORD res; - res.v[0] = x; - res.v[1] = y; - res.v[2] = z; - res.v[3] = t; - return res; -} - -static PJ_DIRECTION opposite_direction(PJ_DIRECTION dir) { - return static_cast(-dir); -} - -/*****************************************************************************/ -int proj_angular_input (PJ *P, enum PJ_DIRECTION dir) { -/****************************************************************************** - Returns 1 if the operator P expects angular input coordinates when - operating in direction dir, 0 otherwise. - dir: {PJ_FWD, PJ_INV} -******************************************************************************/ - if (PJ_FWD==dir) - return pj_left (P)==PJ_IO_UNITS_ANGULAR; - return pj_right (P)==PJ_IO_UNITS_ANGULAR; -} - -/*****************************************************************************/ -int proj_angular_output (PJ *P, enum PJ_DIRECTION dir) { -/****************************************************************************** - Returns 1 if the operator P provides angular output coordinates when - operating in direction dir, 0 otherwise. - dir: {PJ_FWD, PJ_INV} -******************************************************************************/ - return proj_angular_input (P, opposite_direction(dir)); -} - - -/* Geodesic distance (in meter) + fwd and rev azimuth between two points on the ellipsoid */ -PJ_COORD proj_geod (const PJ *P, PJ_COORD a, PJ_COORD b) { - PJ_COORD c; - /* Note: the geodesic code takes arguments in degrees */ - geod_inverse (P->geod, - PJ_TODEG(a.lpz.phi), PJ_TODEG(a.lpz.lam), - PJ_TODEG(b.lpz.phi), PJ_TODEG(b.lpz.lam), - c.v, c.v+1, c.v+2 - ); - - return c; -} - - -/* Geodesic distance (in meter) between two points with angular 2D coordinates */ -double proj_lp_dist (const PJ *P, PJ_COORD a, PJ_COORD b) { - double s12, azi1, azi2; - /* Note: the geodesic code takes arguments in degrees */ - geod_inverse (P->geod, - PJ_TODEG(a.lpz.phi), PJ_TODEG(a.lpz.lam), - PJ_TODEG(b.lpz.phi), PJ_TODEG(b.lpz.lam), - &s12, &azi1, &azi2 - ); - return s12; -} - -/* The geodesic distance AND the vertical offset */ -double proj_lpz_dist (const PJ *P, PJ_COORD a, PJ_COORD b) { - if (HUGE_VAL==a.lpz.lam || HUGE_VAL==b.lpz.lam) - return HUGE_VAL; - return hypot (proj_lp_dist (P, a, b), a.lpz.z - b.lpz.z); -} - -/* Euclidean distance between two points with linear 2D coordinates */ -double proj_xy_dist (PJ_COORD a, PJ_COORD b) { - return hypot (a.xy.x - b.xy.x, a.xy.y - b.xy.y); -} - -/* Euclidean distance between two points with linear 3D coordinates */ -double proj_xyz_dist (PJ_COORD a, PJ_COORD b) { - return hypot (proj_xy_dist (a, b), a.xyz.z - b.xyz.z); -} - - - -/* Measure numerical deviation after n roundtrips fwd-inv (or inv-fwd) */ -double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_COORD *coord) { - int i; - PJ_COORD t, org; - - if (nullptr==P) - return HUGE_VAL; - - if (n < 1) { - proj_errno_set (P, EINVAL); - return HUGE_VAL; - } - - /* in the first half-step, we generate the output value */ - org = *coord; - *coord = proj_trans (P, direction, org); - t = *coord; - - /* now we take n-1 full steps in inverse direction: We are */ - /* out of phase due to the half step already taken */ - for (i = 0; i < n - 1; i++) - t = proj_trans (P, direction, proj_trans (P, opposite_direction(direction), t) ); - - /* finally, we take the last half-step */ - t = proj_trans (P, opposite_direction(direction), t); - - /* checking for angular *input* since we do a roundtrip, and end where we begin */ - if (proj_angular_input (P, direction)) - return proj_lpz_dist (P, org, t); - - return proj_xyz_dist (org, t); -} - - - -/**************************************************************************************/ -PJ_COORD proj_trans (PJ *P, PJ_DIRECTION direction, PJ_COORD coord) { -/*************************************************************************************** -Apply the transformation P to the coordinate coord, preferring the 4D interfaces if -available. - -See also pj_approx_2D_trans and pj_approx_3D_trans in pj_internal.c, which work -similarly, but prefers the 2D resp. 3D interfaces if available. -***************************************************************************************/ - if (nullptr==P) - return coord; - if (P->inverted) - direction = opposite_direction(direction); - - switch (direction) { - case PJ_FWD: - return pj_fwd4d (coord, P); - case PJ_INV: - return pj_inv4d (coord, P); - case PJ_IDENT: - return coord; - default: - break; - } - - proj_errno_set (P, EINVAL); - return proj_coord_error (); -} - - - -/*****************************************************************************/ -int proj_trans_array (PJ *P, PJ_DIRECTION direction, size_t n, PJ_COORD *coord) { -/****************************************************************************** - Batch transform an array of PJ_COORD. - - Returns 0 if all coordinates are transformed without error, otherwise - returns error number. -******************************************************************************/ - size_t i; - - for (i = 0; i < n; i++) { - coord[i] = proj_trans (P, direction, coord[i]); - if (proj_errno(P)) - return proj_errno (P); - } - - return 0; -} - - - -/*************************************************************************************/ -size_t proj_trans_generic ( - PJ *P, - PJ_DIRECTION direction, - double *x, size_t sx, size_t nx, - double *y, size_t sy, size_t ny, - double *z, size_t sz, size_t nz, - double *t, size_t st, size_t nt -) { -/************************************************************************************** - - Transform a series of coordinates, where the individual coordinate dimension - may be represented by an array that is either - - 1. fully populated - 2. a null pointer and/or a length of zero, which will be treated as a - fully populated array of zeroes - 3. of length one, i.e. a constant, which will be treated as a fully - populated array of that constant value - - The strides, sx, sy, sz, st, represent the step length, in bytes, between - consecutive elements of the corresponding array. This makes it possible for - proj_transform to handle transformation of a large class of application - specific data structures, without necessarily understanding the data structure - format, as in: - - typedef struct {double x, y; int quality_level; char surveyor_name[134];} XYQS; - XYQS survey[345]; - double height = 23.45; - PJ *P = {...}; - size_t stride = sizeof (XYQS); - ... - proj_transform ( - P, PJ_INV, sizeof(XYQS), - &(survey[0].x), stride, 345, (* We have 345 eastings *) - &(survey[0].y), stride, 345, (* ...and 345 northings. *) - &height, 1, (* The height is the constant 23.45 m *) - 0, 0 (* and the time is the constant 0.00 s *) - ); - - This is similar to the inner workings of the pj_transform function, but the - stride functionality has been generalized to work for any size of basic unit, - not just a fixed number of doubles. - - In most cases, the stride will be identical for x, y,z, and t, since they will - typically be either individual arrays (stride = sizeof(double)), or strided - views into an array of application specific data structures (stride = sizeof (...)). - - But in order to support cases where x, y, z, and t come from heterogeneous - sources, individual strides, sx, sy, sz, st, are used. - - Caveat: Since proj_transform does its work *in place*, this means that even the - supposedly constants (i.e. length 1 arrays) will return from the call in altered - state. Hence, remember to reinitialize between repeated calls. - - Return value: Number of transformations completed. - -**************************************************************************************/ - PJ_COORD coord = {{0,0,0,0}}; - size_t i, nmin; - double null_broadcast = 0; - - if (nullptr==P) - return 0; - - if (P->inverted) - direction = opposite_direction(direction); - - /* ignore lengths of null arrays */ - if (nullptr==x) nx = 0; - if (nullptr==y) ny = 0; - if (nullptr==z) nz = 0; - if (nullptr==t) nt = 0; - - /* and make the nullities point to some real world memory for broadcasting nulls */ - if (0==nx) x = &null_broadcast; - if (0==ny) y = &null_broadcast; - if (0==nz) z = &null_broadcast; - if (0==nt) t = &null_broadcast; - - /* nothing to do? */ - if (0==nx+ny+nz+nt) - return 0; - - /* arrays of length 1 are constants, which we broadcast along the longer arrays */ - /* so we need to find the length of the shortest non-unity array to figure out */ - /* how many coordinate pairs we must transform */ - nmin = (nx > 1)? nx: (ny > 1)? ny: (nz > 1)? nz: (nt > 1)? nt: 1; - if ((nx > 1) && (nx < nmin)) nmin = nx; - if ((ny > 1) && (ny < nmin)) nmin = ny; - if ((nz > 1) && (nz < nmin)) nmin = nz; - if ((nt > 1) && (nt < nmin)) nmin = nt; - - /* Check validity of direction flag */ - switch (direction) { - case PJ_FWD: - case PJ_INV: - break; - case PJ_IDENT: - return nmin; - default: - proj_errno_set (P, EINVAL); - return 0; - } - - /* Arrays of length==0 are broadcast as the constant 0 */ - /* Arrays of length==1 are broadcast as their single value */ - /* Arrays of length >1 are iterated over (for the first nmin values) */ - /* The slightly convolved incremental indexing is used due */ - /* to the stride, which may be any size supported by the platform */ - for (i = 0; i < nmin; i++) { - coord.xyzt.x = *x; - coord.xyzt.y = *y; - coord.xyzt.z = *z; - coord.xyzt.t = *t; - - if (PJ_FWD==direction) - coord = pj_fwd4d (coord, P); - else - coord = pj_inv4d (coord, P); - - /* in all full length cases, we overwrite the input with the output, */ - /* and step on to the next element. */ - /* The casts are somewhat funky, but they compile down to no-ops and */ - /* they tell compilers and static analyzers that we know what we do */ - if (nx > 1) { - *x = coord.xyzt.x; - x = (double *) ((void *) ( ((char *) x) + sx)); - } - if (ny > 1) { - *y = coord.xyzt.y; - y = (double *) ((void *) ( ((char *) y) + sy)); - } - if (nz > 1) { - *z = coord.xyzt.z; - z = (double *) ((void *) ( ((char *) z) + sz)); - } - if (nt > 1) { - *t = coord.xyzt.t; - t = (double *) ((void *) ( ((char *) t) + st)); - } - } - - /* Last time around, we update the length 1 cases with their transformed alter egos */ - if (nx==1) - *x = coord.xyzt.x; - if (ny==1) - *y = coord.xyzt.y; - if (nz==1) - *z = coord.xyzt.z; - if (nt==1) - *t = coord.xyzt.t; - - return i; -} - - -/*************************************************************************************/ -PJ_COORD pj_geocentric_latitude (const PJ *P, PJ_DIRECTION direction, PJ_COORD coord) { -/************************************************************************************** - Convert geographical latitude to geocentric (or the other way round if - direction = PJ_INV) - - The conversion involves a call to the tangent function, which goes through the - roof at the poles, so very close (the last centimeter) to the poles no - conversion takes place and the input latitude is copied directly to the output. - - Fortunately, the geocentric latitude converges to the geographical at the - poles, so the difference is negligible. - - For the spherical case, the geographical latitude equals the geocentric, and - consequently, the input is copied directly to the output. -**************************************************************************************/ - const double limit = M_HALFPI - 1e-9; - PJ_COORD res = coord; - if ((coord.lp.phi > limit) || (coord.lp.phi < -limit) || (P->es==0)) - return res; - if (direction==PJ_FWD) - res.lp.phi = atan (P->one_es * tan (coord.lp.phi) ); - else - res.lp.phi = atan (P->rone_es * tan (coord.lp.phi) ); - - return res; -} - -double proj_torad (double angle_in_degrees) { return PJ_TORAD (angle_in_degrees);} -double proj_todeg (double angle_in_radians) { return PJ_TODEG (angle_in_radians);} - -double proj_dmstor(const char *is, char **rs) { - return dmstor(is, rs); -} - -char* proj_rtodms(char *s, double r, int pos, int neg) { - return rtodms(s, r, pos, neg); -} - -/*************************************************************************************/ -static PJ* skip_prep_fin(PJ *P) { -/************************************************************************************** -Skip prepare and finalize function for the various "helper operations" added to P when -in cs2cs compatibility mode. -**************************************************************************************/ - P->skip_fwd_prepare = 1; - P->skip_fwd_finalize = 1; - P->skip_inv_prepare = 1; - P->skip_inv_finalize = 1; - return P; -} - -/*************************************************************************************/ -static int cs2cs_emulation_setup (PJ *P) { -/************************************************************************************** -If any cs2cs style modifiers are given (axis=..., towgs84=..., ) create the 4D API -equivalent operations, so the preparation and finalization steps in the pj_inv/pj_fwd -invocators can emulate the behaviour of pj_transform and the cs2cs app. - -Returns 1 on success, 0 on failure -**************************************************************************************/ - PJ *Q; - paralist *p; - int do_cart = 0; - if (nullptr==P) - return 0; - - /* Don't recurse when calling proj_create (which calls us back) */ - if (pj_param_exists (P->params, "break_cs2cs_recursion")) - return 1; - - /* Swap axes? */ - p = pj_param_exists (P->params, "axis"); - - /* Don't axisswap if data are already in "enu" order */ - if (p && (0!=strcmp ("enu", p->param))) { - char *def = static_cast(malloc (100+strlen(P->axis))); - if (nullptr==def) - return 0; - sprintf (def, "break_cs2cs_recursion proj=axisswap axis=%s", P->axis); - Q = proj_create (P->ctx, def); - free (def); - if (nullptr==Q) - return 0; - P->axisswap = skip_prep_fin(Q); - } - - /* Geoid grid(s) given? */ - p = pj_param_exists (P->params, "geoidgrids"); - if (p && strlen (p->param) > strlen ("geoidgrids=")) { - char *gridnames = p->param + strlen ("geoidgrids="); - char *def = static_cast(malloc (100+strlen(gridnames))); - if (nullptr==def) - return 0; - sprintf (def, "break_cs2cs_recursion proj=vgridshift grids=%s", gridnames); - Q = proj_create (P->ctx, def); - free (def); - if (nullptr==Q) - return 0; - P->vgridshift = skip_prep_fin(Q); - } - - /* Datum shift grid(s) given? */ - p = pj_param_exists (P->params, "nadgrids"); - if (p && strlen (p->param) > strlen ("nadgrids=")) { - char *gridnames = p->param + strlen ("nadgrids="); - char *def = static_cast(malloc (100+strlen(gridnames))); - if (nullptr==def) - return 0; - sprintf (def, "break_cs2cs_recursion proj=hgridshift grids=%s", gridnames); - Q = proj_create (P->ctx, def); - free (def); - if (nullptr==Q) - return 0; - P->hgridshift = skip_prep_fin(Q); - } - - /* We ignore helmert if we have grid shift */ - p = P->hgridshift ? nullptr : pj_param_exists (P->params, "towgs84"); - while (p) { - char *def; - char *s = p->param; - double *d = P->datum_params; - size_t n = strlen (s); - - /* We ignore null helmert shifts (common in auto-translated resource files, e.g. epsg) */ - if (0==d[0] && 0==d[1] && 0==d[2] && 0==d[3] && 0==d[4] && 0==d[5] && 0==d[6]) { - /* If the current ellipsoid is not WGS84, then make sure the */ - /* change in ellipsoid is still done. */ - if (!(fabs(P->a_orig - 6378137.0) < 1e-8 && fabs(P->es_orig - 0.0066943799901413) < 1e-15)) { - do_cart = 1; - } - break; - } - - if (n <= 8) /* 8==strlen ("towgs84=") */ - return 0; - - def = static_cast(malloc (100+n)); - if (nullptr==def) - return 0; - sprintf (def, "break_cs2cs_recursion proj=helmert exact %s convention=position_vector", s); - Q = proj_create (P->ctx, def); - free(def); - if (nullptr==Q) - return 0; - pj_inherit_ellipsoid_def (P, Q); - P->helmert = skip_prep_fin (Q); - - break; - } - - /* We also need cartesian/geographical transformations if we are working in */ - /* geocentric/cartesian space or we need to do a Helmert transform. */ - if (P->is_geocent || P->helmert || do_cart) { - char def[150]; - sprintf (def, "break_cs2cs_recursion proj=cart a=%40.20g es=%40.20g", P->a_orig, P->es_orig); - { - /* In case the current locale does not use dot but comma as decimal */ - /* separator, replace it with dot, so that proj_atof() behaves */ - /* correctly. */ - /* TODO later: use C++ ostringstream with imbue(std::locale::classic()) */ - /* to be locale unaware */ - char* next_pos; - for (next_pos = def; (next_pos = strchr (next_pos, ',')) != nullptr; next_pos++) { - *next_pos = '.'; - } - } - Q = proj_create (P->ctx, def); - if (nullptr==Q) - return 0; - P->cart = skip_prep_fin (Q); - - if (!P->is_geocent) { - sprintf (def, "break_cs2cs_recursion proj=cart ellps=WGS84"); - Q = proj_create (P->ctx, def); - if (nullptr==Q) - return 0; - P->cart_wgs84 = skip_prep_fin (Q); - } - } - - return 1; -} - - - -/*************************************************************************************/ -PJ *proj_create (PJ_CONTEXT *ctx, const char *definition) { -/************************************************************************************** - Create a new PJ object in the context ctx, using the given definition. If ctx==0, - the default context is used, if definition==0, or invalid, a null-pointer is - returned. The definition may use '+' as argument start indicator, as in - "+proj=utm +zone=32", or leave it out, as in "proj=utm zone=32". - - It may even use free formatting "proj = utm; zone =32 ellps= GRS80". - Note that the semicolon separator is allowed, but not required. -**************************************************************************************/ - PJ *P; - char *args, **argv; - size_t argc, n; - int ret; - int allow_init_epsg; - - if (nullptr==ctx) - ctx = pj_get_default_ctx (); - - /* Make a copy that we can manipulate */ - n = strlen (definition); - args = (char *) malloc (n + 1); - if (nullptr==args) { - proj_context_errno_set(ctx, ENOMEM); - return nullptr; - } - strcpy (args, definition); - - argc = pj_trim_argc (args); - if (argc==0) { - pj_dealloc (args); - proj_context_errno_set(ctx, PJD_ERR_NO_ARGS); - return nullptr; - } - - argv = pj_trim_argv (argc, args); - - /* ...and let pj_init_ctx do the hard work */ - /* New interface: forbid init=epsg:XXXX syntax by default */ - allow_init_epsg = proj_context_get_use_proj4_init_rules(ctx, FALSE); - P = pj_init_ctx_with_allow_init_epsg (ctx, (int) argc, argv, allow_init_epsg); - - pj_dealloc (argv); - pj_dealloc (args); - - /* Support cs2cs-style modifiers */ - ret = cs2cs_emulation_setup (P); - if (0==ret) - return proj_destroy (P); - - return P; -} - - - -/*************************************************************************************/ -PJ *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv) { -/************************************************************************************** -Create a new PJ object in the context ctx, using the given definition argument -array argv. If ctx==0, the default context is used, if definition==0, or invalid, -a null-pointer is returned. The definition arguments may use '+' as argument start -indicator, as in {"+proj=utm", "+zone=32"}, or leave it out, as in {"proj=utm", -"zone=32"}. -**************************************************************************************/ - PJ *P; - const char *c; - - if (nullptr==ctx) - ctx = pj_get_default_ctx (); - if (nullptr==argv) { - proj_context_errno_set(ctx, PJD_ERR_NO_ARGS); - return nullptr; - } - - /* We assume that free format is used, and build a full proj_create compatible string */ - c = pj_make_args (argc, argv); - if (nullptr==c) { - proj_context_errno_set(ctx, ENOMEM); - return nullptr; - } - - P = proj_create (ctx, c); - - pj_dealloc ((char *) c); - return P; -} - -/** Create an area of use */ -PJ_AREA * proj_area_create(void) { - return static_cast(pj_calloc(1, sizeof(PJ_AREA))); -} - -/** Assign a bounding box to an area of use. */ -void proj_area_set_bbox(PJ_AREA *area, - double west_lon_degree, - double south_lat_degree, - double east_lon_degree, - double north_lat_degree) { - area->bbox_set = TRUE; - area->west_lon_degree = west_lon_degree; - area->south_lat_degree = south_lat_degree; - area->east_lon_degree = east_lon_degree; - area->north_lat_degree = north_lat_degree; -} - -/** Free an area of use */ -void proj_area_destroy(PJ_AREA* area) { - pj_dealloc(area); -} - -/************************************************************************/ -/* proj_context_use_proj4_init_rules() */ -/************************************************************************/ - -void proj_context_use_proj4_init_rules(PJ_CONTEXT *ctx, int enable) { - if( ctx == nullptr ) { - ctx = pj_get_default_ctx(); - } - ctx->use_proj4_init_rules = enable; -} - -/************************************************************************/ -/* EQUAL() */ -/************************************************************************/ - -static int EQUAL(const char* a, const char* b) { -#ifdef _MSC_VER - return _stricmp(a, b) == 0; -#else - return strcasecmp(a, b) == 0; -#endif -} - -/************************************************************************/ -/* proj_context_get_use_proj4_init_rules() */ -/************************************************************************/ - -int proj_context_get_use_proj4_init_rules(PJ_CONTEXT *ctx, int from_legacy_code_path) { - const char* val = getenv("PROJ_USE_PROJ4_INIT_RULES"); - - if( ctx == nullptr ) { - ctx = pj_get_default_ctx(); - } - - if( val ) { - if( EQUAL(val, "yes") || EQUAL(val, "on") || EQUAL(val, "true") ) { - return TRUE; - } - if( EQUAL(val, "no") || EQUAL(val, "off") || EQUAL(val, "false") ) { - return FALSE; - } - pj_log(ctx, PJ_LOG_ERROR, "Invalid value for PROJ_USE_PROJ4_INIT_RULES"); - } - - if( ctx->use_proj4_init_rules >= 0 ) { - return ctx->use_proj4_init_rules; - } - return from_legacy_code_path; -} - - -/*****************************************************************************/ -PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char *target_crs, PJ_AREA *area) { -/****************************************************************************** - Create a transformation pipeline between two known coordinate reference - systems. - - source_crs and target_crs can be : - - a "AUTHORITY:CODE", like EPSG:25832. When using that syntax for a source - CRS, the created pipeline will expect that the values passed to proj_trans() - respect the axis order and axis unit of the official definition ( - so for example, for EPSG:4326, with latitude first and longitude next, - in degrees). Similarly, when using that syntax for a target CRS, output - values will be emitted according to the official definition of this CRS. - - a PROJ string, like "+proj=longlat +datum=WGS84". - When using that syntax, the axis order and unit for geographic CRS will - be longitude, latitude, and the unit degrees. - - more generally any string accepted by proj_obj_create_from_user_input() - - An "area of use" can be specified in area. When it is supplied, the more - accurate transformation between two given systems can be chosen. - - Example call: - - PJ *P = proj_create_crs_to_crs(0, "EPSG:25832", "EPSG:25833", NULL); - -******************************************************************************/ - PJ *P; - PJ_OBJ* src; - PJ_OBJ* dst; - PJ_OPERATION_FACTORY_CONTEXT* operation_ctx; - PJ_OBJ_LIST* op_list; - PJ_OBJ* op; - const char* proj_string; - const char* const optionsProj4Mode[] = { "USE_PROJ4_INIT_RULES=YES", nullptr }; - const char* const* optionsImportCRS = - proj_context_get_use_proj4_init_rules(ctx, FALSE) ? optionsProj4Mode : nullptr; - - src = proj_obj_create_from_user_input(ctx, source_crs, optionsImportCRS); - if( !src ) { - return nullptr; - } - - dst = proj_obj_create_from_user_input(ctx, target_crs, optionsImportCRS); - if( !dst ) { - proj_obj_destroy(src); - return nullptr; - } - - operation_ctx = proj_create_operation_factory_context(ctx, nullptr); - if( !operation_ctx ) { - proj_obj_destroy(src); - proj_obj_destroy(dst); - return nullptr; - } - - if( area && area->bbox_set ) { - proj_operation_factory_context_set_area_of_interest( - ctx, - operation_ctx, - area->west_lon_degree, - area->south_lat_degree, - area->east_lon_degree, - area->north_lat_degree); - } - - proj_operation_factory_context_set_grid_availability_use( - ctx, operation_ctx, PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID); - - op_list = proj_obj_create_operations(ctx, src, dst, operation_ctx); - - proj_operation_factory_context_destroy(operation_ctx); - proj_obj_destroy(src); - proj_obj_destroy(dst); - - if( !op_list ) { - return nullptr; - } - - if( proj_obj_list_get_count(op_list) == 0 ) { - proj_obj_list_destroy(op_list); - return nullptr; - } - - op = proj_obj_list_get(ctx, op_list, 0); - proj_obj_list_destroy(op_list); - if( !op ) { - return nullptr; - } - - proj_string = proj_obj_as_proj_string(ctx, op, PJ_PROJ_5, nullptr); - if( !proj_string) { - proj_obj_destroy(op); - return nullptr; - } - - if( proj_string[0] == '\0' ) { - /* Null transform ? */ - P = proj_create(ctx, "proj=affine"); - } else { - P = proj_create(ctx, proj_string); - } - - proj_obj_destroy(op); - - return P; -} - -PJ *proj_destroy (PJ *P) { - pj_free (P); - return nullptr; -} - -/*****************************************************************************/ -int proj_errno (const PJ *P) { -/****************************************************************************** - Read an error level from the context of a PJ. -******************************************************************************/ - return pj_ctx_get_errno (pj_get_ctx ((PJ *) P)); -} - -/*****************************************************************************/ -int proj_context_errno (PJ_CONTEXT *ctx) { -/****************************************************************************** - Read an error directly from a context, without going through a PJ - belonging to that context. -******************************************************************************/ - if (nullptr==ctx) - ctx = pj_get_default_ctx(); - return pj_ctx_get_errno (ctx); -} - -/*****************************************************************************/ -int proj_errno_set (const PJ *P, int err) { -/****************************************************************************** - Set context-errno, bubble it up to the thread local errno, return err -******************************************************************************/ - /* Use proj_errno_reset to explicitly clear the error status */ - if (0==err) - return 0; - - /* For P==0 err goes to the default context */ - proj_context_errno_set (pj_get_ctx ((PJ *) P), err); - errno = err; - return err; -} - -/*****************************************************************************/ -int proj_errno_restore (const PJ *P, int err) { -/****************************************************************************** - Use proj_errno_restore when the current function succeeds, but the - error flag was set on entry, and stored/reset using proj_errno_reset - in order to monitor for new errors. - - See usage example under proj_errno_reset () -******************************************************************************/ - if (0==err) - return 0; - proj_errno_set (P, err); - return 0; -} - -/*****************************************************************************/ -int proj_errno_reset (const PJ *P) { -/****************************************************************************** - Clears errno in the context and thread local levels - through the low level pj_ctx interface. - - Returns the previous value of the errno, for convenient reset/restore - operations: - - int foo (PJ *P) { - // errno may be set on entry, but we need to reset it to be able to - // check for errors from "do_something_with_P(P)" - int last_errno = proj_errno_reset (P); - - // local failure - if (0==P) - return proj_errno_set (P, 42); - - // call to function that may fail - do_something_with_P (P); - - // failure in do_something_with_P? - keep latest error status - if (proj_errno(P)) - return proj_errno (P); - - // success - restore previous error status, return 0 - return proj_errno_restore (P, last_errno); - } -******************************************************************************/ - int last_errno; - last_errno = proj_errno (P); - - pj_ctx_set_errno (pj_get_ctx ((PJ *) P), 0); - errno = 0; - pj_errno = 0; - return last_errno; -} - - -/* Create a new context */ -PJ_CONTEXT *proj_context_create (void) { - return pj_ctx_alloc (); -} - - -PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx) { - if (nullptr==ctx) - return nullptr; - - /* Trying to free the default context is a no-op (since it is statically allocated) */ - if (pj_get_default_ctx ()==ctx) - return nullptr; - - pj_ctx_free (ctx); - return nullptr; -} - - - - - - -/*****************************************************************************/ -static char *path_append (char *buf, const char *app, size_t *buf_size) { -/****************************************************************************** - Helper for proj_info() below. Append app to buf, separated by a - semicolon. Also handle allocation of longer buffer if needed. - - Returns buffer and adjusts *buf_size through provided pointer arg. -******************************************************************************/ - char *p; - size_t len, applen = 0, buflen = 0; -#ifdef _WIN32 - const char *delim = ";"; -#else - const char *delim = ":"; -#endif - - /* Nothing to do? */ - if (nullptr == app) - return buf; - applen = strlen (app); - if (0 == applen) - return buf; - - /* Start checking whether buf is long enough */ - if (nullptr != buf) - buflen = strlen (buf); - len = buflen+applen+strlen (delim) + 1; - - /* "pj_realloc", so to speak */ - if (*buf_size < len) { - p = static_cast(pj_calloc (2 * len, sizeof (char))); - if (nullptr==p) { - pj_dealloc (buf); - return nullptr; - } - *buf_size = 2 * len; - if (buf != nullptr) - strcpy (p, buf); - pj_dealloc (buf); - buf = p; - } - - /* Only append a semicolon if something's already there */ - if (0 != buflen) - strcat (buf, ";"); - strcat (buf, app); - return buf; -} - -static const char *empty = {""}; -static char version[64] = {""}; -static PJ_INFO info = {0, 0, 0, nullptr, nullptr, nullptr, nullptr, 0}; -static volatile int info_initialized = 0; - -/*****************************************************************************/ -PJ_INFO proj_info (void) { -/****************************************************************************** - Basic info about the current instance of the PROJ.4 library. - - Returns PJ_INFO struct. -******************************************************************************/ - const char * const *paths; - size_t i, n; - - size_t buf_size = 0; - char *buf = nullptr; - - pj_acquire_lock (); - - if (0!=info_initialized) { - pj_release_lock (); - return info; - } - - info.major = PROJ_VERSION_MAJOR; - info.minor = PROJ_VERSION_MINOR; - info.patch = PROJ_VERSION_PATCH; - - /* This is a controlled environment, so no risk of sprintf buffer - overflow. A normal version string is xx.yy.zz which is 8 characters - long and there is room for 64 bytes in the version string. */ - sprintf (version, "%d.%d.%d", info.major, info.minor, info.patch); - - info.searchpath = empty; - info.version = version; - info.release = pj_get_release (); - - /* build search path string */ - buf = path_append (buf, getenv ("HOME"), &buf_size); - buf = path_append (buf, getenv ("PROJ_LIB"), &buf_size); - - paths = proj_get_searchpath (); - n = (size_t) proj_get_path_count (); - - for (i = 0; i < n; i++) - buf = path_append (buf, paths[i], &buf_size); - info.searchpath = buf ? buf : empty; - - info.paths = paths; - info.path_count = n; - - info_initialized = 1; - pj_release_lock (); - return info; -} - - -/*****************************************************************************/ -PJ_PROJ_INFO proj_pj_info(PJ *P) { -/****************************************************************************** - Basic info about a particular instance of a projection object. - - Returns PJ_PROJ_INFO struct. -******************************************************************************/ - PJ_PROJ_INFO pjinfo; - char *def; - - memset(&pjinfo, 0, sizeof(PJ_PROJ_INFO)); - - /* Expected accuracy of the transformation. Hardcoded for now, will be improved */ - /* later. Most likely to be used when a transformation is set up with */ - /* proj_create_crs_to_crs in a future version that leverages the EPSG database. */ - pjinfo.accuracy = -1.0; - - if (nullptr==P) - return pjinfo; - - /* projection id */ - if (pj_param(P->ctx, P->params, "tproj").i) - pjinfo.id = pj_param(P->ctx, P->params, "sproj").s; - - /* projection description */ - pjinfo.description = P->descr; - - /* projection definition */ - if (P->def_full) - def = P->def_full; - else - def = pj_get_def(P, 0); /* pj_get_def takes a non-const PJ pointer */ - if (nullptr==def) - pjinfo.definition = empty; - else - pjinfo.definition = pj_shrink (def); - /* Make pj_free clean this up eventually */ - P->def_full = def; - - pjinfo.has_inverse = pj_has_inverse(P); - return pjinfo; -} - - -/*****************************************************************************/ -PJ_GRID_INFO proj_grid_info(const char *gridname) { -/****************************************************************************** - Information about a named datum grid. - - Returns PJ_GRID_INFO struct. -******************************************************************************/ - PJ_GRID_INFO grinfo; - - /*PJ_CONTEXT *ctx = proj_context_create(); */ - PJ_CONTEXT *ctx = pj_get_default_ctx(); - PJ_GRIDINFO *gridinfo = pj_gridinfo_init(ctx, gridname); - memset(&grinfo, 0, sizeof(PJ_GRID_INFO)); - - /* in case the grid wasn't found */ - if (gridinfo->filename == nullptr) { - pj_gridinfo_free(ctx, gridinfo); - strcpy(grinfo.format, "missing"); - return grinfo; - } - - /* The string copies below are automatically null-terminated due to */ - /* the memset above, so strncpy is safe */ - - /* name of grid */ - strncpy (grinfo.gridname, gridname, sizeof(grinfo.gridname) - 1); - - /* full path of grid */ - pj_find_file(ctx, gridname, grinfo.filename, sizeof(grinfo.filename) - 1); - - /* grid format */ - strncpy (grinfo.format, gridinfo->format, sizeof(grinfo.format) - 1); - - /* grid size */ - grinfo.n_lon = gridinfo->ct->lim.lam; - grinfo.n_lat = gridinfo->ct->lim.phi; - - /* cell size */ - grinfo.cs_lon = gridinfo->ct->del.lam; - grinfo.cs_lat = gridinfo->ct->del.phi; - - /* bounds of grid */ - grinfo.lowerleft = gridinfo->ct->ll; - grinfo.upperright.lam = grinfo.lowerleft.lam + grinfo.n_lon*grinfo.cs_lon; - grinfo.upperright.phi = grinfo.lowerleft.phi + grinfo.n_lat*grinfo.cs_lat; - - pj_gridinfo_free(ctx, gridinfo); - - return grinfo; -} - - - -/*****************************************************************************/ -PJ_INIT_INFO proj_init_info(const char *initname){ -/****************************************************************************** - Information about a named init file. - - Maximum length of initname is 64. - - Returns PJ_INIT_INFO struct. - - If the init file is not found all members of the return struct are set - to the empty string. - - If the init file is found, but the metadata is missing, the value is - set to "Unknown". -******************************************************************************/ - int file_found; - char param[80], key[74]; - paralist *start, *next; - PJ_INIT_INFO ininfo; - PJ_CONTEXT *ctx = pj_get_default_ctx(); - - memset(&ininfo, 0, sizeof(PJ_INIT_INFO)); - - file_found = pj_find_file(ctx, initname, ininfo.filename, sizeof(ininfo.filename)); - if (!file_found || strlen(initname) > 64) { - if( strcmp(initname, "epsg") == 0 || strcmp(initname, "EPSG") == 0 ) { - const char* val; - - pj_ctx_set_errno( ctx, 0 ); - - strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); - strcpy(ininfo.origin, "EPSG"); - val = proj_context_get_database_metadata(ctx, "EPSG.VERSION"); - if( val ) { - strncpy(ininfo.version, val, sizeof(ininfo.version) - 1); - } - val = proj_context_get_database_metadata(ctx, "EPSG.DATE"); - if( val ) { - strncpy(ininfo.lastupdate, val, sizeof(ininfo.lastupdate) - 1); - } - return ininfo; - } - - if( strcmp(initname, "IGNF") == 0 ) { - const char* val; - - pj_ctx_set_errno( ctx, 0 ); - - strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); - strcpy(ininfo.origin, "IGNF"); - val = proj_context_get_database_metadata(ctx, "IGNF.VERSION"); - if( val ) { - strncpy(ininfo.version, val, sizeof(ininfo.version) - 1); - } - val = proj_context_get_database_metadata(ctx, "IGNF.DATE"); - if( val ) { - strncpy(ininfo.lastupdate, val, sizeof(ininfo.lastupdate) - 1); - } - return ininfo; - } - - return ininfo; - } - - /* The initial memset (0) makes strncpy safe here */ - strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); - strcpy(ininfo.origin, "Unknown"); - strcpy(ininfo.version, "Unknown"); - strcpy(ininfo.lastupdate, "Unknown"); - - strncpy (key, initname, 64); /* make room for ":metadata\0" at the end */ - key[64] = 0; - memcpy(key + strlen(key), ":metadata", 9 + 1); - strcpy(param, "+init="); - /* The +strlen(param) avoids a cppcheck false positive warning */ - strncat(param + strlen(param), key, sizeof(param)-1-strlen(param)); - - start = pj_mkparam(param); - pj_expand_init(ctx, start); - - if (pj_param(ctx, start, "tversion").i) - strncpy(ininfo.version, pj_param(ctx, start, "sversion").s, sizeof(ininfo.version) - 1); - - if (pj_param(ctx, start, "torigin").i) - strncpy(ininfo.origin, pj_param(ctx, start, "sorigin").s, sizeof(ininfo.origin) - 1); - - if (pj_param(ctx, start, "tlastupdate").i) - strncpy(ininfo.lastupdate, pj_param(ctx, start, "slastupdate").s, sizeof(ininfo.lastupdate) - 1); - - for ( ; start; start = next) { - next = start->next; - pj_dalloc(start); - } - - return ininfo; -} - - - -/*****************************************************************************/ -PJ_FACTORS proj_factors(PJ *P, PJ_COORD lp) { -/****************************************************************************** - Cartographic characteristics at point lp. - - Characteristics include meridian, parallel and areal scales, angular - distortion, meridian/parallel, meridian convergence and scale error. - - returns PJ_FACTORS. If unsuccessful, error number is set and the - struct returned contains NULL data. -******************************************************************************/ - PJ_FACTORS factors = {0,0,0, 0,0,0, 0,0, 0,0,0,0}; - struct FACTORS f; - - if (nullptr==P) - return factors; - - if (pj_factors(lp.lp, P, 0.0, &f)) - return factors; - - factors.meridional_scale = f.h; - factors.parallel_scale = f.k; - factors.areal_scale = f.s; - - factors.angular_distortion = f.omega; - factors.meridian_parallel_angle = f.thetap; - factors.meridian_convergence = f.conv; - - factors.tissot_semimajor = f.a; - factors.tissot_semiminor = f.b; - - /* Raw derivatives, for completeness's sake */ - factors.dx_dlam = f.der.x_l; - factors.dx_dphi = f.der.x_p; - factors.dy_dlam = f.der.y_l; - factors.dy_dphi = f.der.y_p; - - return factors; -} 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; +} diff --git a/src/qsfn.cpp b/src/qsfn.cpp new file mode 100644 index 00000000..c18a7b95 --- /dev/null +++ b/src/qsfn.cpp @@ -0,0 +1,22 @@ +/* determine small q */ +#include +#include "projects.h" + +# define EPSILON 1.0e-7 + +double pj_qsfn(double sinphi, double e, double one_es) { + double con, div1, div2; + + if (e >= EPSILON) { + con = e * sinphi; + div1 = 1.0 - con * con; + div2 = 1.0 + con; + + /* avoid zero division, fail gracefully */ + if (div1 == 0.0 || div2 == 0.0) + return HUGE_VAL; + + return (one_es * (sinphi / div1 - (.5 / e) * log ((1. - con) / div2 ))); + } else + return (sinphi + sinphi); +} diff --git a/src/release.cpp b/src/release.cpp new file mode 100644 index 00000000..9beb45ef --- /dev/null +++ b/src/release.cpp @@ -0,0 +1,18 @@ +/* <<< Release Notice for library >>> */ + +#include "proj.h" +#include "projects.h" + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +char const pj_release[] = + "Rel. " + STR(PROJ_VERSION_MAJOR)"." + STR(PROJ_VERSION_MINOR)"." + STR(PROJ_VERSION_PATCH)", " + "March 1st, 2019"; + +const char *pj_get_release() { + return pj_release; +} diff --git a/src/strerrno.cpp b/src/strerrno.cpp new file mode 100644 index 00000000..18ed0d33 --- /dev/null +++ b/src/strerrno.cpp @@ -0,0 +1,109 @@ +/* list of projection system pj_errno values */ + +#include +#include +#include + +#include "proj.h" +#include "projects.h" + +static const char * const +pj_err_list[] = { + "no arguments in initialization list", /* -1 */ + "no options found in 'init' file", /* -2 */ + "no colon in init= string", /* -3 */ + "projection not named", /* -4 */ + "unknown projection id", /* -5 */ + "effective eccentricity = 1.", /* -6 */ + "unknown unit conversion id", /* -7 */ + "invalid boolean param argument", /* -8 */ + "unknown elliptical parameter name", /* -9 */ + "reciprocal flattening (1/f) = 0", /* -10 */ + "|radius reference latitude| > 90", /* -11 */ + "squared eccentricity < 0", /* -12 */ + "major axis or radius = 0 or not given", /* -13 */ + "latitude or longitude exceeded limits", /* -14 */ + "invalid x or y", /* -15 */ + "improperly formed DMS value", /* -16 */ + "non-convergent inverse meridional dist", /* -17 */ + "non-convergent inverse phi2", /* -18 */ + "acos/asin: |arg| >1.+1e-14", /* -19 */ + "tolerance condition error", /* -20 */ + "conic lat_1 = -lat_2", /* -21 */ + "lat_1 >= 90", /* -22 */ + "lat_1 = 0", /* -23 */ + "lat_ts >= 90", /* -24 */ + "no distance between control points", /* -25 */ + "projection not selected to be rotated", /* -26 */ + "W <= 0 or M <= 0", /* -27 */ + "lsat not in 1-5 range", /* -28 */ + "path not in range", /* -29 */ + "h <= 0", /* -30 */ + "k <= 0", /* -31 */ + "lat_0 = 0 or 90 or alpha = 90", /* -32 */ + "lat_1=lat_2 or lat_1=0 or lat_2=90", /* -33 */ + "elliptical usage required", /* -34 */ + "invalid UTM zone number", /* -35 */ + "arg(s) out of range for Tcheby eval", /* -36 */ + "failed to find projection to be rotated", /* -37 */ + "failed to load datum shift file", /* -38 */ + "both n & m must be spec'd and > 0", /* -39 */ + "n <= 0, n > 1 or not specified", /* -40 */ + "lat_1 or lat_2 not specified", /* -41 */ + "|lat_1| == |lat_2|", /* -42 */ + "lat_0 is pi/2 from mean lat", /* -43 */ + "unparseable coordinate system definition", /* -44 */ + "geocentric transformation missing z or ellps", /* -45 */ + "unknown prime meridian conversion id", /* -46 */ + "illegal axis orientation combination", /* -47 */ + "point not within available datum shift grids", /* -48 */ + "invalid sweep axis, choose x or y", /* -49 */ + "malformed pipeline", /* -50 */ + "unit conversion factor must be > 0", /* -51 */ + "invalid scale", /* -52 */ + "non-convergent computation", /* -53 */ + "missing required arguments", /* -54 */ + "lat_0 = 0", /* -55 */ + "ellipsoidal usage unsupported", /* -56 */ + "only one +init allowed for non-pipeline operations", /* -57 */ + "argument not numerical or out of range", /* -58 */ + "inconsistent unit type between input and output", /* -59 */ + + /* When adding error messages, remember to update ID defines in + projects.h, and transient_error array in pj_transform */ +}; + +char *pj_strerrno(int err) { + const int max_error = 9999; + static char note[50]; + size_t adjusted_err; + + if (0==err) + return nullptr; + + /* System error codes are positive */ + if (err > 0) { +#ifdef HAVE_STRERROR + return strerror(err); +#else + /* Defend string boundary against exorbitantly large err values */ + /* which may occur on platforms with 64-bit ints */ + sprintf(note, "no system list, errno: %d\n", + (err < max_error) ? err: max_error); + return note; +#endif + } + + /* PROJ.4 error codes are negative: -1 to -9999 */ + adjusted_err = err < -max_error ? max_error : -err - 1; + if (adjusted_err < (sizeof(pj_err_list) / sizeof(char *))) + return (char *)pj_err_list[adjusted_err]; + + sprintf(note, "invalid projection system error (%d)", + (err > -max_error) ? err: -max_error); + return note; +} + +const char* proj_errno_string(int err) { + return pj_strerrno(err); +} diff --git a/src/strtod.cpp b/src/strtod.cpp new file mode 100644 index 00000000..5a360c2e --- /dev/null +++ b/src/strtod.cpp @@ -0,0 +1,195 @@ +/****************************************************************************** + * + * Derived from GDAL port/cpl_strtod.cpp + * Purpose: Functions to convert ASCII string to floating point number. + * Author: Andrey Kiselev, dron@ak4719.spb.edu. + * + ****************************************************************************** + * Copyright (c) 2006, Andrey Kiselev + * Copyright (c) 2008-2012, Even Rouault + * + * 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. + ****************************************************************************/ + +#include +#include +#include +#include + +#include "projects.h" + +/* Windows nmake build doesn't have a proj_config.h, but HAVE_LOCALECONV */ +/* is defined in the compilation line */ +#ifndef HAVE_LOCALECONV +#include "proj_config.h" +#endif + +#define PJ_STRTOD_WORK_BUFFER_SIZE 64 + +/************************************************************************/ +/* pj_atof() */ +/************************************************************************/ + +/** + * Converts ASCII string to floating point number. + * + * This function converts the initial portion of the string pointed to + * by nptr to double floating point representation. The behaviour is the + * same as + * + * pj_strtod(nptr, (char **)NULL); + * + * This function does the same as standard atof(3), but does not take + * locale in account. That means, the decimal delimiter is always '.' + * (decimal point). + * + * @param nptr Pointer to string to convert. + * + * @return Converted value. + */ +double pj_atof( const char* nptr ) +{ + return pj_strtod(nptr, nullptr); +} + + +/************************************************************************/ +/* replace_point_by_locale_point() */ +/************************************************************************/ + +static char* replace_point_by_locale_point(const char* pszNumber, char point, + char* pszWorkBuffer) +{ +#if !defined(HAVE_LOCALECONV) + +#if defined(_MSC_VER) /* Visual C++ */ +#pragma message("localeconv not available") +#else +#warning "localeconv not available" +#endif + + static char byPoint = 0; + if (byPoint == 0) + { + char szBuf[16]; + sprintf(szBuf, "%.1f", 1.0); + byPoint = szBuf[1]; + } + if (point != byPoint) + { + const char* pszPoint = strchr(pszNumber, point); + if (pszPoint) + { + char* pszNew; + if( strlen(pszNumber) < PJ_STRTOD_WORK_BUFFER_SIZE ) + { + strcpy(pszWorkBuffer, pszNumber); + pszNew = pszWorkBuffer; + } + else { + pszNew = pj_strdup(pszNumber); + if (!pszNew) + return NULL; + } + pszNew[pszPoint - pszNumber] = byPoint; + return pszNew; + } + } +#else + struct lconv *poLconv = localeconv(); + if ( poLconv + && poLconv->decimal_point + && poLconv->decimal_point[0] != '\0' ) + { + char byPoint = poLconv->decimal_point[0]; + + if (point != byPoint) + { + const char* pszLocalePoint = strchr(pszNumber, byPoint); + const char* pszPoint = strchr(pszNumber, point); + if (pszPoint || pszLocalePoint) + { + char* pszNew; + if( strlen(pszNumber) < PJ_STRTOD_WORK_BUFFER_SIZE ) + { + strcpy(pszWorkBuffer, pszNumber); + pszNew = pszWorkBuffer; + } + else { + pszNew = pj_strdup(pszNumber); + if (!pszNew) + return nullptr; + } + if( pszLocalePoint ) + pszNew[pszLocalePoint - pszNumber] = ' '; + if( pszPoint ) + pszNew[pszPoint - pszNumber] = byPoint; + return pszNew; + } + } + } +#endif + return (char*) pszNumber; +} + +/************************************************************************/ +/* pj_strtod() */ +/************************************************************************/ + +/** + * Converts ASCII string to floating point number. + * + * This function converts the initial portion of the string pointed to + * by nptr to double floating point representation. This function does the + * same as standard strtod(3), but does not take locale in account and use + * decimal point. + * + * @param nptr Pointer to string to convert. + * @param endptr If is not NULL, a pointer to the character after the last + * character used in the conversion is stored in the location referenced + * by endptr. + * + * @return Converted value. + */ +double pj_strtod( const char *nptr, char **endptr ) +{ +/* -------------------------------------------------------------------- */ +/* We are implementing a simple method here: copy the input string */ +/* into the temporary buffer, replace the specified decimal delimiter */ +/* with the one, taken from locale settings and use standard strtod() */ +/* on that buffer. */ +/* -------------------------------------------------------------------- */ + double dfValue; + int nError; + char szWorkBuffer[PJ_STRTOD_WORK_BUFFER_SIZE]; + + char* pszNumber = replace_point_by_locale_point(nptr, '.', szWorkBuffer); + + dfValue = strtod( pszNumber, endptr ); + nError = errno; + + if ( endptr ) + *endptr = (char *)nptr + (*endptr - pszNumber); + + if (pszNumber != (char*) nptr && pszNumber != szWorkBuffer ) + free( pszNumber ); + + errno = nError; + return dfValue; +} diff --git a/src/transform.cpp b/src/transform.cpp new file mode 100644 index 00000000..433fc017 --- /dev/null +++ b/src/transform.cpp @@ -0,0 +1,1047 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Perform overall coordinate system to coordinate system + * transformations (pj_transform() function) including reprojection + * and datum shifting. + * 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. + *****************************************************************************/ + +#include +#include +#include + +#include "proj.h" +#include "projects.h" +#include "geocent.h" + +static int adjust_axis( projCtx ctx, const char *axis, int denormalize_flag, + long point_count, int point_offset, + double *x, double *y, double *z ); + +#ifndef SRS_WGS84_SEMIMAJOR +#define SRS_WGS84_SEMIMAJOR 6378137.0 +#endif + +#ifndef SRS_WGS84_ESQUARED +#define SRS_WGS84_ESQUARED 0.0066943799901413165 +#endif + +#define Dx_BF (defn->datum_params[0]) +#define Dy_BF (defn->datum_params[1]) +#define Dz_BF (defn->datum_params[2]) +#define Rx_BF (defn->datum_params[3]) +#define Ry_BF (defn->datum_params[4]) +#define Rz_BF (defn->datum_params[5]) +#define M_BF (defn->datum_params[6]) + +/* +** This table is intended to indicate for any given error code +** whether that error will occur for all locations (ie. +** it is a problem with the coordinate system as a whole) in which case the +** value would be 0, or if the problem is with the point being transformed +** in which case the value is 1. +** +** At some point we might want to move this array in with the error message +** list or something, but while experimenting with it this should be fine. +** +** +** NOTE (2017-10-01): Non-transient errors really should have resulted in a +** PJ==0 during initialization, and hence should be handled at the level +** before calling pj_transform. The only obvious example of the contrary +** appears to be the PJD_ERR_GRID_AREA case, which may also be taken to +** mean "no grids available" +** +** +*/ + +static const int transient_error[60] = { + /* 0 1 2 3 4 5 6 7 8 9 */ + /* 0 to 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 10 to 19 */ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, + /* 20 to 29 */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, + /* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 40 to 49 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + /* 50 to 59 */ 1, 0, 1, 0, 1, 1, 1, 1, 0, 0 }; + + +/* -------------------------------------------------------------------- */ +/* Read transient_error[] in a safe way. */ +/* -------------------------------------------------------------------- */ +static int get_transient_error_value(int pos_index) +{ + const int array_size = + (int)(sizeof(transient_error) / sizeof(transient_error[0])); + if( pos_index < 0 || pos_index >= array_size ) { + return 0; + } + return transient_error[pos_index]; +} + + +/* -------------------------------------------------------------------- */ +/* Transform unusual input coordinate axis orientation to */ +/* standard form if needed. */ +/* -------------------------------------------------------------------- */ +static int adjust_axes (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { + /* Nothing to do? */ + if (0==strcmp(P->axis,"enu")) + return 0; + + return adjust_axis( P->ctx, P->axis, + dir==PJ_FWD ? 1: 0, n, dist, x, y, z ); +} + + + +/* ----------------------------------------------------------------------- */ +/* Transform geographic (lat/long) source coordinates to */ +/* cartesian ("geocentric"), if needed */ +/* ----------------------------------------------------------------------- */ +static int geographic_to_cartesian (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { + int res; + long i; + double fac = P->to_meter; + + /* Nothing to do? */ + if (!P->is_geocent) + return 0; + + if ( z == nullptr ) { + pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); + return PJD_ERR_GEOCENTRIC; + } + + if (PJ_FWD==dir) { + fac = P->fr_meter; + res = pj_geodetic_to_geocentric( P->a_orig, P->es_orig, n, dist, x, y, z ); + if (res) + return res; + } + + if (fac != 1.0) { + for( i = 0; i < n; i++ ) { + if( x[dist*i] != HUGE_VAL ) { + x[dist*i] *= fac; + y[dist*i] *= fac; + z[dist*i] *= fac; + } + } + } + + if (PJ_FWD==dir) + return 0; + return pj_geocentric_to_geodetic( + P->a_orig, P->es_orig, + n, dist, + x, y, z + ); +} + + + + + + + + + + +/* -------------------------------------------------------------------- */ +/* Transform destination points to projection coordinates, if */ +/* desired. */ +/* */ +/* Ought to fold this into projected_to_geographic */ +/* -------------------------------------------------------------------- */ +static int geographic_to_projected (PJ *P, long n, int dist, double *x, double *y, double *z) { + long i; + + /* Nothing to do? */ + if (P->is_latlong && !P->geoc && P->vto_meter == 1.0) + return 0; + if (P->is_geocent) + return 0; + + if(P->fwd3d != nullptr && !(z == nullptr && P->is_latlong)) + { + /* Three dimensions must be defined */ + if ( z == nullptr) + { + pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); + return PJD_ERR_GEOCENTRIC; + } + + for( i = 0; i < n; i++ ) + { + XYZ projected_loc; + LPZ geodetic_loc; + + geodetic_loc.lam = x[dist*i]; + geodetic_loc.phi = y[dist*i]; + geodetic_loc.z = z[dist*i]; + + if (geodetic_loc.lam == HUGE_VAL) + continue; + + proj_errno_reset( P ); + projected_loc = pj_fwd3d( geodetic_loc, P); + if( P->ctx->last_errno != 0 ) + { + if( (P->ctx->last_errno != EDOM + && P->ctx->last_errno != ERANGE) + && (P->ctx->last_errno > 0 + || P->ctx->last_errno < -44 || n == 1 + || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) + { + return P->ctx->last_errno; + } + else + { + projected_loc.x = HUGE_VAL; + projected_loc.y = HUGE_VAL; + projected_loc.z = HUGE_VAL; + } + } + + x[dist*i] = projected_loc.x; + y[dist*i] = projected_loc.y; + z[dist*i] = projected_loc.z; + } + return 0; + } + + for( i = 0; i ctx->last_errno != 0 ) + { + if( (P->ctx->last_errno != EDOM + && P->ctx->last_errno != ERANGE) + && (P->ctx->last_errno > 0 + || P->ctx->last_errno < -44 || n == 1 + || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) + { + return P->ctx->last_errno; + } + else + { + projected_loc.x = HUGE_VAL; + projected_loc.y = HUGE_VAL; + } + } + + x[dist*i] = projected_loc.x; + y[dist*i] = projected_loc.y; + } + return 0; +} + + + + + +/* ----------------------------------------------------------------------- */ +/* Transform projected source coordinates to lat/long, if needed */ +/* ----------------------------------------------------------------------- */ +static int projected_to_geographic (PJ *P, long n, int dist, double *x, double *y, double *z) { + long i; + + /* Nothing to do? */ + if (P->is_latlong && !P->geoc && P->vto_meter == 1.0) + return 0; + if (P->is_geocent) + return 0; + + /* Check first if projection is invertible. */ + if( (P->inv3d == nullptr) && (P->inv == nullptr)) + { + pj_ctx_set_errno(pj_get_ctx(P), PJD_ERR_NON_CONV_INV_MERI_DIST); + pj_log( pj_get_ctx(P), PJ_LOG_ERROR, + "pj_transform(): source projection not invertable" ); + return PJD_ERR_NON_CONV_INV_MERI_DIST; + } + + /* If invertible - First try inv3d if defined */ + if (P->inv3d != nullptr && !(z == nullptr && P->is_latlong)) + { + /* Three dimensions must be defined */ + if ( z == nullptr) + { + pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); + return PJD_ERR_GEOCENTRIC; + } + + for (i=0; i < n; i++) + { + XYZ projected_loc; + LPZ geodetic_loc; + + projected_loc.x = x[dist*i]; + projected_loc.y = y[dist*i]; + projected_loc.z = z[dist*i]; + + if (projected_loc.x == HUGE_VAL) + continue; + + proj_errno_reset( P ); + geodetic_loc = pj_inv3d(projected_loc, P); + if( P->ctx->last_errno != 0 ) + { + if( (P->ctx->last_errno != EDOM + && P->ctx->last_errno != ERANGE) + && (P->ctx->last_errno > 0 + || P->ctx->last_errno < -44 || n == 1 + || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) + { + return P->ctx->last_errno; + } + else + { + geodetic_loc.lam = HUGE_VAL; + geodetic_loc.phi = HUGE_VAL; + geodetic_loc.z = HUGE_VAL; + } + } + + x[dist*i] = geodetic_loc.lam; + y[dist*i] = geodetic_loc.phi; + z[dist*i] = geodetic_loc.z; + + } + return 0; + } + + /* Fallback to the original PROJ.4 API 2d inversion - inv */ + for( i = 0; i < n; i++ ) { + XY projected_loc; + LP geodetic_loc; + + projected_loc.x = x[dist*i]; + projected_loc.y = y[dist*i]; + + if( projected_loc.x == HUGE_VAL ) + continue; + + proj_errno_reset( P ); + geodetic_loc = pj_inv( projected_loc, P ); + if( P->ctx->last_errno != 0 ) + { + if( (P->ctx->last_errno != EDOM + && P->ctx->last_errno != ERANGE) + && (P->ctx->last_errno > 0 + || P->ctx->last_errno < -44 || n == 1 + || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) + { + return P->ctx->last_errno; + } + else + { + geodetic_loc.lam = HUGE_VAL; + geodetic_loc.phi = HUGE_VAL; + } + } + + x[dist*i] = geodetic_loc.lam; + y[dist*i] = geodetic_loc.phi; + } + return 0; +} + + + +/* -------------------------------------------------------------------- */ +/* Adjust for the prime meridian if needed. */ +/* -------------------------------------------------------------------- */ +static int prime_meridian (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x) { + int i; + double pm = P->from_greenwich; + + /* Nothing to do? */ + if (pm==0.0) + return 0; + if (!(P->is_geocent || P->is_latlong)) + return 0; + + if (dir==PJ_FWD) + pm = -pm; + + for (i = 0; i < n; i++) + if (x[dist*i] != HUGE_VAL) + x[dist*i] += pm; + + return 0; +} + + + +/* -------------------------------------------------------------------- */ +/* Adjust for vertical scale factor if needed */ +/* -------------------------------------------------------------------- */ +static int height_unit (PJ *P, PJ_DIRECTION dir, long n, int dist, double *z) { + int i; + double fac = P->vto_meter; + + if (PJ_FWD==dir) + fac = P->vfr_meter; + + /* Nothing to do? */ + if (fac==1.0) + return 0; + if (nullptr==z) + return 0; + if (P->is_latlong) + return 0; /* done in pj_inv3d() / pj_fwd3d() */ + + for (i = 0; i < n; i++) + if (z[dist*i] != HUGE_VAL ) + z[dist*i] *= fac; + + return 0; +} + + + +/* -------------------------------------------------------------------- */ +/* Transform to ellipsoidal heights if needed */ +/* -------------------------------------------------------------------- */ +static int geometric_to_orthometric (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { + int err; + if (0==P->has_geoid_vgrids) + return 0; + if (z==nullptr) + return PJD_ERR_GEOCENTRIC; + err = pj_apply_vgridshift (P, "sgeoidgrids", + &(P->vgridlist_geoid), + &(P->vgridlist_geoid_count), + dir==PJ_FWD ? 1 : 0, n, dist, x, y, z ); + if (err) + return pj_ctx_get_errno(P->ctx); + return 0; +} + + + +/* -------------------------------------------------------------------- */ +/* Convert datums if needed, and possible. */ +/* -------------------------------------------------------------------- */ +static int datum_transform (PJ *P, PJ *Q, long n, int dist, double *x, double *y, double *z) { + if (0==pj_datum_transform (P, Q, n, dist, x, y, z)) + return 0; + if (P->ctx->last_errno) + return P->ctx->last_errno; + return Q->ctx->last_errno; +} + + + + + +/* -------------------------------------------------------------------- */ +/* If a wrapping center other than 0 is provided, rewrap around */ +/* the suggested center (for latlong coordinate systems only). */ +/* -------------------------------------------------------------------- */ +static int long_wrap (PJ *P, long n, int dist, double *x) { + long i; + + /* Nothing to do? */ + if (P->is_geocent) + return 0; + if (!P->is_long_wrap_set) + return 0; + if (!P->is_latlong) + return 0; + + for (i = 0; i < n; i++ ) { + double val = x[dist*i]; + if (val == HUGE_VAL) + continue; + + /* Get fast in ] -2 PI, 2 PI [ range */ + val = fmod(val, M_TWOPI); + while( val < P->long_wrap_center - M_PI ) + val += M_TWOPI; + while( val > P->long_wrap_center + M_PI ) + val -= M_TWOPI; + x[dist*i] = val; + } + return 0; +} + + + +/************************************************************************/ +/* pj_transform() */ +/* */ +/* Currently this function doesn't recognise if two projections */ +/* are identical (to short circuit reprojection) because it is */ +/* difficult to compare PJ structures (since there are some */ +/* projection specific components). */ +/************************************************************************/ + +int pj_transform( + PJ *src, PJ *dst, + long point_count, int point_offset, + double *x, double *y, double *z +){ + int err; + + src->ctx->last_errno = 0; + dst->ctx->last_errno = 0; + + if( point_offset == 0 ) + point_offset = 1; + + /* Bring input to "normal form": longitude, latitude, ellipsoidal height */ + + err = adjust_axes (src, PJ_INV, point_count, point_offset, x, y, z); + if (err) + return err; + err = geographic_to_cartesian (src, PJ_INV, point_count, point_offset, x, y, z); + if (err) + return err; + err = projected_to_geographic (src, point_count, point_offset, x, y, z); + if (err) + return err; + err = prime_meridian (src, PJ_INV, point_count, point_offset, x); + if (err) + return err; + err = height_unit (src, PJ_INV, point_count, point_offset, z); + if (err) + return err; + err = geometric_to_orthometric (src, PJ_INV, point_count, point_offset, x, y, z); + if (err) + return err; + + /* At the center of the process we do the datum shift (if needed) */ + + err = datum_transform(src, dst, point_count, point_offset, x, y, z ); + if (err) + return err; + + /* Now get out on the other side: Bring "normal form" to output form */ + + err = geometric_to_orthometric (dst, PJ_FWD, point_count, point_offset, x, y, z); + if (err) + return err; + err = height_unit (dst, PJ_FWD, point_count, point_offset, z); + if (err) + return err; + err = prime_meridian (dst, PJ_FWD, point_count, point_offset, x); + if (err) + return err; + err = geographic_to_cartesian (dst, PJ_FWD, point_count, point_offset, x, y, z); + if (err) + return err; + err = geographic_to_projected (dst, point_count, point_offset, x, y, z); + if (err) + return err; + err = long_wrap (dst, point_count, point_offset, x); + if (err) + return err; + err = adjust_axes (dst, PJ_FWD, point_count, point_offset, x, y, z); + if (err) + return err; + + return 0; +} + + + +/************************************************************************/ +/* pj_geodetic_to_geocentric() */ +/************************************************************************/ + +int pj_geodetic_to_geocentric( double a, double es, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + double b; + int i; + GeocentricInfo gi; + int ret_errno = 0; + + if( es == 0.0 ) + b = a; + else + b = a * sqrt(1-es); + + if( pj_Set_Geocentric_Parameters( &gi, a, b ) != 0 ) + { + return PJD_ERR_GEOCENTRIC; + } + + for( i = 0; i < point_count; i++ ) + { + long io = i * point_offset; + + if( x[io] == HUGE_VAL ) + continue; + + if( pj_Convert_Geodetic_To_Geocentric( &gi, y[io], x[io], z[io], + x+io, y+io, z+io ) != 0 ) + { + ret_errno = PJD_ERR_LAT_OR_LON_EXCEED_LIMIT; + x[io] = y[io] = HUGE_VAL; + /* but keep processing points! */ + } + } + + return ret_errno; +} + +/************************************************************************/ +/* pj_geocentric_to_geodetic() */ +/************************************************************************/ + +int pj_geocentric_to_geodetic( double a, double es, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + double b; + int i; + GeocentricInfo gi; + + if( es == 0.0 ) + b = a; + else + b = a * sqrt(1-es); + + if( pj_Set_Geocentric_Parameters( &gi, a, b ) != 0 ) + { + return PJD_ERR_GEOCENTRIC; + } + + for( i = 0; i < point_count; i++ ) + { + long io = i * point_offset; + + if( x[io] == HUGE_VAL ) + continue; + + pj_Convert_Geocentric_To_Geodetic( &gi, x[io], y[io], z[io], + y+io, x+io, z+io ); + } + + return 0; +} + +/************************************************************************/ +/* pj_compare_datums() */ +/* */ +/* Returns TRUE if the two datums are identical, otherwise */ +/* FALSE. */ +/************************************************************************/ + +int pj_compare_datums( PJ *srcdefn, PJ *dstdefn ) + +{ + if( srcdefn->datum_type != dstdefn->datum_type ) + { + return 0; + } + else if( srcdefn->a_orig != dstdefn->a_orig + || ABS(srcdefn->es_orig - dstdefn->es_orig) > 0.000000000050 ) + { + /* the tolerance for es is to ensure that GRS80 and WGS84 are + considered identical */ + return 0; + } + else if( srcdefn->datum_type == PJD_3PARAM ) + { + return (srcdefn->datum_params[0] == dstdefn->datum_params[0] + && srcdefn->datum_params[1] == dstdefn->datum_params[1] + && srcdefn->datum_params[2] == dstdefn->datum_params[2]); + } + else if( srcdefn->datum_type == PJD_7PARAM ) + { + return (srcdefn->datum_params[0] == dstdefn->datum_params[0] + && srcdefn->datum_params[1] == dstdefn->datum_params[1] + && srcdefn->datum_params[2] == dstdefn->datum_params[2] + && srcdefn->datum_params[3] == dstdefn->datum_params[3] + && srcdefn->datum_params[4] == dstdefn->datum_params[4] + && srcdefn->datum_params[5] == dstdefn->datum_params[5] + && srcdefn->datum_params[6] == dstdefn->datum_params[6]); + } + else if( srcdefn->datum_type == PJD_GRIDSHIFT ) + { + const char* srcnadgrids = + pj_param(srcdefn->ctx, srcdefn->params,"snadgrids").s; + const char* dstnadgrids = + pj_param(dstdefn->ctx, dstdefn->params,"snadgrids").s; + return srcnadgrids != nullptr && dstnadgrids != nullptr && + strcmp( srcnadgrids, dstnadgrids ) == 0; + } + else + return 1; +} + +/************************************************************************/ +/* pj_geocentic_to_wgs84() */ +/************************************************************************/ + +static +int pj_geocentric_to_wgs84( PJ *defn, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + int i; + + if( defn->datum_type == PJD_3PARAM ) + { + for( i = 0; i < point_count; i++ ) + { + long io = i * point_offset; + + if( x[io] == HUGE_VAL ) + continue; + + x[io] = x[io] + Dx_BF; + y[io] = y[io] + Dy_BF; + z[io] = z[io] + Dz_BF; + } + } + else if( defn->datum_type == PJD_7PARAM ) + { + for( i = 0; i < point_count; i++ ) + { + long io = i * point_offset; + double x_out, y_out, z_out; + + if( x[io] == HUGE_VAL ) + continue; + + x_out = M_BF*( x[io] - Rz_BF*y[io] + Ry_BF*z[io]) + Dx_BF; + y_out = M_BF*( Rz_BF*x[io] + y[io] - Rx_BF*z[io]) + Dy_BF; + z_out = M_BF*(-Ry_BF*x[io] + Rx_BF*y[io] + z[io]) + Dz_BF; + + x[io] = x_out; + y[io] = y_out; + z[io] = z_out; + } + } + + return 0; +} + +/************************************************************************/ +/* pj_geocentic_from_wgs84() */ +/************************************************************************/ + +static +int pj_geocentric_from_wgs84( PJ *defn, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + int i; + + if( defn->datum_type == PJD_3PARAM ) + { + for( i = 0; i < point_count; i++ ) + { + long io = i * point_offset; + + if( x[io] == HUGE_VAL ) + continue; + + x[io] = x[io] - Dx_BF; + y[io] = y[io] - Dy_BF; + z[io] = z[io] - Dz_BF; + } + } + else if( defn->datum_type == PJD_7PARAM ) + { + for( i = 0; i < point_count; i++ ) + { + long io = i * point_offset; + double x_tmp, y_tmp, z_tmp; + + if( x[io] == HUGE_VAL ) + continue; + + x_tmp = (x[io] - Dx_BF) / M_BF; + y_tmp = (y[io] - Dy_BF) / M_BF; + z_tmp = (z[io] - Dz_BF) / M_BF; + + x[io] = x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp; + y[io] = -Rz_BF*x_tmp + y_tmp + Rx_BF*z_tmp; + z[io] = Ry_BF*x_tmp - Rx_BF*y_tmp + z_tmp; + } + } + + return 0; +} + +/************************************************************************/ +/* pj_datum_transform() */ +/* */ +/* The input should be long/lat/z coordinates in radians in the */ +/* source datum, and the output should be long/lat/z */ +/* coordinates in radians in the destination datum. */ +/************************************************************************/ + +int pj_datum_transform( PJ *src, PJ *dst, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + double src_a, src_es, dst_a, dst_es; + int z_is_temp = FALSE; + +/* -------------------------------------------------------------------- */ +/* We cannot do any meaningful datum transformation if either */ +/* the source or destination are of an unknown datum type */ +/* (ie. only a +ellps declaration, no +datum). This is new */ +/* behavior for PROJ 4.6.0. */ +/* -------------------------------------------------------------------- */ + if( src->datum_type == PJD_UNKNOWN + || dst->datum_type == PJD_UNKNOWN ) + return 0; + +/* -------------------------------------------------------------------- */ +/* Short cut if the datums are identical. */ +/* -------------------------------------------------------------------- */ + if( pj_compare_datums( src, dst ) ) + return 0; + + src_a = src->a_orig; + src_es = src->es_orig; + + dst_a = dst->a_orig; + dst_es = dst->es_orig; + +/* -------------------------------------------------------------------- */ +/* Create a temporary Z array if one is not provided. */ +/* -------------------------------------------------------------------- */ + if( z == nullptr ) + { + size_t bytes = sizeof(double) * point_count * point_offset; + z = (double *) pj_malloc(bytes); + memset( z, 0, bytes ); + z_is_temp = TRUE; + } + +#define CHECK_RETURN(defn) {if( defn->ctx->last_errno != 0 && (defn->ctx->last_errno > 0 || get_transient_error_value(-defn->ctx->last_errno) == 0) ) { if( z_is_temp ) pj_dalloc(z); return defn->ctx->last_errno; }} + +/* -------------------------------------------------------------------- */ +/* If this datum requires grid shifts, then apply it to geodetic */ +/* coordinates. */ +/* -------------------------------------------------------------------- */ + if( src->datum_type == PJD_GRIDSHIFT ) + { + pj_apply_gridshift_2( src, 0, point_count, point_offset, x, y, z ); + CHECK_RETURN(src); + + src_a = SRS_WGS84_SEMIMAJOR; + src_es = SRS_WGS84_ESQUARED; + } + + if( dst->datum_type == PJD_GRIDSHIFT ) + { + dst_a = SRS_WGS84_SEMIMAJOR; + dst_es = SRS_WGS84_ESQUARED; + } + +/* ==================================================================== */ +/* Do we need to go through geocentric coordinates? */ +/* ==================================================================== */ + if( src_es != dst_es || src_a != dst_a + || src->datum_type == PJD_3PARAM + || src->datum_type == PJD_7PARAM + || dst->datum_type == PJD_3PARAM + || dst->datum_type == PJD_7PARAM) + { +/* -------------------------------------------------------------------- */ +/* Convert to geocentric coordinates. */ +/* -------------------------------------------------------------------- */ + src->ctx->last_errno = + pj_geodetic_to_geocentric( src_a, src_es, + point_count, point_offset, x, y, z ); + CHECK_RETURN(src); + +/* -------------------------------------------------------------------- */ +/* Convert between datums. */ +/* -------------------------------------------------------------------- */ + if( src->datum_type == PJD_3PARAM + || src->datum_type == PJD_7PARAM ) + { + pj_geocentric_to_wgs84( src, point_count, point_offset,x,y,z); + CHECK_RETURN(src); + } + + if( dst->datum_type == PJD_3PARAM + || dst->datum_type == PJD_7PARAM ) + { + pj_geocentric_from_wgs84( dst, point_count,point_offset,x,y,z); + CHECK_RETURN(dst); + } + +/* -------------------------------------------------------------------- */ +/* Convert back to geodetic coordinates. */ +/* -------------------------------------------------------------------- */ + dst->ctx->last_errno = + pj_geocentric_to_geodetic( dst_a, dst_es, + point_count, point_offset, x, y, z ); + CHECK_RETURN(dst); + } + +/* -------------------------------------------------------------------- */ +/* Apply grid shift to destination if required. */ +/* -------------------------------------------------------------------- */ + if( dst->datum_type == PJD_GRIDSHIFT ) + { + pj_apply_gridshift_2( dst, 1, point_count, point_offset, x, y, z ); + CHECK_RETURN(dst); + } + + if( z_is_temp ) + pj_dalloc( z ); + + return 0; +} + +/************************************************************************/ +/* adjust_axis() */ +/* */ +/* Normalize or de-normalized the x/y/z axes. The normal form */ +/* is "enu" (easting, northing, up). */ +/************************************************************************/ +static int adjust_axis( projCtx ctx, + const char *axis, int denormalize_flag, + long point_count, int point_offset, + double *x, double *y, double *z ) + +{ + double x_in, y_in, z_in = 0.0; + int i, i_axis; + + if( !denormalize_flag ) + { + for( i = 0; i < point_count; i++ ) + { + x_in = x[point_offset*i]; + y_in = y[point_offset*i]; + if( z ) + z_in = z[point_offset*i]; + + for( i_axis = 0; i_axis < 3; i_axis++ ) + { + double value; + + if( i_axis == 0 ) + value = x_in; + else if( i_axis == 1 ) + value = y_in; + else + value = z_in; + + switch( axis[i_axis] ) + { + case 'e': + x[point_offset*i] = value; + break; + case 'w': + x[point_offset*i] = -value; + break; + case 'n': + y[point_offset*i] = value; + break; + case 's': + y[point_offset*i] = -value; + break; + case 'u': + if( z ) + z[point_offset*i] = value; + break; + case 'd': + if( z ) + z[point_offset*i] = -value; + break; + default: + pj_ctx_set_errno( ctx, PJD_ERR_AXIS ); + return PJD_ERR_AXIS; + } + } /* i_axis */ + } /* i (point) */ + } + + else /* denormalize */ + { + for( i = 0; i < point_count; i++ ) + { + x_in = x[point_offset*i]; + y_in = y[point_offset*i]; + if( z ) + z_in = z[point_offset*i]; + + for( i_axis = 0; i_axis < 3; i_axis++ ) + { + double *target; + + if( i_axis == 2 && z == nullptr ) + continue; + + if( i_axis == 0 ) + target = x; + else if( i_axis == 1 ) + target = y; + else + target = z; + + switch( axis[i_axis] ) + { + case 'e': + target[point_offset*i] = x_in; break; + case 'w': + target[point_offset*i] = -x_in; break; + case 'n': + target[point_offset*i] = y_in; break; + case 's': + target[point_offset*i] = -y_in; break; + case 'u': + target[point_offset*i] = z_in; break; + case 'd': + target[point_offset*i] = -z_in; break; + default: + pj_ctx_set_errno( ctx, PJD_ERR_AXIS ); + return PJD_ERR_AXIS; + } + } /* i_axis */ + } /* i (point) */ + } + + return 0; +} diff --git a/src/transformations/PJ_affine.cpp b/src/transformations/PJ_affine.cpp deleted file mode 100644 index e2b668d3..00000000 --- a/src/transformations/PJ_affine.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/************************************************************************ -* Copyright (c) 2018, Even Rouault -* -* 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_internal.h" -#include "proj.h" -#include "projects.h" - -PROJ_HEAD(affine, "Affine transformation"); -PROJ_HEAD(geogoffset, "Geographic Offset"); - -namespace { // anonymous namespace -struct pj_affine_coeffs { - double s11; - double s12; - double s13; - double s21; - double s22; - double s23; - double s31; - double s32; - double s33; - double tscale; -}; -} // anonymous namespace - -namespace { // anonymous namespace -struct pj_opaque_affine { - double xoff; - double yoff; - double zoff; - double toff; - struct pj_affine_coeffs forward; - struct pj_affine_coeffs reverse; -}; -} // anonymous namespace - - -static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { - PJ_COORD newObs; - const struct pj_opaque_affine *Q = (const struct pj_opaque_affine *) P->opaque; - const struct pj_affine_coeffs *C = &(Q->forward); - newObs.xyzt.x = Q->xoff + C->s11 * obs.xyzt.x + C->s12 * obs.xyzt.y + C->s13 * obs.xyzt.z; - newObs.xyzt.y = Q->yoff + C->s21 * obs.xyzt.x + C->s22 * obs.xyzt.y + C->s23 * obs.xyzt.z; - newObs.xyzt.z = Q->zoff + C->s31 * obs.xyzt.x + C->s32 * obs.xyzt.y + C->s33 * obs.xyzt.z; - newObs.xyzt.t = Q->toff + C->tscale * obs.xyzt.t; - return newObs; -} - -static XYZ forward_3d(LPZ lpz, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - point.lpz = lpz; - return forward_4d(point, P).xyz; -} - - -static XY forward_2d(LP lp, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - point.lp = lp; - return forward_4d(point, P).xy; -} - - -static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { - PJ_COORD newObs; - const struct pj_opaque_affine *Q = (const struct pj_opaque_affine *) P->opaque; - const struct pj_affine_coeffs *C = &(Q->reverse); - obs.xyzt.x -= Q->xoff; - obs.xyzt.y -= Q->yoff; - obs.xyzt.z -= Q->zoff; - newObs.xyzt.x = C->s11 * obs.xyzt.x + C->s12 * obs.xyzt.y + C->s13 * obs.xyzt.z; - newObs.xyzt.y = C->s21 * obs.xyzt.x + C->s22 * obs.xyzt.y + C->s23 * obs.xyzt.z; - newObs.xyzt.z = C->s31 * obs.xyzt.x + C->s32 * obs.xyzt.y + C->s33 * obs.xyzt.z; - newObs.xyzt.t = C->tscale * (obs.xyzt.t - Q->toff); - return newObs; -} - -static LPZ reverse_3d(XYZ xyz, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - point.xyz = xyz; - return reverse_4d(point, P).lpz; -} - -static LP reverse_2d(XY xy, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - point.xy = xy; - return reverse_4d(point, P).lp; -} - -static struct pj_opaque_affine * initQ() { - struct pj_opaque_affine *Q = static_cast(pj_calloc(1, sizeof(struct pj_opaque_affine))); - if (nullptr==Q) - return nullptr; - - /* default values */ - Q->forward.s11 = 1.0; - Q->forward.s22 = 1.0; - Q->forward.s33 = 1.0; - Q->forward.tscale = 1.0; - - Q->reverse.s11 = 1.0; - Q->reverse.s22 = 1.0; - Q->reverse.s33 = 1.0; - Q->reverse.tscale = 1.0; - - return Q; -} - -static void computeReverseParameters(PJ* P) -{ - struct pj_opaque_affine *Q = (struct pj_opaque_affine *) P->opaque; - - /* cf https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3_%C3%97_3_matrices */ - const double a = Q->forward.s11; - const double b = Q->forward.s12; - const double c = Q->forward.s13; - const double d = Q->forward.s21; - const double e = Q->forward.s22; - const double f = Q->forward.s23; - const double g = Q->forward.s31; - const double h = Q->forward.s32; - const double i = Q->forward.s33; - const double A = e * i - f * h; - const double B = -(d * i - f * g); - const double C = (d * h - e * g); - const double D = -(b * i - c * h); - const double E = (a * i - c * g); - const double F = -(a * h - b * g); - const double G = b * f - c * e; - const double H = -(a * f - c * d); - const double I = a * e - b * d; - const double det = a * A + b * B + c * C; - if( det == 0.0 || Q->forward.tscale == 0.0 ) { - if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_DEBUG) { - proj_log_debug(P, "Affine: matrix non invertible"); - } - P->inv4d = nullptr; - P->inv3d = nullptr; - P->inv = nullptr; - } else { - Q->reverse.s11 = A / det; - Q->reverse.s12 = D / det; - Q->reverse.s13 = G / det; - Q->reverse.s21 = B / det; - Q->reverse.s22 = E / det; - Q->reverse.s23 = H / det; - Q->reverse.s31 = C / det; - Q->reverse.s32 = F / det; - Q->reverse.s33 = I / det; - Q->reverse.tscale = 1.0 / Q->forward.tscale; - } -} - -PJ *TRANSFORMATION(affine,0 /* no need for ellipsoid */) { - struct pj_opaque_affine *Q = initQ(); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = (void *) Q; - - P->fwd4d = forward_4d; - P->inv4d = reverse_4d; - P->fwd3d = forward_3d; - P->inv3d = reverse_3d; - P->fwd = forward_2d; - P->inv = reverse_2d; - - P->left = PJ_IO_UNITS_WHATEVER; - P->right = PJ_IO_UNITS_WHATEVER; - - /* read args */ - Q->xoff = pj_param(P->ctx, P->params, "dxoff").f; - Q->yoff = pj_param(P->ctx, P->params, "dyoff").f; - Q->zoff = pj_param(P->ctx, P->params, "dzoff").f; - Q->toff = pj_param(P->ctx, P->params, "dtoff").f; - - if(pj_param (P->ctx, P->params, "ts11").i) { - Q->forward.s11 = pj_param(P->ctx, P->params, "ds11").f; - } - Q->forward.s12 = pj_param(P->ctx, P->params, "ds12").f; - Q->forward.s13 = pj_param(P->ctx, P->params, "ds13").f; - Q->forward.s21 = pj_param(P->ctx, P->params, "ds21").f; - if(pj_param (P->ctx, P->params, "ts22").i) { - Q->forward.s22 = pj_param(P->ctx, P->params, "ds22").f; - } - Q->forward.s23 = pj_param(P->ctx, P->params, "ds23").f; - Q->forward.s31 = pj_param(P->ctx, P->params, "ds31").f; - Q->forward.s32 = pj_param(P->ctx, P->params, "ds32").f; - if(pj_param (P->ctx, P->params, "ts33").i) { - Q->forward.s33 = pj_param(P->ctx, P->params, "ds33").f; - } - if(pj_param (P->ctx, P->params, "ttscale").i) { - Q->forward.tscale = pj_param(P->ctx, P->params, "dtscale").f; - } - - computeReverseParameters(P); - - return P; -} - - -/* Arcsecond to radians */ -#define ARCSEC_TO_RAD (DEG_TO_RAD / 3600.0) - - -PJ *TRANSFORMATION(geogoffset,0 /* no need for ellipsoid */) { - struct pj_opaque_affine *Q = initQ(); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = (void *) Q; - - P->fwd4d = forward_4d; - P->inv4d = reverse_4d; - P->fwd3d = forward_3d; - P->inv3d = reverse_3d; - P->fwd = forward_2d; - P->inv = reverse_2d; - - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_ANGULAR; - - /* read args */ - Q->xoff = pj_param(P->ctx, P->params, "ddlon").f * ARCSEC_TO_RAD; - Q->yoff = pj_param(P->ctx, P->params, "ddlat").f * ARCSEC_TO_RAD; - Q->zoff = pj_param(P->ctx, P->params, "ddh").f; - - return P; -} diff --git a/src/transformations/PJ_deformation.cpp b/src/transformations/PJ_deformation.cpp deleted file mode 100644 index 6c30f21c..00000000 --- a/src/transformations/PJ_deformation.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/*********************************************************************** - - Kinematic datum shifting utilizing a deformation model - - Kristian Evers, 2017-10-29 - -************************************************************************ - -Perform datum shifts by means of a deformation/velocity model. - - X_out = X_in + (T_ct - T_obs)*DX - Y_out = Y_in + (T_ct - T_obs)*DY - Z_out = Z_in + (T_ct - T_obs)*DZ - - -The deformation operation takes cartesian coordinates as input and -returns cartesian coordinates as well. - -Corrections in the gridded model are in east, north, up (ENU) space. -Hence the input coordinates needs to be converted to ENU-space when -searching for corrections in the grid. The corrections are then converted -to cartesian XYZ-space and applied to the input coordinates (also in -cartesian space). - -A full deformation model is described by two grids, one for the horizontal -components and one for the vertical component. The horizontal grid is -stored in CTable/CTable2 and the vertical grid is stored in the GTX -format. The NTv2 format should not be used for this purpose since grid- -values are scaled upon reading. Both grids are expected to contain -grid-values in units of mm/year in ENU-space. - -************************************************************************ -* Copyright (c) 2017, 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. -* -***********************************************************************/ -#define PJ_LIB__ -#include -#include "proj.h" -#include "proj_internal.h" -#include "proj_math.h" -#include "projects.h" - -PROJ_HEAD(deformation, "Kinematic grid shift"); - -#define TOL 1e-8 -#define MAX_ITERATIONS 10 - -namespace { // anonymous namespace -struct pj_opaque { - double t_obs; - double t_epoch; - PJ *cart; -}; -} // anonymous namespace - -/********************************************************************************/ -static XYZ get_grid_shift(PJ* P, XYZ cartesian) { -/******************************************************************************** - Read correction values from grid. The cartesian input coordinates are - converted to geodetic coordinates in order look up the correction values - in the grid. Once the grid corrections are read we need to convert them - from ENU-space to cartesian XYZ-space. ENU -> XYZ formula described in: - - Nørbech, T., et al, 2003(?), "Transformation from a Common Nordic Reference - Frame to ETRS89 in Denmark, Finland, Norway, and Sweden – status report" - -********************************************************************************/ - PJ_COORD geodetic, shift, temp; - double sp, cp, sl, cl; - int previous_errno = proj_errno_reset(P); - - /* cartesian to geodetic */ - geodetic.lpz = pj_inv3d(cartesian, static_cast(P->opaque)->cart); - - /* look up correction values in grids */ - shift.lp = proj_hgrid_value(P, geodetic.lp); - shift.enu.u = proj_vgrid_value(P, geodetic.lp); - - if (proj_errno(P) == PJD_ERR_GRID_AREA) - proj_log_debug(P, "deformation: coordinate (%.3f, %.3f) outside deformation model", - proj_todeg(geodetic.lp.lam), proj_todeg(geodetic.lp.phi)); - - /* grid values are stored as mm/yr, we need m/yr */ - shift.xyz.x /= 1000; - shift.xyz.y /= 1000; - shift.xyz.z /= 1000; - - /* pre-calc cosines and sines */ - sp = sin(geodetic.lp.phi); - cp = cos(geodetic.lp.phi); - sl = sin(geodetic.lp.lam); - cl = cos(geodetic.lp.lam); - - /* ENU -> XYZ */ - temp.xyz.x = -sp*cl*shift.enu.n - sl*shift.enu.e + cp*cl*shift.enu.u; - temp.xyz.y = -sp*sl*shift.enu.n + cl*shift.enu.e + cp*sl*shift.enu.u; - temp.xyz.z = cp*shift.enu.n + sp*shift.enu.u; - - shift.xyz = temp.xyz; - - proj_errno_restore(P, previous_errno); - - return shift.xyz; -} - -/********************************************************************************/ -static XYZ reverse_shift(PJ *P, XYZ input, double dt) { -/******************************************************************************** - Iteratively determine the reverse grid shift correction values. -*********************************************************************************/ - XYZ out, delta, dif; - double z0; - int i = MAX_ITERATIONS; - - delta = get_grid_shift(P, input); - - /* Store the origial z shift for later application */ - z0 = delta.z; - - /* When iterating to find the best horizontal coordinate we also carry */ - /* along the z-component, since we need it for the cartesian -> geodetic */ - /* conversion. The z-component adjustment is overwritten with z0 after */ - /* the loop has finished. */ - out.x = input.x - dt*delta.x; - out.y = input.y - dt*delta.y; - out.z = input.z + dt*delta.z; - - do { - delta = get_grid_shift(P, out); - - if (delta.x == HUGE_VAL) - break; - - dif.x = out.x + dt*delta.x - input.x; - dif.y = out.y + dt*delta.y - input.y; - dif.z = out.z - dt*delta.z - input.z; - out.x += dif.x; - out.y += dif.y; - out.z += dif.z; - - } while ( --i && hypot(dif.x, dif.y) > TOL ); - - out.z = input.z - dt*z0; - - return out; -} - -static XYZ forward_3d(LPZ lpz, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - PJ_COORD out, in; - XYZ shift; - double dt = 0.0; - in.lpz = lpz; - out = in; - - if (Q->t_obs != HUGE_VAL) { - dt = Q->t_epoch - Q->t_obs; - } else { - out = proj_coord_error(); /* in the 3D case +t_obs must be specified */ - proj_log_debug(P, "deformation: +t_obs must be specified"); - return out.xyz; - } - - shift = get_grid_shift(P, in.xyz); - - out.xyz.x += dt * shift.x; - out.xyz.y += dt * shift.y; - out.xyz.z += dt * shift.z; - - return out.xyz; -} - - -static PJ_COORD forward_4d(PJ_COORD in, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - double dt; - XYZ shift; - PJ_COORD out = in; - - if (Q->t_obs != HUGE_VAL) { - dt = Q->t_epoch - Q->t_obs; - } else { - dt = Q->t_epoch - in.xyzt.t; - } - - shift = get_grid_shift(P, in.xyz); - - out.xyzt.x += dt*shift.x; - out.xyzt.y += dt*shift.y; - out.xyzt.z += dt*shift.z; - - - return out; -} - - -static LPZ reverse_3d(XYZ in, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - PJ_COORD out; - double dt = 0.0; - out.xyz = in; - - if (Q->t_obs != HUGE_VAL) { - dt = Q->t_epoch - Q->t_obs; - } else { - out = proj_coord_error(); /* in the 3D case +t_obs must be specified */ - proj_log_debug(P, "deformation: +t_obs must be specified"); - return out.lpz; - } - - out.xyz = reverse_shift(P, in, dt); - - return out.lpz; -} - -static PJ_COORD reverse_4d(PJ_COORD in, PJ *P) { - struct pj_opaque *Q = (struct pj_opaque *) P->opaque; - PJ_COORD out = in; - double dt; - - - if (Q->t_obs != HUGE_VAL) { - dt = Q->t_epoch - Q->t_obs; - } else { - dt = Q->t_epoch - in.xyzt.t; - } - - out.xyz = reverse_shift(P, in.xyz, dt); - return out; -} - -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)->cart) - static_cast(P->opaque)->cart->destructor (static_cast(P->opaque)->cart, errlev); - - return pj_default_destructor(P, errlev); -} - - -PJ *TRANSFORMATION(deformation,1) { - int has_xy_grids = 0; - int has_z_grids = 0; - struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); - if (nullptr==Q) - return destructor(P, ENOMEM); - P->opaque = (void *) Q; - - Q->cart = proj_create(P->ctx, "+proj=cart"); - if (Q->cart == nullptr) - return destructor(P, ENOMEM); - - /* inherit ellipsoid definition from P to Q->cart */ - pj_inherit_ellipsoid_def (P, Q->cart); - - has_xy_grids = pj_param(P->ctx, P->params, "txy_grids").i; - has_z_grids = pj_param(P->ctx, P->params, "tz_grids").i; - - /* Build gridlists. Both horizontal and vertical grids are mandatory. */ - if (!has_xy_grids || !has_z_grids) { - proj_log_error(P, "deformation: Both +xy_grids and +z_grids should be specified."); - return destructor(P, PJD_ERR_NO_ARGS ); - } - - proj_hgrid_init(P, "xy_grids"); - if (proj_errno(P)) { - proj_log_error(P, "deformation: could not find requested xy_grid(s)."); - return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID); - } - - proj_vgrid_init(P, "z_grids"); - if (proj_errno(P)) { - proj_log_error(P, "deformation: could not find requested z_grid(s)."); - return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID); - } - - Q->t_obs = HUGE_VAL; - if (pj_param(P->ctx, P->params, "tt_obs").i) { - Q->t_obs = pj_param(P->ctx, P->params, "dt_obs").f; - } - - if (pj_param(P->ctx, P->params, "tt_epoch").i) { - Q->t_epoch = pj_param(P->ctx, P->params, "dt_epoch").f; - } else { - proj_log_error(P, "deformation: +t_epoch parameter missing."); - return destructor(P, PJD_ERR_MISSING_ARGS); - } - - P->fwd4d = forward_4d; - P->inv4d = reverse_4d; - P->fwd3d = forward_3d; - P->inv3d = reverse_3d; - P->fwd = nullptr; - P->inv = nullptr; - - P->left = PJ_IO_UNITS_CARTESIAN; - P->right = PJ_IO_UNITS_CARTESIAN; - P->destructor = destructor; - - return P; -} - diff --git a/src/transformations/PJ_helmert.cpp b/src/transformations/PJ_helmert.cpp deleted file mode 100644 index 4a3abf4e..00000000 --- a/src/transformations/PJ_helmert.cpp +++ /dev/null @@ -1,755 +0,0 @@ -/*********************************************************************** - - 3-, 4-and 7-parameter shifts, and their 6-, 8- - and 14-parameter kinematic counterparts. - - Thomas Knudsen, 2016-05-24 - -************************************************************************ - - Implements 3(6)-, 4(8) and 7(14)-parameter Helmert transformations for - 3D data. - - Also incorporates Molodensky-Badekas variant of 7-parameter Helmert - transformation, where the rotation is not applied regarding the centre - of the spheroid, but given a reference point. - - Primarily useful for implementation of datum shifts in transformation - pipelines. - -************************************************************************ - -Thomas Knudsen, thokn@sdfe.dk, 2016-05-24/06-05 -Kristian Evers, kreve@sdfe.dk, 2017-05-01 -Even Rouault, even.roault@spatialys.com -Last update: 2018-10-26 - -************************************************************************ -* Copyright (c) 2016, Thomas Knudsen / SDFE -* -* 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_internal.h" -#include "projects.h" -#include "geocent.h" - -PROJ_HEAD(helmert, "3(6)-, 4(8)- and 7(14)-parameter Helmert shift"); -PROJ_HEAD(molobadekas, "Molodensky-Badekas transformation"); - -static XYZ helmert_forward_3d (LPZ lpz, PJ *P); -static LPZ helmert_reverse_3d (XYZ xyz, PJ *P); - - - -/***********************************************************************/ -namespace { // anonymous namespace -struct pj_opaque_helmert { -/************************************************************************ - Projection specific elements for the "helmert" PJ object -************************************************************************/ - XYZ xyz; - XYZ xyz_0; - XYZ dxyz; - XYZ refp; - PJ_OPK opk; - PJ_OPK opk_0; - PJ_OPK dopk; - double scale; - double scale_0; - double dscale; - double theta; - double theta_0; - double dtheta; - double R[3][3]; - double t_epoch, t_obs; - int no_rotation, exact, fourparam; - int is_position_vector; /* 1 = position_vector, 0 = coordinate_frame */ -}; -} // anonymous namespace - - -/* Make the maths of the rotation operations somewhat more readable and textbook like */ -#define R00 (Q->R[0][0]) -#define R01 (Q->R[0][1]) -#define R02 (Q->R[0][2]) - -#define R10 (Q->R[1][0]) -#define R11 (Q->R[1][1]) -#define R12 (Q->R[1][2]) - -#define R20 (Q->R[2][0]) -#define R21 (Q->R[2][1]) -#define R22 (Q->R[2][2]) - -/**************************************************************************/ -static void update_parameters(PJ *P) { -/*************************************************************************** - - Update transformation parameters. - --------------------------------- - - The 14-parameter Helmert transformation is at it's core the same as the - 7-parameter transformation, since the transformation parameters are - projected forward or backwards in time via the rate of changes of the - parameters. The transformation parameters are calculated for a specific - epoch before the actual Helmert transformation is carried out. - - The transformation parameters are updated with the following equation [0]: - - . - P(t) = P(EPOCH) + P * (t - EPOCH) - - . - where EPOCH is the epoch indicated in the above table and P is the rate - of that parameter. - - [0] http://itrf.ign.fr/doc_ITRF/Transfo-ITRF2008_ITRFs.txt - -*******************************************************************************/ - - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; - double dt = Q->t_obs - Q->t_epoch; - - Q->xyz.x = Q->xyz_0.x + Q->dxyz.x * dt; - Q->xyz.y = Q->xyz_0.y + Q->dxyz.y * dt; - Q->xyz.z = Q->xyz_0.z + Q->dxyz.z * dt; - - Q->opk.o = Q->opk_0.o + Q->dopk.o * dt; - Q->opk.p = Q->opk_0.p + Q->dopk.p * dt; - Q->opk.k = Q->opk_0.k + Q->dopk.k * dt; - - Q->scale = Q->scale_0 + Q->dscale * dt; - - Q->theta = Q->theta_0 + Q->dtheta * dt; - - /* debugging output */ - if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_TRACE) { - proj_log_trace(P, "Transformation parameters for observation " - "t_obs=%g (t_epoch=%g):", Q->t_obs, Q->t_epoch); - proj_log_trace(P, "x: %g", Q->xyz.x); - proj_log_trace(P, "y: %g", Q->xyz.y); - proj_log_trace(P, "z: %g", Q->xyz.z); - proj_log_trace(P, "s: %g", Q->scale*1e-6); - proj_log_trace(P, "rx: %g", Q->opk.o); - proj_log_trace(P, "ry: %g", Q->opk.p); - proj_log_trace(P, "rz: %g", Q->opk.k); - proj_log_trace(P, "theta: %g", Q->theta); - } -} - -/**************************************************************************/ -static void build_rot_matrix(PJ *P) { -/*************************************************************************** - - Build rotation matrix. - ---------------------- - - Here we rename rotation indices from omega, phi, kappa (opk), to - fi (i.e. phi), theta, psi (ftp), in order to reduce the mental agility - needed to implement the expression for the rotation matrix derived over - at https://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions - The relevant section is Euler angles ( z-’-x" intrinsic) -> Rotation matrix - - By default small angle approximations are used: - The matrix elements are approximated by expanding the trigonometric - functions to linear order (i.e. cos(x) = 1, sin(x) = x), and discarding - products of second order. - - This was a useful hack when calculating by hand was the only option, - but in general, today, should be avoided because: - - 1. It does not save much computation time, as the rotation matrix - is built only once and probably used many times (except when - transforming spatio-temporal coordinates). - - 2. The error induced may be too large for ultra high accuracy - applications: the Earth is huge and the linear error is - approximately the angular error multiplied by the Earth radius. - - However, in many cases the approximation is necessary, since it has - been used historically: Rotation angles from older published datum - shifts may actually be a least squares fit to the linearized rotation - approximation, hence not being strictly valid for deriving the exact - rotation matrix. In fact, most publicly available transformation - parameters are based on the approximate Helmert transform, which is why - we use that as the default setting, even though it is more correct to - use the exact form of the equations. - - So in order to fit historically derived coordinates, the access to - the approximate rotation matrix is necessary - at least in principle. - - Also, when using any published datum transformation information, one - should always check which convention (exact or approximate rotation - matrix) is expected, and whether the induced error for selecting - the opposite convention is acceptable (which it often is). - - - Sign conventions - ---------------- - - Take care: Two different sign conventions exist for the rotation terms. - - Conceptually they relate to whether we rotate the coordinate system - or the "position vector" (the vector going from the coordinate system - origin to the point being transformed, i.e. the point coordinates - interpreted as vector coordinates). - - Switching between the "position vector" and "coordinate system" - conventions is simply a matter of switching the sign of the rotation - angles, which algebraically also translates into a transposition of - the rotation matrix. - - Hence, as geodetic constants should preferably be referred to exactly - as published, the "convention" option provides the ability to switch - between the conventions. - -***************************************************************************/ - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; - - double f, t, p; /* phi/fi , theta, psi */ - double cf, ct, cp; /* cos (fi, theta, psi) */ - double sf, st, sp; /* sin (fi, theta, psi) */ - - /* rename (omega, phi, kappa) to (fi, theta, psi) */ - f = Q->opk.o; - t = Q->opk.p; - p = Q->opk.k; - - /* Those equations are given assuming coordinate frame convention. */ - /* For the position vector convention, we transpose the matrix just after. */ - if (Q->exact) { - cf = cos(f); - sf = sin(f); - ct = cos(t); - st = sin(t); - cp = cos(p); - sp = sin(p); - - - R00 = ct*cp; - R01 = cf*sp + sf*st*cp; - R02 = sf*sp - cf*st*cp; - - R10 = -ct*sp; - R11 = cf*cp - sf*st*sp; - R12 = sf*cp + cf*st*sp; - - R20 = st; - R21 = -sf*ct; - R22 = cf*ct; - } else{ - R00 = 1; - R01 = p; - R02 = -t; - - R10 = -p; - R11 = 1; - R12 = f; - - R20 = t; - R21 = -f; - R22 = 1; - } - - - /* - For comparison: Description from Engsager/Poder implementation - in set_dtm_1.c (trlib) - - DATUM SHIFT: - TO = scale * ROTZ * ROTY * ROTX * FROM + TRANSLA - - ( cz sz 0) (cy 0 -sy) (1 0 0) - ROTZ=(-sz cz 0), ROTY=(0 1 0), ROTX=(0 cx sx) - ( 0 0 1) (sy 0 cy) (0 -sx cx) - - trp->r11 = cos_ry*cos_rz; - trp->r12 = cos_rx*sin_rz + sin_rx*sin_ry*cos_rz; - trp->r13 = sin_rx*sin_rz - cos_rx*sin_ry*cos_rz; - - trp->r21 = -cos_ry*sin_rz; - trp->r22 = cos_rx*cos_rz - sin_rx*sin_ry*sin_rz; - trp->r23 = sin_rx*cos_rz + cos_rx*sin_ry*sin_rz; - - trp->r31 = sin_ry; - trp->r32 = -sin_rx*cos_ry; - trp->r33 = cos_rx*cos_ry; - - trp->scale = 1.0 + scale; - */ - - - if (Q->is_position_vector) { - double r; - r = R01; R01 = R10; R10 = r; - r = R02; R02 = R20; R20 = r; - r = R12; R12 = R21; R21 = r; - } - - /* some debugging output */ - if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_TRACE) { - proj_log_trace(P, "Rotation Matrix:"); - proj_log_trace(P, " | % 6.6g % 6.6g % 6.6g |", R00, R01, R02); - proj_log_trace(P, " | % 6.6g % 6.6g % 6.6g |", R10, R11, R12); - proj_log_trace(P, " | % 6.6g % 6.6g % 6.6g |", R20, R21, R22); - } -} - - - - -/***********************************************************************/ -static XY helmert_forward (LP lp, PJ *P) { -/***********************************************************************/ - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - double x, y, cr, sr; - point.lp = lp; - - cr = cos(Q->theta) * Q->scale; - sr = sin(Q->theta) * Q->scale; - x = point.xy.x; - y = point.xy.y; - - point.xy.x = cr*x + sr*y + Q->xyz_0.x; - point.xy.y = -sr*x + cr*y + Q->xyz_0.y; - - return point.xy; -} - - -/***********************************************************************/ -static LP helmert_reverse (XY xy, PJ *P) { -/***********************************************************************/ - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - double x, y, sr, cr; - point.xy = xy; - - cr = cos(Q->theta) / Q->scale; - sr = sin(Q->theta) / Q->scale; - x = point.xy.x - Q->xyz_0.x; - y = point.xy.y - Q->xyz_0.y; - - point.xy.x = x*cr - y*sr; - point.xy.y = x*sr + y*cr; - - return point.lp; -} - - -/***********************************************************************/ -static XYZ helmert_forward_3d (LPZ lpz, PJ *P) { -/***********************************************************************/ - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - double X, Y, Z, scale; - - point.lpz = lpz; - - if (Q->fourparam) { - point.xy = helmert_forward(point.lp, P); - return point.xyz; - } - - if (Q->no_rotation) { - point.xyz.x = lpz.lam + Q->xyz.x; - point.xyz.y = lpz.phi + Q->xyz.y; - point.xyz.z = lpz.z + Q->xyz.z; - return point.xyz; - } - - scale = 1 + Q->scale * 1e-6; - - X = lpz.lam - Q->refp.x; - Y = lpz.phi - Q->refp.y; - Z = lpz.z - Q->refp.z; - - - point.xyz.x = scale * ( R00 * X + R01 * Y + R02 * Z); - point.xyz.y = scale * ( R10 * X + R11 * Y + R12 * Z); - point.xyz.z = scale * ( R20 * X + R21 * Y + R22 * Z); - - point.xyz.x += Q->xyz.x; /* for Molodensky-Badekas, Q->xyz already incorporates the Q->refp offset */ - point.xyz.y += Q->xyz.y; - point.xyz.z += Q->xyz.z; - - return point.xyz; -} - - -/***********************************************************************/ -static LPZ helmert_reverse_3d (XYZ xyz, PJ *P) { -/***********************************************************************/ - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - double X, Y, Z, scale; - - point.xyz = xyz; - - if (Q->fourparam) { - point.lp = helmert_reverse(point.xy, P); - return point.lpz; - } - - if (Q->no_rotation) { - point.xyz.x = xyz.x - Q->xyz.x; - point.xyz.y = xyz.y - Q->xyz.y; - point.xyz.z = xyz.z - Q->xyz.z; - return point.lpz; - } - - scale = 1 + Q->scale * 1e-6; - - /* Unscale and deoffset */ - X = (xyz.x - Q->xyz.x) / scale; - Y = (xyz.y - Q->xyz.y) / scale; - Z = (xyz.z - Q->xyz.z) / scale; - - /* Inverse rotation through transpose multiplication */ - point.xyz.x = ( R00 * X + R10 * Y + R20 * Z) + Q->refp.x; - point.xyz.y = ( R01 * X + R11 * Y + R21 * Z) + Q->refp.y; - point.xyz.z = ( R02 * X + R12 * Y + R22 * Z) + Q->refp.z; - - return point.lpz; -} - - -static PJ_COORD helmert_forward_4d (PJ_COORD point, PJ *P) { - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; - - /* We only need to rebuild the rotation matrix if the - * observation time is different from the last call */ - double t_obs = (point.xyzt.t == HUGE_VAL) ? Q->t_epoch : point.xyzt.t; - if (t_obs != Q->t_obs) { - Q->t_obs = t_obs; - update_parameters(P); - build_rot_matrix(P); - } - - point.xyz = helmert_forward_3d (point.lpz, P); - - return point; -} - - -static PJ_COORD helmert_reverse_4d (PJ_COORD point, PJ *P) { - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; - - /* We only need to rebuild the rotation matrix if the - * observation time is different from the last call */ - double t_obs = (point.xyzt.t == HUGE_VAL) ? Q->t_epoch : point.xyzt.t; - if (t_obs != Q->t_obs) { - Q->t_obs = t_obs; - update_parameters(P); - build_rot_matrix(P); - } - - point.lpz = helmert_reverse_3d (point.xyz, P); - - return point; -} - -/* Arcsecond to radians */ -#define ARCSEC_TO_RAD (DEG_TO_RAD / 3600.0) - - -static PJ* init_helmert_six_parameters(PJ* P) { - struct pj_opaque_helmert *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque_helmert))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = (void *) Q; - - /* In most cases, we work on 3D cartesian coordinates */ - P->left = PJ_IO_UNITS_CARTESIAN; - P->right = PJ_IO_UNITS_CARTESIAN; - - /* Translations */ - if (pj_param (P->ctx, P->params, "tx").i) - Q->xyz_0.x = pj_param (P->ctx, P->params, "dx").f; - - if (pj_param (P->ctx, P->params, "ty").i) - Q->xyz_0.y = pj_param (P->ctx, P->params, "dy").f; - - if (pj_param (P->ctx, P->params, "tz").i) - Q->xyz_0.z = pj_param (P->ctx, P->params, "dz").f; - - /* Rotations */ - if (pj_param (P->ctx, P->params, "trx").i) - Q->opk_0.o = pj_param (P->ctx, P->params, "drx").f * ARCSEC_TO_RAD; - - if (pj_param (P->ctx, P->params, "try").i) - Q->opk_0.p = pj_param (P->ctx, P->params, "dry").f * ARCSEC_TO_RAD; - - if (pj_param (P->ctx, P->params, "trz").i) - Q->opk_0.k = pj_param (P->ctx, P->params, "drz").f * ARCSEC_TO_RAD; - - /* Use small angle approximations? */ - if (pj_param (P->ctx, P->params, "bexact").i) - Q->exact = 1; - - return P; -} - - -static PJ* read_convention(PJ* P) { - - struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *)P->opaque; - - /* In case there are rotational terms, we require an explicit convention - * to be provided. */ - if (!Q->no_rotation) { - const char* convention = pj_param (P->ctx, P->params, "sconvention").s; - if( !convention ) { - proj_log_error (P, "helmert: missing 'convention' argument"); - return pj_default_destructor (P, PJD_ERR_MISSING_ARGS); - } - if( strcmp(convention, "position_vector") == 0 ) { - Q->is_position_vector = 1; - } - else if( strcmp(convention, "coordinate_frame") == 0 ) { - Q->is_position_vector = 0; - } - else { - proj_log_error (P, "helmert: invalid value for 'convention' argument"); - return pj_default_destructor (P, PJD_ERR_INVALID_ARG); - } - - /* historically towgs84 in PROJ has always been using position_vector - * convention. Accepting coordinate_frame would be confusing. */ - if (pj_param_exists (P->params, "towgs84")) { - if( !Q->is_position_vector ) { - proj_log_error (P, "helmert: towgs84 should only be used with " - "convention=position_vector"); - return pj_default_destructor (P, PJD_ERR_INVALID_ARG); - } - } - } - - return P; -} - - -/***********************************************************************/ -PJ *TRANSFORMATION(helmert, 0) { -/***********************************************************************/ - - struct pj_opaque_helmert *Q; - - if( !init_helmert_six_parameters(P) ) { - return nullptr; - } - - /* In the 2D case, the coordinates are projected */ - if (pj_param_exists (P->params, "theta")) { - P->left = PJ_IO_UNITS_PROJECTED; - P->right = PJ_IO_UNITS_PROJECTED; - } - - P->fwd4d = helmert_forward_4d; - P->inv4d = helmert_reverse_4d; - P->fwd3d = helmert_forward_3d; - P->inv3d = helmert_reverse_3d; - P->fwd = helmert_forward; - P->inv = helmert_reverse; - - Q = (struct pj_opaque_helmert *)P->opaque; - - /* Detect obsolete transpose flag and error out if found */ - if (pj_param (P->ctx, P->params, "ttranspose").i) { - proj_log_error (P, "helmert: 'transpose' argument is no longer valid. " - "Use convention=position_vector/coordinate_frame"); - return pj_default_destructor (P, PJD_ERR_INVALID_ARG); - } - - /* Support the classic PROJ towgs84 parameter, but allow later overrides.*/ - /* Note that if towgs84 is specified, the datum_params array is set up */ - /* for us automagically by the pj_datum_set call in pj_init_ctx */ - if (pj_param_exists (P->params, "towgs84")) { - Q->xyz_0.x = P->datum_params[0]; - Q->xyz_0.y = P->datum_params[1]; - Q->xyz_0.z = P->datum_params[2]; - - Q->opk_0.o = P->datum_params[3]; - Q->opk_0.p = P->datum_params[4]; - Q->opk_0.k = P->datum_params[5]; - - /* We must undo conversion to absolute scale from pj_datum_set */ - if (0==P->datum_params[6]) - Q->scale_0 = 0; - else - Q->scale_0 = (P->datum_params[6] - 1) * 1e6; - } - - if (pj_param (P->ctx, P->params, "ttheta").i) { - Q->theta_0 = pj_param (P->ctx, P->params, "dtheta").f * ARCSEC_TO_RAD; - Q->fourparam = 1; - Q->scale_0 = 1.0; /* default scale for the 4-param shift */ - } - - /* Scale */ - if (pj_param (P->ctx, P->params, "ts").i) { - Q->scale_0 = pj_param (P->ctx, P->params, "ds").f; - if (pj_param (P->ctx, P->params, "ttheta").i && Q->scale_0 == 0.0) - return pj_default_destructor (P, PJD_ERR_INVALID_SCALE); - } - - /* Translation rates */ - if (pj_param(P->ctx, P->params, "tdx").i) - Q->dxyz.x = pj_param (P->ctx, P->params, "ddx").f; - - if (pj_param(P->ctx, P->params, "tdy").i) - Q->dxyz.y = pj_param (P->ctx, P->params, "ddy").f; - - if (pj_param(P->ctx, P->params, "tdz").i) - Q->dxyz.z = pj_param (P->ctx, P->params, "ddz").f; - - /* Rotations rates */ - if (pj_param (P->ctx, P->params, "tdrx").i) - Q->dopk.o = pj_param (P->ctx, P->params, "ddrx").f * ARCSEC_TO_RAD; - - if (pj_param (P->ctx, P->params, "tdry").i) - Q->dopk.p = pj_param (P->ctx, P->params, "ddry").f * ARCSEC_TO_RAD; - - if (pj_param (P->ctx, P->params, "tdrz").i) - Q->dopk.k = pj_param (P->ctx, P->params, "ddrz").f * ARCSEC_TO_RAD; - - if (pj_param (P->ctx, P->params, "tdtheta").i) - Q->dtheta = pj_param (P->ctx, P->params, "ddtheta").f * ARCSEC_TO_RAD; - - /* Scale rate */ - if (pj_param (P->ctx, P->params, "tds").i) - Q->dscale = pj_param (P->ctx, P->params, "dds").f; - - - /* Epoch */ - if (pj_param(P->ctx, P->params, "tt_epoch").i) - Q->t_epoch = pj_param (P->ctx, P->params, "dt_epoch").f; - - if (pj_param(P->ctx, P->params, "tt_obs").i) - Q->t_obs = pj_param (P->ctx, P->params, "dt_obs").f; - - Q->xyz = Q->xyz_0; - Q->opk = Q->opk_0; - Q->scale = Q->scale_0; - Q->theta = Q->theta_0; - - if ((Q->opk.o==0) && (Q->opk.p==0) && (Q->opk.k==0) && (Q->scale==0) && - (Q->dopk.o==0) && (Q->dopk.p==0) && (Q->dopk.k==0)) { - Q->no_rotation = 1; - } - - if( !read_convention(P) ) { - return nullptr; - } - - /* Let's help with debugging */ - if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_DEBUG) { - proj_log_debug(P, "Helmert parameters:"); - proj_log_debug(P, "x= %8.5f y= %8.5f z= %8.5f", Q->xyz.x, Q->xyz.y, Q->xyz.z); - proj_log_debug(P, "rx= %8.5f ry= %8.5f rz= %8.5f", - Q->opk.o / ARCSEC_TO_RAD, Q->opk.p / ARCSEC_TO_RAD, Q->opk.k / ARCSEC_TO_RAD); - proj_log_debug(P, "s= %8.5f exact=%d%s", Q->scale, Q->exact, - Q->no_rotation ? "" : - Q->is_position_vector ? " convention=position_vector" : - " convention=coordinate_frame"); - proj_log_debug(P, "dx= %8.5f dy= %8.5f dz= %8.5f", Q->dxyz.x, Q->dxyz.y, Q->dxyz.z); - proj_log_debug(P, "drx=%8.5f dry=%8.5f drz=%8.5f", Q->dopk.o, Q->dopk.p, Q->dopk.k); - proj_log_debug(P, "ds= %8.5f t_epoch=%8.5f t_obs=%8.5f", Q->dscale, Q->t_epoch, Q->t_obs); - } - - if (Q->no_rotation) { - return P; - } - - update_parameters(P); - build_rot_matrix(P); - - return P; -} - - -/***********************************************************************/ -PJ *TRANSFORMATION(molobadekas, 0) { -/***********************************************************************/ - - struct pj_opaque_helmert *Q; - - if( !init_helmert_six_parameters(P) ) { - return nullptr; - } - - P->fwd3d = helmert_forward_3d; - P->inv3d = helmert_reverse_3d; - - Q = (struct pj_opaque_helmert *)P->opaque; - - /* Scale */ - if (pj_param (P->ctx, P->params, "ts").i) { - Q->scale_0 = pj_param (P->ctx, P->params, "ds").f; - } - - Q->opk = Q->opk_0; - Q->scale = Q->scale_0; - - if( !read_convention(P) ) { - return nullptr; - } - - /* Reference point */ - if (pj_param (P->ctx, P->params, "tpx").i) - Q->refp.x = pj_param (P->ctx, P->params, "dpx").f; - - if (pj_param (P->ctx, P->params, "tpy").i) - Q->refp.y = pj_param (P->ctx, P->params, "dpy").f; - - if (pj_param (P->ctx, P->params, "tpz").i) - Q->refp.z = pj_param (P->ctx, P->params, "dpz").f; - - - /* Let's help with debugging */ - if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_DEBUG) { - proj_log_debug(P, "Molodensky-Badekas parameters:"); - proj_log_debug(P, "x= %8.5f y= %8.5f z= %8.5f", Q->xyz_0.x, Q->xyz_0.y, Q->xyz_0.z); - proj_log_debug(P, "rx= %8.5f ry= %8.5f rz= %8.5f", - Q->opk.o / ARCSEC_TO_RAD, Q->opk.p / ARCSEC_TO_RAD, Q->opk.k / ARCSEC_TO_RAD); - proj_log_debug(P, "s= %8.5f exact=%d%s", Q->scale, Q->exact, - Q->is_position_vector ? " convention=position_vector" : - " convention=coordinate_frame"); - proj_log_debug(P, "px= %8.5f py= %8.5f pz= %8.5f", Q->refp.x, Q->refp.y, Q->refp.z); - } - - /* as an optimization, we incorporate the refp in the translation terms */ - Q->xyz_0.x += Q->refp.x; - Q->xyz_0.y += Q->refp.y; - Q->xyz_0.z += Q->refp.z; - - Q->xyz = Q->xyz_0; - - build_rot_matrix(P); - - return P; -} diff --git a/src/transformations/PJ_hgridshift.cpp b/src/transformations/PJ_hgridshift.cpp deleted file mode 100644 index f0e57251..00000000 --- a/src/transformations/PJ_hgridshift.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#define PJ_LIB__ - -#include -#include -#include -#include - -#include "proj_internal.h" -#include "projects.h" - -PROJ_HEAD(hgridshift, "Horizontal grid shift"); - -namespace { // anonymous namespace -struct pj_opaque_hgridshift { - double t_final; - double t_epoch; -}; -} // anonymous namespace - -static XYZ forward_3d(LPZ lpz, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - point.lpz = lpz; - - if (P->gridlist != nullptr) { - /* Only try the gridshift if at least one grid is loaded, - * otherwise just pass the coordinate through unchanged. */ - point.lp = proj_hgrid_apply(P, point.lp, PJ_FWD); - } - - return point.xyz; -} - - -static LPZ reverse_3d(XYZ xyz, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - point.xyz = xyz; - - if (P->gridlist != nullptr) { - /* Only try the gridshift if at least one grid is loaded, - * otherwise just pass the coordinate through unchanged. */ - point.lp = proj_hgrid_apply(P, point.lp, PJ_INV); - } - - return point.lpz; -} - -static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { - struct pj_opaque_hgridshift *Q = (struct pj_opaque_hgridshift *) P->opaque; - PJ_COORD point = obs; - - /* If transformation is not time restricted, we always call it */ - if (Q->t_final==0 || Q->t_epoch==0) { - point.xyz = forward_3d (obs.lpz, P); - return point; - } - - /* Time restricted - only apply transform if within time bracket */ - if (obs.lpzt.t < Q->t_epoch && Q->t_final > Q->t_epoch) - point.xyz = forward_3d (obs.lpz, P); - - - return point; -} - -static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { - struct pj_opaque_hgridshift *Q = (struct pj_opaque_hgridshift *) P->opaque; - PJ_COORD point = obs; - - /* If transformation is not time restricted, we always call it */ - if (Q->t_final==0 || Q->t_epoch==0) { - point.lpz = reverse_3d (obs.xyz, P); - return point; - } - - /* Time restricted - only apply transform if within time bracket */ - if (obs.lpzt.t < Q->t_epoch && Q->t_final > Q->t_epoch) - point.lpz = reverse_3d (obs.xyz, P); - - return point; -} - - -PJ *TRANSFORMATION(hgridshift,0) { - struct pj_opaque_hgridshift *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque_hgridshift))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = (void *) Q; - - P->fwd4d = forward_4d; - P->inv4d = reverse_4d; - P->fwd3d = forward_3d; - P->inv3d = reverse_3d; - P->fwd = nullptr; - P->inv = nullptr; - - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_ANGULAR; - - if (0==pj_param(P->ctx, P->params, "tgrids").i) { - proj_log_error(P, "hgridshift: +grids parameter missing."); - return pj_default_destructor (P, PJD_ERR_NO_ARGS); - } - - /* TODO: Refactor into shared function that can be used */ - /* by both vgridshift and hgridshift */ - if (pj_param(P->ctx, P->params, "tt_final").i) { - Q->t_final = pj_param (P->ctx, P->params, "dt_final").f; - if (Q->t_final == 0) { - /* a number wasn't passed to +t_final, let's see if it was "now" */ - /* and set the time accordingly. */ - if (!strcmp("now", pj_param(P->ctx, P->params, "st_final").s)) { - time_t now; - struct tm *date; - time(&now); - date = localtime(&now); - Q->t_final = 1900.0 + date->tm_year + date->tm_yday/365.0; - } - } - } - - if (pj_param(P->ctx, P->params, "tt_epoch").i) - Q->t_epoch = pj_param (P->ctx, P->params, "dt_epoch").f; - - - proj_hgrid_init(P, "grids"); - /* Was gridlist compiled properly? */ - if ( proj_errno(P) ) { - proj_log_error(P, "hgridshift: could not find required grid(s)."); - return pj_default_destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID); - } - - return P; -} diff --git a/src/transformations/PJ_horner.cpp b/src/transformations/PJ_horner.cpp deleted file mode 100644 index 73977de6..00000000 --- a/src/transformations/PJ_horner.cpp +++ /dev/null @@ -1,513 +0,0 @@ -/*********************************************************************** - - Interfacing to a classic piece of geodetic software - -************************************************************************ - - gen_pol is a highly efficient, classic implementation of a generic - 2D Horner's Scheme polynomial evaluation routine by Knud Poder and - Karsten Engsager, originating in the vivid geodetic environment at - what was then (1960-ish) the Danish Geodetic Institute. - - The original Poder/Engsager gen_pol implementation (where - the polynomial degree and two sets of polynomial coefficients - are packed together in one compound array, handled via a plain - double pointer) is compelling and "true to the code history": - - It has a beautiful classical 1960s ring to it, not unlike the - original fft implementations, which revolutionized spectral - analysis in twenty lines of code. - - The Poder coding sound, as classic 1960s as Phil Spector's Wall - of Sound, is beautiful and inimitable. - - On the other hand: For the uninitiated, the gen_pol code is hard - to follow, despite being compact. - - Also, since adding metadata and improving maintainability - of the code are among the implied goals of a current SDFE/DTU Space - project, the material in this file introduces a version with a - more modern (or at least 1990s) look, introducing a "double 2D - polynomial" data type, HORNER. - - Despite introducing a new data type for handling the polynomial - coefficients, great care has been taken to keep the coefficient - array organization identical to that of gen_pol. - - Hence, on one hand, the HORNER data type helps improving the - long term maintainability of the code by making the data - organization more mentally accessible. - - On the other hand, it allows us to preserve the business end of - the original gen_pol implementation - although not including the - famous "Poder dual autocheck" in all its enigmatic elegance. - - ********************************************************************** - - The material included here was written by Knud Poder, starting - around 1960, and Karsten Engsager, starting around 1970. It was - originally written in Algol 60, later (1980s) reimplemented in C. - - The HORNER data type interface, and the organization as a header - library was implemented by Thomas Knudsen, starting around 2015. - - *********************************************************************** - * - * Copyright (c) 2016, SDFE http://www.sdfe.dk / Thomas Knudsen / Karsten Engsager - * - * 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 -#include - -#include "proj_internal.h" -#include "projects.h" - -PROJ_HEAD(horner, "Horner polynomial evaluation"); - -/* make horner.h interface with proj's memory management */ -#define horner_dealloc(x) pj_dealloc(x) -#define horner_calloc(n,x) pj_calloc(n,x) - -namespace { // anonymous namespace -struct horner { - int uneg; /* u axis negated? */ - int vneg; /* v axis negated? */ - int order; /* maximum degree of polynomium */ - int coefs; /* number of coefficients for each polynomium */ - double range; /* radius of the region of validity */ - - double *fwd_u; /* coefficients for the forward transformations */ - double *fwd_v; /* i.e. latitude/longitude to northing/easting */ - - double *inv_u; /* coefficients for the inverse transformations */ - double *inv_v; /* i.e. northing/easting to latitude/longitude */ - - double *fwd_c; /* coefficients for the complex forward transformations */ - double *inv_c; /* coefficients for the complex inverse transformations */ - - UV *fwd_origin; /* False longitude/latitude */ - UV *inv_origin; /* False easting/northing */ -}; -} // anonymous namespace - -typedef struct horner HORNER; -static UV horner_func (const HORNER *transformation, PJ_DIRECTION direction, UV position); -static HORNER *horner_alloc (size_t order, int complex_polynomia); -static void horner_free (HORNER *h); - -/* e.g. degree = 2: a + bx + cy + dxx + eyy + fxy, i.e. 6 coefficients */ -#define horner_number_of_coefficients(order) \ - (((order + 1)*(order + 2)/2)) - - -static void horner_free (HORNER *h) { - horner_dealloc (h->inv_v); - horner_dealloc (h->inv_u); - horner_dealloc (h->fwd_v); - horner_dealloc (h->fwd_u); - horner_dealloc (h->fwd_c); - horner_dealloc (h->inv_c); - horner_dealloc (h->fwd_origin); - horner_dealloc (h->inv_origin); - horner_dealloc (h); -} - - -static HORNER *horner_alloc (size_t order, int complex_polynomia) { - /* size_t is unsigned, so we need not check for order > 0 */ - int n = (int)horner_number_of_coefficients(order); - int polynomia_ok = 0; - HORNER *h = static_cast(horner_calloc (1, sizeof (HORNER))); - - if (nullptr==h) - return nullptr; - - if (complex_polynomia) - n = 2*(int)order + 2; - h->order = (int)order; - h->coefs = n; - - if (complex_polynomia) { - h->fwd_c = static_cast(horner_calloc (n, sizeof(double))); - h->inv_c = static_cast(horner_calloc (n, sizeof(double))); - if (h->fwd_c && h->inv_c) - polynomia_ok = 1; - } - else { - h->fwd_u = static_cast(horner_calloc (n, sizeof(double))); - h->fwd_v = static_cast(horner_calloc (n, sizeof(double))); - h->inv_u = static_cast(horner_calloc (n, sizeof(double))); - h->inv_v = static_cast(horner_calloc (n, sizeof(double))); - if (h->fwd_u && h->fwd_v && h->inv_u && h->inv_v) - polynomia_ok = 1; - } - - h->fwd_origin = static_cast(horner_calloc (1, sizeof(UV))); - h->inv_origin = static_cast(horner_calloc (1, sizeof(UV))); - - if (polynomia_ok && h->fwd_origin && h->inv_origin) - return h; - - /* safe, since all pointers are null-initialized (by calloc) */ - horner_free (h); - return nullptr; -} - - - - -/**********************************************************************/ -static UV horner_func (const HORNER *transformation, PJ_DIRECTION direction, UV position) { -/*********************************************************************** - -A reimplementation of the classic Engsager/Poder 2D Horner polynomial -evaluation engine "gen_pol". - -This version omits the inimitable Poder "dual autocheck"-machinery, -which here is intended to be implemented at a higher level of the -library: We separate the polynomial evaluation from the quality -control (which, given the limited MTBF for "computing machinery", -typical when Knud Poder invented the dual autocheck method, -was not defensible at that time). - -Another difference from the original version is that we return the -result on the stack, rather than accepting pointers to result variables -as input. This results in code that is easy to read: - - projected = horner (s34j, 1, geographic); - geographic = horner (s34j, -1, projected ); - -and experiments have shown that on contemporary architectures, the time -taken for returning even comparatively large objects on the stack (and -the UV is not that large - typically only 16 bytes) is negligibly -different from passing two pointers (i.e. typically also 16 bytes) the -other way. - -The polynomium has the form: - -P = sum (i = [0 : order]) - sum (j = [0 : order - i]) - pow(par_1, i) * pow(par_2, j) * coef(index(order, i, j)) - -For numerical stability, the summation is carried out backwards, -summing the tiny high order elements first. - -***********************************************************************/ - - /* These variable names follow the Engsager/Poder implementation */ - int sz; /* Number of coefficients per polynomial */ - double *tcx, *tcy; /* Coefficient pointers */ - double range; /* Equivalent to the gen_pol's FLOATLIMIT constant */ - double n, e; - UV uv_error; - uv_error.u = uv_error.v = HUGE_VAL; - - if (nullptr==transformation) - return uv_error; - - /* Check for valid value of direction (-1, 0, 1) */ - switch (direction) { - case PJ_IDENT: /* no-op */ - return position; - case PJ_FWD: /* forward */ - case PJ_INV: /* inverse */ - break; - default: /* invalid */ - errno = EINVAL; - return uv_error; - } - - /* Prepare for double Horner */ - sz = horner_number_of_coefficients(transformation->order); - range = transformation->range; - - - if (direction==PJ_FWD) { /* forward */ - tcx = transformation->fwd_u + sz; - tcy = transformation->fwd_v + sz; - e = position.u - transformation->fwd_origin->u; - n = position.v - transformation->fwd_origin->v; - } else { /* inverse */ - tcx = transformation->inv_u + sz; - tcy = transformation->inv_v + sz; - e = position.u - transformation->inv_origin->u; - n = position.v - transformation->inv_origin->v; - } - - if ((fabs(n) > range) || (fabs(e) > range)) { - errno = EDOM; - return uv_error; - } - - /* The melody of this block is straight out of the great Engsager/Poder songbook */ - else { - int g = transformation->order; - int r = g, c; - double u, v, N, E; - - /* Double Horner's scheme: N = n*Cy*e -> yout, E = e*Cx*n -> xout */ - N = *--tcy; - E = *--tcx; - for (; r > 0; r--) { - u = *--tcy; - v = *--tcx; - for (c = g; c >= r; c--) { - u = n*u + *--tcy; - v = e*v + *--tcx; - } - N = e*N + u; - E = n*E + v; - } - - position.u = E; - position.v = N; - } - - return position; -} - - - - - - - -static PJ_COORD horner_forward_4d (PJ_COORD point, PJ *P) { - point.uv = horner_func ((HORNER *) P->opaque, PJ_FWD, point.uv); - return point; -} - -static PJ_COORD horner_reverse_4d (PJ_COORD point, PJ *P) { - point.uv = horner_func ((HORNER *) P->opaque, PJ_INV, point.uv); - return point; -} - - - - -/**********************************************************************/ -static UV complex_horner (const HORNER *transformation, PJ_DIRECTION direction, UV position) { -/*********************************************************************** - -A reimplementation of a classic Engsager/Poder Horner complex -polynomial evaluation engine. - -***********************************************************************/ - - /* These variable names follow the Engsager/Poder implementation */ - int sz; /* Number of coefficients */ - double *c, *cb; /* Coefficient pointers */ - double range; /* Equivalent to the gen_pol's FLOATLIMIT constant */ - double n, e, w, N, E; - UV uv_error; - uv_error.u = uv_error.v = HUGE_VAL; - - if (nullptr==transformation) - return uv_error; - - /* Check for valid value of direction (-1, 0, 1) */ - switch (direction) { - case PJ_IDENT: /* no-op */ - return position; - case PJ_FWD: /* forward */ - case PJ_INV: /* inverse */ - break; - default: /* invalid */ - errno = EINVAL; - return uv_error; - } - - /* Prepare for double Horner */ - sz = 2*transformation->order + 2; - range = transformation->range; - - if (direction==PJ_FWD) { /* forward */ - cb = transformation->fwd_c; - c = cb + sz; - e = position.u - transformation->fwd_origin->u; - n = position.v - transformation->fwd_origin->v; - if (transformation->uneg) - e = -e; - if (transformation->vneg) - n = -n; - } else { /* inverse */ - cb = transformation->inv_c; - c = cb + sz; - e = position.u - transformation->inv_origin->u; - n = position.v - transformation->inv_origin->v; - if (transformation->uneg) - e = -e; - if (transformation->vneg) - n = -n; - } - - if ((fabs(n) > range) || (fabs(e) > range)) { - errno = EDOM; - return uv_error; - } - - /* Everything's set up properly - now do the actual polynomium evaluation */ - E = *--c; - N = *--c; - while (c > cb) { - w = n*E + e*N + *--c; - N = n*N - e*E + *--c; - E = w; - } - - position.u = E; - position.v = N; - return position; -} - - - -static PJ_COORD complex_horner_forward_4d (PJ_COORD point, PJ *P) { - point.uv = complex_horner ((HORNER *) P->opaque, PJ_FWD, point.uv); - return point; -} - -static PJ_COORD complex_horner_reverse_4d (PJ_COORD point, PJ *P) { - point.uv = complex_horner ((HORNER *) P->opaque, PJ_INV, point.uv); - return point; -} - - -static PJ *horner_freeup (PJ *P, int errlev) { /* Destructor */ - if (nullptr==P) - return nullptr; - if (nullptr==P->opaque) - return pj_default_destructor (P, errlev); - horner_free ((HORNER *) P->opaque); - P->opaque = nullptr; - return pj_default_destructor (P, errlev); -} - - -static int parse_coefs (PJ *P, double *coefs, const char *param, int ncoefs) { - char *buf, *init, *next = nullptr; - int i; - - buf = static_cast(pj_calloc (strlen (param) + 2, sizeof(char))); - if (nullptr==buf) { - proj_log_error (P, "Horner: No memory left"); - return 0; - } - - sprintf (buf, "t%s", param); - if (0==pj_param (P->ctx, P->params, buf).i) { - pj_dealloc (buf); - return 0; - } - sprintf (buf, "s%s", param); - init = pj_param(P->ctx, P->params, buf).s; - pj_dealloc (buf); - - for (i = 0; i < ncoefs; i++) { - if (i > 0) { - if ( next == nullptr || ','!=*next) { - proj_log_error (P, "Horner: Malformed polynomium set %s. need %d coefs", param, ncoefs); - return 0; - } - init = ++next; - } - coefs[i] = pj_strtod (init, &next); - } - return 1; -} - - -/*********************************************************************/ -PJ *PROJECTION(horner) { -/*********************************************************************/ - int degree = 0, n, complex_polynomia = 0; - HORNER *Q; - P->fwd4d = horner_forward_4d; - P->inv4d = horner_reverse_4d; - P->fwd3d = nullptr; - P->inv3d = nullptr; - P->fwd = nullptr; - P->inv = nullptr; - P->left = P->right = PJ_IO_UNITS_PROJECTED; - P->destructor = horner_freeup; - - /* Polynomial degree specified? */ - if (pj_param (P->ctx, P->params, "tdeg").i) { /* degree specified? */ - degree = pj_param(P->ctx, P->params, "ideg").i; - if (degree < 0 || degree > 10000) { - /* What are reasonable minimum and maximums for degree? */ - proj_log_debug (P, "Horner: Degree is unreasonable: %d", degree); - return horner_freeup (P, PJD_ERR_INVALID_ARG); - } - } else { - proj_log_debug (P, "Horner: Must specify polynomial degree, (+deg=n)"); - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - } - - if (pj_param (P->ctx, P->params, "tfwd_c").i || pj_param (P->ctx, P->params, "tinv_c").i) /* complex polynomium? */ - complex_polynomia = 1; - - Q = horner_alloc (degree, complex_polynomia); - if (Q == nullptr) - return horner_freeup (P, ENOMEM); - P->opaque = Q; - - if (complex_polynomia) { - /* Westings and/or southings? */ - Q->uneg = pj_param_exists (P->params, "uneg") ? 1 : 0; - Q->vneg = pj_param_exists (P->params, "vneg") ? 1 : 0; - - n = 2*degree + 2; - if (0==parse_coefs (P, Q->fwd_c, "fwd_c", n)) - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - if (0==parse_coefs (P, Q->inv_c, "inv_c", n)) - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - P->fwd4d = complex_horner_forward_4d; - P->inv4d = complex_horner_reverse_4d; - } - - else { - n = horner_number_of_coefficients (degree); - if (0==parse_coefs (P, Q->fwd_u, "fwd_u", n)) - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - if (0==parse_coefs (P, Q->fwd_v, "fwd_v", n)) - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - if (0==parse_coefs (P, Q->inv_u, "inv_u", n)) - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - if (0==parse_coefs (P, Q->inv_v, "inv_v", n)) - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - } - - if (0==parse_coefs (P, (double *)(Q->fwd_origin), "fwd_origin", 2)) - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - if (0==parse_coefs (P, (double *)(Q->inv_origin), "inv_origin", 2)) - return horner_freeup (P, PJD_ERR_MISSING_ARGS); - if (0==parse_coefs (P, &Q->range, "range", 1)) - Q->range = 500000; - - return P; -} diff --git a/src/transformations/PJ_molodensky.cpp b/src/transformations/PJ_molodensky.cpp deleted file mode 100644 index 91743fda..00000000 --- a/src/transformations/PJ_molodensky.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/*********************************************************************** - - (Abridged) Molodensky Transform - - Kristian Evers, 2017-07-07 - -************************************************************************ - - Implements the (abridged) Molodensky transformations for 2D and 3D - data. - - Primarily useful for implementation of datum shifts in transformation - pipelines. - - The code in this file is mostly based on - - The Standard and Abridged Molodensky Coordinate Transformation - Formulae, 2004, R.E. Deaking, - http://www.mygeodesy.id.au/documents/Molodensky%20V2.pdf - - - -************************************************************************ -* Copyright (c) 2017, Kristian Evers / SDFE -* -* 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 "proj_internal.h" -#include "projects.h" - -PROJ_HEAD(molodensky, "Molodensky transform"); - -static XYZ forward_3d(LPZ lpz, PJ *P); -static LPZ reverse_3d(XYZ xyz, PJ *P); - -namespace { // anonymous namespace -struct pj_opaque_molodensky { - double dx; - double dy; - double dz; - double da; - double df; - int abridged; -}; -} // anonymous namespace - - -static double RN (double a, double es, double phi) { -/********************************************************** - N(phi) - prime vertical radius of curvature - ------------------------------------------- - - This is basically the same function as in PJ_cart.c - should probably be refactored into it's own file at some - point. - -**********************************************************/ - double s = sin(phi); - if (es==0) - return a; - - return a / sqrt (1 - es*s*s); -} - - -static double RM (double a, double es, double phi) { -/********************************************************** - M(phi) - Meridian radius of curvature - ------------------------------------- - - Source: - - E.J Krakiwsky & D.B. Thomson, 1974, - GEODETIC POSITION COMPUTATIONS, - - Fredericton NB, Canada: - University of New Brunswick, - Department of Geodesy and Geomatics Engineering, - Lecture Notes No. 39, - 99 pp. - - http://www2.unb.ca/gge/Pubs/LN39.pdf - -**********************************************************/ - double s = sin(phi); - if (es==0) - return a; - - /* eq. 13a */ - if (phi == 0) - return a * (1-es); - - /* eq. 13b */ - if (fabs(phi) == M_PI_2) - return a / sqrt(1-es); - - /* eq. 13 */ - return (a * (1 - es) ) / pow(1 - es*s*s, 1.5); - -} - - -static LPZ calc_standard_params(LPZ lpz, PJ *P) { - struct pj_opaque_molodensky *Q = (struct pj_opaque_molodensky *) P->opaque; - double dphi, dlam, dh; - - /* sines and cosines */ - double slam = sin(lpz.lam); - double clam = cos(lpz.lam); - double sphi = sin(lpz.phi); - double cphi = cos(lpz.phi); - - /* ellipsoid parameters and differences */ - double f = P->f, a = P->a; - double dx = Q->dx, dy = Q->dy, dz = Q->dz; - double da = Q->da, df = Q->df; - - /* ellipsoid radii of curvature */ - double rho = RM(a, P->es, lpz.phi); - double nu = RN(a, P->e2s, lpz.phi); - - /* delta phi */ - dphi = (-dx*sphi*clam) - (dy*sphi*slam) + (dz*cphi) - + ((nu * P->es * sphi * cphi * da) / a) - + (sphi*cphi * ( rho/(1-f) + nu*(1-f))*df); - dphi /= (rho + lpz.z); - - /* delta lambda */ - dlam = (-dx*slam + dy*clam) / ((nu+lpz.z)*cphi); - - /* delta h */ - dh = dx*cphi*clam + dy*cphi*slam + dz*sphi - (a/nu)*da + nu*(1-f)*sphi*sphi*df; - - lpz.phi = dphi; - lpz.lam = dlam; - lpz.z = dh; - - return lpz; -} - - -static LPZ calc_abridged_params(LPZ lpz, PJ *P) { - struct pj_opaque_molodensky *Q = (struct pj_opaque_molodensky *) P->opaque; - double dphi, dlam, dh; - - /* sines and cosines */ - double slam = sin(lpz.lam); - double clam = cos(lpz.lam); - double sphi = sin(lpz.phi); - double cphi = cos(lpz.phi); - - /* ellipsoid parameters and differences */ - double dx = Q->dx, dy = Q->dy, dz = Q->dz; - double da = Q->da, df = Q->df; - double adffda = (P->a*df + P->f*da); - - /* delta phi */ - dphi = -dx*sphi*clam - dy*sphi*slam + dz*cphi + adffda*sin(2*lpz.phi); - dphi /= RM(P->a, P->es, lpz.phi); - - /* delta lambda */ - dlam = -dx*slam + dy*clam; - dlam /= RN(P->a, P->e2s, lpz.phi)*cphi; - - /* delta h */ - dh = dx*cphi*clam + dy*cphi*slam + dz*sphi - da + adffda*sphi*sphi; - - /* offset coordinate */ - lpz.phi = dphi; - lpz.lam = dlam; - lpz.z = dh; - - return lpz; -} - - -static XY forward_2d(LP lp, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - - point.lp = lp; - point.xyz = forward_3d(point.lpz, P); - - return point.xy; -} - - -static LP reverse_2d(XY xy, PJ *P) { - PJ_COORD point = {{0,0,0,0}}; - - point.xy = xy; - point.xyz.z = 0; - point.lpz = reverse_3d(point.xyz, P); - - return point.lp; -} - - -static XYZ forward_3d(LPZ lpz, PJ *P) { - struct pj_opaque_molodensky *Q = (struct pj_opaque_molodensky *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - - point.lpz = lpz; - - /* calculate parameters depending on the mode we are in */ - if (Q->abridged) { - lpz = calc_abridged_params(lpz, P); - } else { - lpz = calc_standard_params(lpz, P); - } - - /* offset coordinate */ - point.lpz.phi += lpz.phi; - point.lpz.lam += lpz.lam; - point.lpz.z += lpz.z; - - return point.xyz; -} - - -static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { - obs.xyz = forward_3d(obs.lpz, P); - return obs; -} - - -static LPZ reverse_3d(XYZ xyz, PJ *P) { - struct pj_opaque_molodensky *Q = (struct pj_opaque_molodensky *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - LPZ lpz; - - /* calculate parameters depending on the mode we are in */ - point.xyz = xyz; - if (Q->abridged) - lpz = calc_abridged_params(point.lpz, P); - else - lpz = calc_standard_params(point.lpz, P); - - /* offset coordinate */ - point.lpz.phi -= lpz.phi; - point.lpz.lam -= lpz.lam; - point.lpz.z -= lpz.z; - - return point.lpz; -} - - -static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { - obs.lpz = reverse_3d(obs.xyz, P); - return obs; -} - - -PJ *TRANSFORMATION(molodensky,1) { - int count_required_params = 0; - struct pj_opaque_molodensky *Q = static_cast(pj_calloc(1, sizeof(struct pj_opaque_molodensky))); - if (nullptr==Q) - return pj_default_destructor(P, ENOMEM); - P->opaque = (void *) Q; - - P->fwd4d = forward_4d; - P->inv4d = reverse_4d; - P->fwd3d = forward_3d; - P->inv3d = reverse_3d; - P->fwd = forward_2d; - P->inv = reverse_2d; - - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_ANGULAR; - - /* read args */ - if (pj_param(P->ctx, P->params, "tdx").i) { - count_required_params ++; - Q->dx = pj_param(P->ctx, P->params, "ddx").f; - } - - if (pj_param(P->ctx, P->params, "tdy").i) { - count_required_params ++; - Q->dy = pj_param(P->ctx, P->params, "ddy").f; - } - - if (pj_param(P->ctx, P->params, "tdz").i) { - count_required_params ++; - Q->dz = pj_param(P->ctx, P->params, "ddz").f; - } - - if (pj_param(P->ctx, P->params, "tda").i) { - count_required_params ++; - Q->da = pj_param(P->ctx, P->params, "dda").f; - } - - if (pj_param(P->ctx, P->params, "tdf").i) { - count_required_params ++; - Q->df = pj_param(P->ctx, P->params, "ddf").f; - } - - Q->abridged = pj_param(P->ctx, P->params, "tabridged").i; - - /* We want all parameters (except +abridged) to be set */ - if (count_required_params == 0) - return pj_default_destructor(P, PJD_ERR_NO_ARGS); - - if (count_required_params != 5) - return pj_default_destructor(P, PJD_ERR_MISSING_ARGS); - - return P; -} diff --git a/src/transformations/PJ_vgridshift.cpp b/src/transformations/PJ_vgridshift.cpp deleted file mode 100644 index b3da906d..00000000 --- a/src/transformations/PJ_vgridshift.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#define PJ_LIB__ - -#include -#include -#include -#include - -#include "proj_internal.h" -#include "projects.h" - -PROJ_HEAD(vgridshift, "Vertical grid shift"); - -namespace { // anonymous namespace -struct pj_opaque_vgridshift { - double t_final; - double t_epoch; - double forward_multiplier; -}; -} // anonymous namespace - -static XYZ forward_3d(LPZ lpz, PJ *P) { - struct pj_opaque_vgridshift *Q = (struct pj_opaque_vgridshift *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - point.lpz = lpz; - - if (P->vgridlist_geoid != nullptr) { - /* Only try the gridshift if at least one grid is loaded, - * otherwise just pass the coordinate through unchanged. */ - point.xyz.z += Q->forward_multiplier * proj_vgrid_value(P, point.lp); - } - - return point.xyz; -} - - -static LPZ reverse_3d(XYZ xyz, PJ *P) { - struct pj_opaque_vgridshift *Q = (struct pj_opaque_vgridshift *) P->opaque; - PJ_COORD point = {{0,0,0,0}}; - point.xyz = xyz; - - if (P->vgridlist_geoid != nullptr) { - /* Only try the gridshift if at least one grid is loaded, - * otherwise just pass the coordinate through unchanged. */ - point.xyz.z -= Q->forward_multiplier * proj_vgrid_value(P, point.lp); - } - - return point.lpz; -} - - -static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { - struct pj_opaque_vgridshift *Q = (struct pj_opaque_vgridshift *) P->opaque; - PJ_COORD point = obs; - - /* If transformation is not time restricted, we always call it */ - if (Q->t_final==0 || Q->t_epoch==0) { - point.xyz = forward_3d (obs.lpz, P); - return point; - } - - /* Time restricted - only apply transform if within time bracket */ - if (obs.lpzt.t < Q->t_epoch && Q->t_final > Q->t_epoch) - point.xyz = forward_3d (obs.lpz, P); - - - return point; -} - -static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { - struct pj_opaque_vgridshift *Q = (struct pj_opaque_vgridshift *) P->opaque; - PJ_COORD point = obs; - - /* If transformation is not time restricted, we always call it */ - if (Q->t_final==0 || Q->t_epoch==0) { - point.lpz = reverse_3d (obs.xyz, P); - return point; - } - - /* Time restricted - only apply transform if within time bracket */ - if (obs.lpzt.t < Q->t_epoch && Q->t_final > Q->t_epoch) - point.lpz = reverse_3d (obs.xyz, P); - - return point; -} - - -PJ *TRANSFORMATION(vgridshift,0) { - struct pj_opaque_vgridshift *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque_vgridshift))); - if (nullptr==Q) - return pj_default_destructor (P, ENOMEM); - P->opaque = (void *) Q; - - if (!pj_param(P->ctx, P->params, "tgrids").i) { - proj_log_error(P, "vgridshift: +grids parameter missing."); - return pj_default_destructor(P, PJD_ERR_NO_ARGS); - } - - /* TODO: Refactor into shared function that can be used */ - /* by both vgridshift and hgridshift */ - if (pj_param(P->ctx, P->params, "tt_final").i) { - Q->t_final = pj_param (P->ctx, P->params, "dt_final").f; - if (Q->t_final == 0) { - /* a number wasn't passed to +t_final, let's see if it was "now" */ - /* and set the time accordingly. */ - if (!strcmp("now", pj_param(P->ctx, P->params, "st_final").s)) { - time_t now; - struct tm *date; - time(&now); - date = localtime(&now); - Q->t_final = 1900.0 + date->tm_year + date->tm_yday/365.0; - } - } - } - - if (pj_param(P->ctx, P->params, "tt_epoch").i) - Q->t_epoch = pj_param (P->ctx, P->params, "dt_epoch").f; - - /* historical: the forward direction subtracts the grid offset. */ - Q->forward_multiplier = -1.0; - if (pj_param(P->ctx, P->params, "tmultiplier").i) { - Q->forward_multiplier = pj_param(P->ctx, P->params, "dmultiplier").f; - } - - /* Build gridlist. P->vgridlist_geoid can be empty if +grids only ask for optional grids. */ - proj_vgrid_init(P, "grids"); - - /* Was gridlist compiled properly? */ - if ( proj_errno(P) ) { - proj_log_error(P, "vgridshift: could not find required grid(s)."); - return pj_default_destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID); - } - - P->fwd4d = forward_4d; - P->inv4d = reverse_4d; - P->fwd3d = forward_3d; - P->inv3d = reverse_3d; - P->fwd = nullptr; - P->inv = nullptr; - - P->left = PJ_IO_UNITS_ANGULAR; - P->right = PJ_IO_UNITS_ANGULAR; - - return P; -} diff --git a/src/transformations/affine.cpp b/src/transformations/affine.cpp new file mode 100644 index 00000000..e2b668d3 --- /dev/null +++ b/src/transformations/affine.cpp @@ -0,0 +1,250 @@ +/************************************************************************ +* Copyright (c) 2018, Even Rouault +* +* 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_internal.h" +#include "proj.h" +#include "projects.h" + +PROJ_HEAD(affine, "Affine transformation"); +PROJ_HEAD(geogoffset, "Geographic Offset"); + +namespace { // anonymous namespace +struct pj_affine_coeffs { + double s11; + double s12; + double s13; + double s21; + double s22; + double s23; + double s31; + double s32; + double s33; + double tscale; +}; +} // anonymous namespace + +namespace { // anonymous namespace +struct pj_opaque_affine { + double xoff; + double yoff; + double zoff; + double toff; + struct pj_affine_coeffs forward; + struct pj_affine_coeffs reverse; +}; +} // anonymous namespace + + +static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { + PJ_COORD newObs; + const struct pj_opaque_affine *Q = (const struct pj_opaque_affine *) P->opaque; + const struct pj_affine_coeffs *C = &(Q->forward); + newObs.xyzt.x = Q->xoff + C->s11 * obs.xyzt.x + C->s12 * obs.xyzt.y + C->s13 * obs.xyzt.z; + newObs.xyzt.y = Q->yoff + C->s21 * obs.xyzt.x + C->s22 * obs.xyzt.y + C->s23 * obs.xyzt.z; + newObs.xyzt.z = Q->zoff + C->s31 * obs.xyzt.x + C->s32 * obs.xyzt.y + C->s33 * obs.xyzt.z; + newObs.xyzt.t = Q->toff + C->tscale * obs.xyzt.t; + return newObs; +} + +static XYZ forward_3d(LPZ lpz, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + point.lpz = lpz; + return forward_4d(point, P).xyz; +} + + +static XY forward_2d(LP lp, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + point.lp = lp; + return forward_4d(point, P).xy; +} + + +static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { + PJ_COORD newObs; + const struct pj_opaque_affine *Q = (const struct pj_opaque_affine *) P->opaque; + const struct pj_affine_coeffs *C = &(Q->reverse); + obs.xyzt.x -= Q->xoff; + obs.xyzt.y -= Q->yoff; + obs.xyzt.z -= Q->zoff; + newObs.xyzt.x = C->s11 * obs.xyzt.x + C->s12 * obs.xyzt.y + C->s13 * obs.xyzt.z; + newObs.xyzt.y = C->s21 * obs.xyzt.x + C->s22 * obs.xyzt.y + C->s23 * obs.xyzt.z; + newObs.xyzt.z = C->s31 * obs.xyzt.x + C->s32 * obs.xyzt.y + C->s33 * obs.xyzt.z; + newObs.xyzt.t = C->tscale * (obs.xyzt.t - Q->toff); + return newObs; +} + +static LPZ reverse_3d(XYZ xyz, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + point.xyz = xyz; + return reverse_4d(point, P).lpz; +} + +static LP reverse_2d(XY xy, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + point.xy = xy; + return reverse_4d(point, P).lp; +} + +static struct pj_opaque_affine * initQ() { + struct pj_opaque_affine *Q = static_cast(pj_calloc(1, sizeof(struct pj_opaque_affine))); + if (nullptr==Q) + return nullptr; + + /* default values */ + Q->forward.s11 = 1.0; + Q->forward.s22 = 1.0; + Q->forward.s33 = 1.0; + Q->forward.tscale = 1.0; + + Q->reverse.s11 = 1.0; + Q->reverse.s22 = 1.0; + Q->reverse.s33 = 1.0; + Q->reverse.tscale = 1.0; + + return Q; +} + +static void computeReverseParameters(PJ* P) +{ + struct pj_opaque_affine *Q = (struct pj_opaque_affine *) P->opaque; + + /* cf https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3_%C3%97_3_matrices */ + const double a = Q->forward.s11; + const double b = Q->forward.s12; + const double c = Q->forward.s13; + const double d = Q->forward.s21; + const double e = Q->forward.s22; + const double f = Q->forward.s23; + const double g = Q->forward.s31; + const double h = Q->forward.s32; + const double i = Q->forward.s33; + const double A = e * i - f * h; + const double B = -(d * i - f * g); + const double C = (d * h - e * g); + const double D = -(b * i - c * h); + const double E = (a * i - c * g); + const double F = -(a * h - b * g); + const double G = b * f - c * e; + const double H = -(a * f - c * d); + const double I = a * e - b * d; + const double det = a * A + b * B + c * C; + if( det == 0.0 || Q->forward.tscale == 0.0 ) { + if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_DEBUG) { + proj_log_debug(P, "Affine: matrix non invertible"); + } + P->inv4d = nullptr; + P->inv3d = nullptr; + P->inv = nullptr; + } else { + Q->reverse.s11 = A / det; + Q->reverse.s12 = D / det; + Q->reverse.s13 = G / det; + Q->reverse.s21 = B / det; + Q->reverse.s22 = E / det; + Q->reverse.s23 = H / det; + Q->reverse.s31 = C / det; + Q->reverse.s32 = F / det; + Q->reverse.s33 = I / det; + Q->reverse.tscale = 1.0 / Q->forward.tscale; + } +} + +PJ *TRANSFORMATION(affine,0 /* no need for ellipsoid */) { + struct pj_opaque_affine *Q = initQ(); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = (void *) Q; + + P->fwd4d = forward_4d; + P->inv4d = reverse_4d; + P->fwd3d = forward_3d; + P->inv3d = reverse_3d; + P->fwd = forward_2d; + P->inv = reverse_2d; + + P->left = PJ_IO_UNITS_WHATEVER; + P->right = PJ_IO_UNITS_WHATEVER; + + /* read args */ + Q->xoff = pj_param(P->ctx, P->params, "dxoff").f; + Q->yoff = pj_param(P->ctx, P->params, "dyoff").f; + Q->zoff = pj_param(P->ctx, P->params, "dzoff").f; + Q->toff = pj_param(P->ctx, P->params, "dtoff").f; + + if(pj_param (P->ctx, P->params, "ts11").i) { + Q->forward.s11 = pj_param(P->ctx, P->params, "ds11").f; + } + Q->forward.s12 = pj_param(P->ctx, P->params, "ds12").f; + Q->forward.s13 = pj_param(P->ctx, P->params, "ds13").f; + Q->forward.s21 = pj_param(P->ctx, P->params, "ds21").f; + if(pj_param (P->ctx, P->params, "ts22").i) { + Q->forward.s22 = pj_param(P->ctx, P->params, "ds22").f; + } + Q->forward.s23 = pj_param(P->ctx, P->params, "ds23").f; + Q->forward.s31 = pj_param(P->ctx, P->params, "ds31").f; + Q->forward.s32 = pj_param(P->ctx, P->params, "ds32").f; + if(pj_param (P->ctx, P->params, "ts33").i) { + Q->forward.s33 = pj_param(P->ctx, P->params, "ds33").f; + } + if(pj_param (P->ctx, P->params, "ttscale").i) { + Q->forward.tscale = pj_param(P->ctx, P->params, "dtscale").f; + } + + computeReverseParameters(P); + + return P; +} + + +/* Arcsecond to radians */ +#define ARCSEC_TO_RAD (DEG_TO_RAD / 3600.0) + + +PJ *TRANSFORMATION(geogoffset,0 /* no need for ellipsoid */) { + struct pj_opaque_affine *Q = initQ(); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = (void *) Q; + + P->fwd4d = forward_4d; + P->inv4d = reverse_4d; + P->fwd3d = forward_3d; + P->inv3d = reverse_3d; + P->fwd = forward_2d; + P->inv = reverse_2d; + + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_ANGULAR; + + /* read args */ + Q->xoff = pj_param(P->ctx, P->params, "ddlon").f * ARCSEC_TO_RAD; + Q->yoff = pj_param(P->ctx, P->params, "ddlat").f * ARCSEC_TO_RAD; + Q->zoff = pj_param(P->ctx, P->params, "ddh").f; + + return P; +} diff --git a/src/transformations/deformation.cpp b/src/transformations/deformation.cpp new file mode 100644 index 00000000..6c30f21c --- /dev/null +++ b/src/transformations/deformation.cpp @@ -0,0 +1,325 @@ +/*********************************************************************** + + Kinematic datum shifting utilizing a deformation model + + Kristian Evers, 2017-10-29 + +************************************************************************ + +Perform datum shifts by means of a deformation/velocity model. + + X_out = X_in + (T_ct - T_obs)*DX + Y_out = Y_in + (T_ct - T_obs)*DY + Z_out = Z_in + (T_ct - T_obs)*DZ + + +The deformation operation takes cartesian coordinates as input and +returns cartesian coordinates as well. + +Corrections in the gridded model are in east, north, up (ENU) space. +Hence the input coordinates needs to be converted to ENU-space when +searching for corrections in the grid. The corrections are then converted +to cartesian XYZ-space and applied to the input coordinates (also in +cartesian space). + +A full deformation model is described by two grids, one for the horizontal +components and one for the vertical component. The horizontal grid is +stored in CTable/CTable2 and the vertical grid is stored in the GTX +format. The NTv2 format should not be used for this purpose since grid- +values are scaled upon reading. Both grids are expected to contain +grid-values in units of mm/year in ENU-space. + +************************************************************************ +* Copyright (c) 2017, 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. +* +***********************************************************************/ +#define PJ_LIB__ +#include +#include "proj.h" +#include "proj_internal.h" +#include "proj_math.h" +#include "projects.h" + +PROJ_HEAD(deformation, "Kinematic grid shift"); + +#define TOL 1e-8 +#define MAX_ITERATIONS 10 + +namespace { // anonymous namespace +struct pj_opaque { + double t_obs; + double t_epoch; + PJ *cart; +}; +} // anonymous namespace + +/********************************************************************************/ +static XYZ get_grid_shift(PJ* P, XYZ cartesian) { +/******************************************************************************** + Read correction values from grid. The cartesian input coordinates are + converted to geodetic coordinates in order look up the correction values + in the grid. Once the grid corrections are read we need to convert them + from ENU-space to cartesian XYZ-space. ENU -> XYZ formula described in: + + Nørbech, T., et al, 2003(?), "Transformation from a Common Nordic Reference + Frame to ETRS89 in Denmark, Finland, Norway, and Sweden – status report" + +********************************************************************************/ + PJ_COORD geodetic, shift, temp; + double sp, cp, sl, cl; + int previous_errno = proj_errno_reset(P); + + /* cartesian to geodetic */ + geodetic.lpz = pj_inv3d(cartesian, static_cast(P->opaque)->cart); + + /* look up correction values in grids */ + shift.lp = proj_hgrid_value(P, geodetic.lp); + shift.enu.u = proj_vgrid_value(P, geodetic.lp); + + if (proj_errno(P) == PJD_ERR_GRID_AREA) + proj_log_debug(P, "deformation: coordinate (%.3f, %.3f) outside deformation model", + proj_todeg(geodetic.lp.lam), proj_todeg(geodetic.lp.phi)); + + /* grid values are stored as mm/yr, we need m/yr */ + shift.xyz.x /= 1000; + shift.xyz.y /= 1000; + shift.xyz.z /= 1000; + + /* pre-calc cosines and sines */ + sp = sin(geodetic.lp.phi); + cp = cos(geodetic.lp.phi); + sl = sin(geodetic.lp.lam); + cl = cos(geodetic.lp.lam); + + /* ENU -> XYZ */ + temp.xyz.x = -sp*cl*shift.enu.n - sl*shift.enu.e + cp*cl*shift.enu.u; + temp.xyz.y = -sp*sl*shift.enu.n + cl*shift.enu.e + cp*sl*shift.enu.u; + temp.xyz.z = cp*shift.enu.n + sp*shift.enu.u; + + shift.xyz = temp.xyz; + + proj_errno_restore(P, previous_errno); + + return shift.xyz; +} + +/********************************************************************************/ +static XYZ reverse_shift(PJ *P, XYZ input, double dt) { +/******************************************************************************** + Iteratively determine the reverse grid shift correction values. +*********************************************************************************/ + XYZ out, delta, dif; + double z0; + int i = MAX_ITERATIONS; + + delta = get_grid_shift(P, input); + + /* Store the origial z shift for later application */ + z0 = delta.z; + + /* When iterating to find the best horizontal coordinate we also carry */ + /* along the z-component, since we need it for the cartesian -> geodetic */ + /* conversion. The z-component adjustment is overwritten with z0 after */ + /* the loop has finished. */ + out.x = input.x - dt*delta.x; + out.y = input.y - dt*delta.y; + out.z = input.z + dt*delta.z; + + do { + delta = get_grid_shift(P, out); + + if (delta.x == HUGE_VAL) + break; + + dif.x = out.x + dt*delta.x - input.x; + dif.y = out.y + dt*delta.y - input.y; + dif.z = out.z - dt*delta.z - input.z; + out.x += dif.x; + out.y += dif.y; + out.z += dif.z; + + } while ( --i && hypot(dif.x, dif.y) > TOL ); + + out.z = input.z - dt*z0; + + return out; +} + +static XYZ forward_3d(LPZ lpz, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + PJ_COORD out, in; + XYZ shift; + double dt = 0.0; + in.lpz = lpz; + out = in; + + if (Q->t_obs != HUGE_VAL) { + dt = Q->t_epoch - Q->t_obs; + } else { + out = proj_coord_error(); /* in the 3D case +t_obs must be specified */ + proj_log_debug(P, "deformation: +t_obs must be specified"); + return out.xyz; + } + + shift = get_grid_shift(P, in.xyz); + + out.xyz.x += dt * shift.x; + out.xyz.y += dt * shift.y; + out.xyz.z += dt * shift.z; + + return out.xyz; +} + + +static PJ_COORD forward_4d(PJ_COORD in, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + double dt; + XYZ shift; + PJ_COORD out = in; + + if (Q->t_obs != HUGE_VAL) { + dt = Q->t_epoch - Q->t_obs; + } else { + dt = Q->t_epoch - in.xyzt.t; + } + + shift = get_grid_shift(P, in.xyz); + + out.xyzt.x += dt*shift.x; + out.xyzt.y += dt*shift.y; + out.xyzt.z += dt*shift.z; + + + return out; +} + + +static LPZ reverse_3d(XYZ in, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + PJ_COORD out; + double dt = 0.0; + out.xyz = in; + + if (Q->t_obs != HUGE_VAL) { + dt = Q->t_epoch - Q->t_obs; + } else { + out = proj_coord_error(); /* in the 3D case +t_obs must be specified */ + proj_log_debug(P, "deformation: +t_obs must be specified"); + return out.lpz; + } + + out.xyz = reverse_shift(P, in, dt); + + return out.lpz; +} + +static PJ_COORD reverse_4d(PJ_COORD in, PJ *P) { + struct pj_opaque *Q = (struct pj_opaque *) P->opaque; + PJ_COORD out = in; + double dt; + + + if (Q->t_obs != HUGE_VAL) { + dt = Q->t_epoch - Q->t_obs; + } else { + dt = Q->t_epoch - in.xyzt.t; + } + + out.xyz = reverse_shift(P, in.xyz, dt); + return out; +} + +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)->cart) + static_cast(P->opaque)->cart->destructor (static_cast(P->opaque)->cart, errlev); + + return pj_default_destructor(P, errlev); +} + + +PJ *TRANSFORMATION(deformation,1) { + int has_xy_grids = 0; + int has_z_grids = 0; + struct pj_opaque *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return destructor(P, ENOMEM); + P->opaque = (void *) Q; + + Q->cart = proj_create(P->ctx, "+proj=cart"); + if (Q->cart == nullptr) + return destructor(P, ENOMEM); + + /* inherit ellipsoid definition from P to Q->cart */ + pj_inherit_ellipsoid_def (P, Q->cart); + + has_xy_grids = pj_param(P->ctx, P->params, "txy_grids").i; + has_z_grids = pj_param(P->ctx, P->params, "tz_grids").i; + + /* Build gridlists. Both horizontal and vertical grids are mandatory. */ + if (!has_xy_grids || !has_z_grids) { + proj_log_error(P, "deformation: Both +xy_grids and +z_grids should be specified."); + return destructor(P, PJD_ERR_NO_ARGS ); + } + + proj_hgrid_init(P, "xy_grids"); + if (proj_errno(P)) { + proj_log_error(P, "deformation: could not find requested xy_grid(s)."); + return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID); + } + + proj_vgrid_init(P, "z_grids"); + if (proj_errno(P)) { + proj_log_error(P, "deformation: could not find requested z_grid(s)."); + return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID); + } + + Q->t_obs = HUGE_VAL; + if (pj_param(P->ctx, P->params, "tt_obs").i) { + Q->t_obs = pj_param(P->ctx, P->params, "dt_obs").f; + } + + if (pj_param(P->ctx, P->params, "tt_epoch").i) { + Q->t_epoch = pj_param(P->ctx, P->params, "dt_epoch").f; + } else { + proj_log_error(P, "deformation: +t_epoch parameter missing."); + return destructor(P, PJD_ERR_MISSING_ARGS); + } + + P->fwd4d = forward_4d; + P->inv4d = reverse_4d; + P->fwd3d = forward_3d; + P->inv3d = reverse_3d; + P->fwd = nullptr; + P->inv = nullptr; + + P->left = PJ_IO_UNITS_CARTESIAN; + P->right = PJ_IO_UNITS_CARTESIAN; + P->destructor = destructor; + + return P; +} + diff --git a/src/transformations/helmert.cpp b/src/transformations/helmert.cpp new file mode 100644 index 00000000..4a3abf4e --- /dev/null +++ b/src/transformations/helmert.cpp @@ -0,0 +1,755 @@ +/*********************************************************************** + + 3-, 4-and 7-parameter shifts, and their 6-, 8- + and 14-parameter kinematic counterparts. + + Thomas Knudsen, 2016-05-24 + +************************************************************************ + + Implements 3(6)-, 4(8) and 7(14)-parameter Helmert transformations for + 3D data. + + Also incorporates Molodensky-Badekas variant of 7-parameter Helmert + transformation, where the rotation is not applied regarding the centre + of the spheroid, but given a reference point. + + Primarily useful for implementation of datum shifts in transformation + pipelines. + +************************************************************************ + +Thomas Knudsen, thokn@sdfe.dk, 2016-05-24/06-05 +Kristian Evers, kreve@sdfe.dk, 2017-05-01 +Even Rouault, even.roault@spatialys.com +Last update: 2018-10-26 + +************************************************************************ +* Copyright (c) 2016, Thomas Knudsen / SDFE +* +* 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_internal.h" +#include "projects.h" +#include "geocent.h" + +PROJ_HEAD(helmert, "3(6)-, 4(8)- and 7(14)-parameter Helmert shift"); +PROJ_HEAD(molobadekas, "Molodensky-Badekas transformation"); + +static XYZ helmert_forward_3d (LPZ lpz, PJ *P); +static LPZ helmert_reverse_3d (XYZ xyz, PJ *P); + + + +/***********************************************************************/ +namespace { // anonymous namespace +struct pj_opaque_helmert { +/************************************************************************ + Projection specific elements for the "helmert" PJ object +************************************************************************/ + XYZ xyz; + XYZ xyz_0; + XYZ dxyz; + XYZ refp; + PJ_OPK opk; + PJ_OPK opk_0; + PJ_OPK dopk; + double scale; + double scale_0; + double dscale; + double theta; + double theta_0; + double dtheta; + double R[3][3]; + double t_epoch, t_obs; + int no_rotation, exact, fourparam; + int is_position_vector; /* 1 = position_vector, 0 = coordinate_frame */ +}; +} // anonymous namespace + + +/* Make the maths of the rotation operations somewhat more readable and textbook like */ +#define R00 (Q->R[0][0]) +#define R01 (Q->R[0][1]) +#define R02 (Q->R[0][2]) + +#define R10 (Q->R[1][0]) +#define R11 (Q->R[1][1]) +#define R12 (Q->R[1][2]) + +#define R20 (Q->R[2][0]) +#define R21 (Q->R[2][1]) +#define R22 (Q->R[2][2]) + +/**************************************************************************/ +static void update_parameters(PJ *P) { +/*************************************************************************** + + Update transformation parameters. + --------------------------------- + + The 14-parameter Helmert transformation is at it's core the same as the + 7-parameter transformation, since the transformation parameters are + projected forward or backwards in time via the rate of changes of the + parameters. The transformation parameters are calculated for a specific + epoch before the actual Helmert transformation is carried out. + + The transformation parameters are updated with the following equation [0]: + + . + P(t) = P(EPOCH) + P * (t - EPOCH) + + . + where EPOCH is the epoch indicated in the above table and P is the rate + of that parameter. + + [0] http://itrf.ign.fr/doc_ITRF/Transfo-ITRF2008_ITRFs.txt + +*******************************************************************************/ + + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; + double dt = Q->t_obs - Q->t_epoch; + + Q->xyz.x = Q->xyz_0.x + Q->dxyz.x * dt; + Q->xyz.y = Q->xyz_0.y + Q->dxyz.y * dt; + Q->xyz.z = Q->xyz_0.z + Q->dxyz.z * dt; + + Q->opk.o = Q->opk_0.o + Q->dopk.o * dt; + Q->opk.p = Q->opk_0.p + Q->dopk.p * dt; + Q->opk.k = Q->opk_0.k + Q->dopk.k * dt; + + Q->scale = Q->scale_0 + Q->dscale * dt; + + Q->theta = Q->theta_0 + Q->dtheta * dt; + + /* debugging output */ + if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_TRACE) { + proj_log_trace(P, "Transformation parameters for observation " + "t_obs=%g (t_epoch=%g):", Q->t_obs, Q->t_epoch); + proj_log_trace(P, "x: %g", Q->xyz.x); + proj_log_trace(P, "y: %g", Q->xyz.y); + proj_log_trace(P, "z: %g", Q->xyz.z); + proj_log_trace(P, "s: %g", Q->scale*1e-6); + proj_log_trace(P, "rx: %g", Q->opk.o); + proj_log_trace(P, "ry: %g", Q->opk.p); + proj_log_trace(P, "rz: %g", Q->opk.k); + proj_log_trace(P, "theta: %g", Q->theta); + } +} + +/**************************************************************************/ +static void build_rot_matrix(PJ *P) { +/*************************************************************************** + + Build rotation matrix. + ---------------------- + + Here we rename rotation indices from omega, phi, kappa (opk), to + fi (i.e. phi), theta, psi (ftp), in order to reduce the mental agility + needed to implement the expression for the rotation matrix derived over + at https://en.wikipedia.org/wiki/Rotation_formalisms_in_three_dimensions + The relevant section is Euler angles ( z-’-x" intrinsic) -> Rotation matrix + + By default small angle approximations are used: + The matrix elements are approximated by expanding the trigonometric + functions to linear order (i.e. cos(x) = 1, sin(x) = x), and discarding + products of second order. + + This was a useful hack when calculating by hand was the only option, + but in general, today, should be avoided because: + + 1. It does not save much computation time, as the rotation matrix + is built only once and probably used many times (except when + transforming spatio-temporal coordinates). + + 2. The error induced may be too large for ultra high accuracy + applications: the Earth is huge and the linear error is + approximately the angular error multiplied by the Earth radius. + + However, in many cases the approximation is necessary, since it has + been used historically: Rotation angles from older published datum + shifts may actually be a least squares fit to the linearized rotation + approximation, hence not being strictly valid for deriving the exact + rotation matrix. In fact, most publicly available transformation + parameters are based on the approximate Helmert transform, which is why + we use that as the default setting, even though it is more correct to + use the exact form of the equations. + + So in order to fit historically derived coordinates, the access to + the approximate rotation matrix is necessary - at least in principle. + + Also, when using any published datum transformation information, one + should always check which convention (exact or approximate rotation + matrix) is expected, and whether the induced error for selecting + the opposite convention is acceptable (which it often is). + + + Sign conventions + ---------------- + + Take care: Two different sign conventions exist for the rotation terms. + + Conceptually they relate to whether we rotate the coordinate system + or the "position vector" (the vector going from the coordinate system + origin to the point being transformed, i.e. the point coordinates + interpreted as vector coordinates). + + Switching between the "position vector" and "coordinate system" + conventions is simply a matter of switching the sign of the rotation + angles, which algebraically also translates into a transposition of + the rotation matrix. + + Hence, as geodetic constants should preferably be referred to exactly + as published, the "convention" option provides the ability to switch + between the conventions. + +***************************************************************************/ + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; + + double f, t, p; /* phi/fi , theta, psi */ + double cf, ct, cp; /* cos (fi, theta, psi) */ + double sf, st, sp; /* sin (fi, theta, psi) */ + + /* rename (omega, phi, kappa) to (fi, theta, psi) */ + f = Q->opk.o; + t = Q->opk.p; + p = Q->opk.k; + + /* Those equations are given assuming coordinate frame convention. */ + /* For the position vector convention, we transpose the matrix just after. */ + if (Q->exact) { + cf = cos(f); + sf = sin(f); + ct = cos(t); + st = sin(t); + cp = cos(p); + sp = sin(p); + + + R00 = ct*cp; + R01 = cf*sp + sf*st*cp; + R02 = sf*sp - cf*st*cp; + + R10 = -ct*sp; + R11 = cf*cp - sf*st*sp; + R12 = sf*cp + cf*st*sp; + + R20 = st; + R21 = -sf*ct; + R22 = cf*ct; + } else{ + R00 = 1; + R01 = p; + R02 = -t; + + R10 = -p; + R11 = 1; + R12 = f; + + R20 = t; + R21 = -f; + R22 = 1; + } + + + /* + For comparison: Description from Engsager/Poder implementation + in set_dtm_1.c (trlib) + + DATUM SHIFT: + TO = scale * ROTZ * ROTY * ROTX * FROM + TRANSLA + + ( cz sz 0) (cy 0 -sy) (1 0 0) + ROTZ=(-sz cz 0), ROTY=(0 1 0), ROTX=(0 cx sx) + ( 0 0 1) (sy 0 cy) (0 -sx cx) + + trp->r11 = cos_ry*cos_rz; + trp->r12 = cos_rx*sin_rz + sin_rx*sin_ry*cos_rz; + trp->r13 = sin_rx*sin_rz - cos_rx*sin_ry*cos_rz; + + trp->r21 = -cos_ry*sin_rz; + trp->r22 = cos_rx*cos_rz - sin_rx*sin_ry*sin_rz; + trp->r23 = sin_rx*cos_rz + cos_rx*sin_ry*sin_rz; + + trp->r31 = sin_ry; + trp->r32 = -sin_rx*cos_ry; + trp->r33 = cos_rx*cos_ry; + + trp->scale = 1.0 + scale; + */ + + + if (Q->is_position_vector) { + double r; + r = R01; R01 = R10; R10 = r; + r = R02; R02 = R20; R20 = r; + r = R12; R12 = R21; R21 = r; + } + + /* some debugging output */ + if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_TRACE) { + proj_log_trace(P, "Rotation Matrix:"); + proj_log_trace(P, " | % 6.6g % 6.6g % 6.6g |", R00, R01, R02); + proj_log_trace(P, " | % 6.6g % 6.6g % 6.6g |", R10, R11, R12); + proj_log_trace(P, " | % 6.6g % 6.6g % 6.6g |", R20, R21, R22); + } +} + + + + +/***********************************************************************/ +static XY helmert_forward (LP lp, PJ *P) { +/***********************************************************************/ + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + double x, y, cr, sr; + point.lp = lp; + + cr = cos(Q->theta) * Q->scale; + sr = sin(Q->theta) * Q->scale; + x = point.xy.x; + y = point.xy.y; + + point.xy.x = cr*x + sr*y + Q->xyz_0.x; + point.xy.y = -sr*x + cr*y + Q->xyz_0.y; + + return point.xy; +} + + +/***********************************************************************/ +static LP helmert_reverse (XY xy, PJ *P) { +/***********************************************************************/ + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + double x, y, sr, cr; + point.xy = xy; + + cr = cos(Q->theta) / Q->scale; + sr = sin(Q->theta) / Q->scale; + x = point.xy.x - Q->xyz_0.x; + y = point.xy.y - Q->xyz_0.y; + + point.xy.x = x*cr - y*sr; + point.xy.y = x*sr + y*cr; + + return point.lp; +} + + +/***********************************************************************/ +static XYZ helmert_forward_3d (LPZ lpz, PJ *P) { +/***********************************************************************/ + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + double X, Y, Z, scale; + + point.lpz = lpz; + + if (Q->fourparam) { + point.xy = helmert_forward(point.lp, P); + return point.xyz; + } + + if (Q->no_rotation) { + point.xyz.x = lpz.lam + Q->xyz.x; + point.xyz.y = lpz.phi + Q->xyz.y; + point.xyz.z = lpz.z + Q->xyz.z; + return point.xyz; + } + + scale = 1 + Q->scale * 1e-6; + + X = lpz.lam - Q->refp.x; + Y = lpz.phi - Q->refp.y; + Z = lpz.z - Q->refp.z; + + + point.xyz.x = scale * ( R00 * X + R01 * Y + R02 * Z); + point.xyz.y = scale * ( R10 * X + R11 * Y + R12 * Z); + point.xyz.z = scale * ( R20 * X + R21 * Y + R22 * Z); + + point.xyz.x += Q->xyz.x; /* for Molodensky-Badekas, Q->xyz already incorporates the Q->refp offset */ + point.xyz.y += Q->xyz.y; + point.xyz.z += Q->xyz.z; + + return point.xyz; +} + + +/***********************************************************************/ +static LPZ helmert_reverse_3d (XYZ xyz, PJ *P) { +/***********************************************************************/ + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + double X, Y, Z, scale; + + point.xyz = xyz; + + if (Q->fourparam) { + point.lp = helmert_reverse(point.xy, P); + return point.lpz; + } + + if (Q->no_rotation) { + point.xyz.x = xyz.x - Q->xyz.x; + point.xyz.y = xyz.y - Q->xyz.y; + point.xyz.z = xyz.z - Q->xyz.z; + return point.lpz; + } + + scale = 1 + Q->scale * 1e-6; + + /* Unscale and deoffset */ + X = (xyz.x - Q->xyz.x) / scale; + Y = (xyz.y - Q->xyz.y) / scale; + Z = (xyz.z - Q->xyz.z) / scale; + + /* Inverse rotation through transpose multiplication */ + point.xyz.x = ( R00 * X + R10 * Y + R20 * Z) + Q->refp.x; + point.xyz.y = ( R01 * X + R11 * Y + R21 * Z) + Q->refp.y; + point.xyz.z = ( R02 * X + R12 * Y + R22 * Z) + Q->refp.z; + + return point.lpz; +} + + +static PJ_COORD helmert_forward_4d (PJ_COORD point, PJ *P) { + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; + + /* We only need to rebuild the rotation matrix if the + * observation time is different from the last call */ + double t_obs = (point.xyzt.t == HUGE_VAL) ? Q->t_epoch : point.xyzt.t; + if (t_obs != Q->t_obs) { + Q->t_obs = t_obs; + update_parameters(P); + build_rot_matrix(P); + } + + point.xyz = helmert_forward_3d (point.lpz, P); + + return point; +} + + +static PJ_COORD helmert_reverse_4d (PJ_COORD point, PJ *P) { + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *) P->opaque; + + /* We only need to rebuild the rotation matrix if the + * observation time is different from the last call */ + double t_obs = (point.xyzt.t == HUGE_VAL) ? Q->t_epoch : point.xyzt.t; + if (t_obs != Q->t_obs) { + Q->t_obs = t_obs; + update_parameters(P); + build_rot_matrix(P); + } + + point.lpz = helmert_reverse_3d (point.xyz, P); + + return point; +} + +/* Arcsecond to radians */ +#define ARCSEC_TO_RAD (DEG_TO_RAD / 3600.0) + + +static PJ* init_helmert_six_parameters(PJ* P) { + struct pj_opaque_helmert *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque_helmert))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = (void *) Q; + + /* In most cases, we work on 3D cartesian coordinates */ + P->left = PJ_IO_UNITS_CARTESIAN; + P->right = PJ_IO_UNITS_CARTESIAN; + + /* Translations */ + if (pj_param (P->ctx, P->params, "tx").i) + Q->xyz_0.x = pj_param (P->ctx, P->params, "dx").f; + + if (pj_param (P->ctx, P->params, "ty").i) + Q->xyz_0.y = pj_param (P->ctx, P->params, "dy").f; + + if (pj_param (P->ctx, P->params, "tz").i) + Q->xyz_0.z = pj_param (P->ctx, P->params, "dz").f; + + /* Rotations */ + if (pj_param (P->ctx, P->params, "trx").i) + Q->opk_0.o = pj_param (P->ctx, P->params, "drx").f * ARCSEC_TO_RAD; + + if (pj_param (P->ctx, P->params, "try").i) + Q->opk_0.p = pj_param (P->ctx, P->params, "dry").f * ARCSEC_TO_RAD; + + if (pj_param (P->ctx, P->params, "trz").i) + Q->opk_0.k = pj_param (P->ctx, P->params, "drz").f * ARCSEC_TO_RAD; + + /* Use small angle approximations? */ + if (pj_param (P->ctx, P->params, "bexact").i) + Q->exact = 1; + + return P; +} + + +static PJ* read_convention(PJ* P) { + + struct pj_opaque_helmert *Q = (struct pj_opaque_helmert *)P->opaque; + + /* In case there are rotational terms, we require an explicit convention + * to be provided. */ + if (!Q->no_rotation) { + const char* convention = pj_param (P->ctx, P->params, "sconvention").s; + if( !convention ) { + proj_log_error (P, "helmert: missing 'convention' argument"); + return pj_default_destructor (P, PJD_ERR_MISSING_ARGS); + } + if( strcmp(convention, "position_vector") == 0 ) { + Q->is_position_vector = 1; + } + else if( strcmp(convention, "coordinate_frame") == 0 ) { + Q->is_position_vector = 0; + } + else { + proj_log_error (P, "helmert: invalid value for 'convention' argument"); + return pj_default_destructor (P, PJD_ERR_INVALID_ARG); + } + + /* historically towgs84 in PROJ has always been using position_vector + * convention. Accepting coordinate_frame would be confusing. */ + if (pj_param_exists (P->params, "towgs84")) { + if( !Q->is_position_vector ) { + proj_log_error (P, "helmert: towgs84 should only be used with " + "convention=position_vector"); + return pj_default_destructor (P, PJD_ERR_INVALID_ARG); + } + } + } + + return P; +} + + +/***********************************************************************/ +PJ *TRANSFORMATION(helmert, 0) { +/***********************************************************************/ + + struct pj_opaque_helmert *Q; + + if( !init_helmert_six_parameters(P) ) { + return nullptr; + } + + /* In the 2D case, the coordinates are projected */ + if (pj_param_exists (P->params, "theta")) { + P->left = PJ_IO_UNITS_PROJECTED; + P->right = PJ_IO_UNITS_PROJECTED; + } + + P->fwd4d = helmert_forward_4d; + P->inv4d = helmert_reverse_4d; + P->fwd3d = helmert_forward_3d; + P->inv3d = helmert_reverse_3d; + P->fwd = helmert_forward; + P->inv = helmert_reverse; + + Q = (struct pj_opaque_helmert *)P->opaque; + + /* Detect obsolete transpose flag and error out if found */ + if (pj_param (P->ctx, P->params, "ttranspose").i) { + proj_log_error (P, "helmert: 'transpose' argument is no longer valid. " + "Use convention=position_vector/coordinate_frame"); + return pj_default_destructor (P, PJD_ERR_INVALID_ARG); + } + + /* Support the classic PROJ towgs84 parameter, but allow later overrides.*/ + /* Note that if towgs84 is specified, the datum_params array is set up */ + /* for us automagically by the pj_datum_set call in pj_init_ctx */ + if (pj_param_exists (P->params, "towgs84")) { + Q->xyz_0.x = P->datum_params[0]; + Q->xyz_0.y = P->datum_params[1]; + Q->xyz_0.z = P->datum_params[2]; + + Q->opk_0.o = P->datum_params[3]; + Q->opk_0.p = P->datum_params[4]; + Q->opk_0.k = P->datum_params[5]; + + /* We must undo conversion to absolute scale from pj_datum_set */ + if (0==P->datum_params[6]) + Q->scale_0 = 0; + else + Q->scale_0 = (P->datum_params[6] - 1) * 1e6; + } + + if (pj_param (P->ctx, P->params, "ttheta").i) { + Q->theta_0 = pj_param (P->ctx, P->params, "dtheta").f * ARCSEC_TO_RAD; + Q->fourparam = 1; + Q->scale_0 = 1.0; /* default scale for the 4-param shift */ + } + + /* Scale */ + if (pj_param (P->ctx, P->params, "ts").i) { + Q->scale_0 = pj_param (P->ctx, P->params, "ds").f; + if (pj_param (P->ctx, P->params, "ttheta").i && Q->scale_0 == 0.0) + return pj_default_destructor (P, PJD_ERR_INVALID_SCALE); + } + + /* Translation rates */ + if (pj_param(P->ctx, P->params, "tdx").i) + Q->dxyz.x = pj_param (P->ctx, P->params, "ddx").f; + + if (pj_param(P->ctx, P->params, "tdy").i) + Q->dxyz.y = pj_param (P->ctx, P->params, "ddy").f; + + if (pj_param(P->ctx, P->params, "tdz").i) + Q->dxyz.z = pj_param (P->ctx, P->params, "ddz").f; + + /* Rotations rates */ + if (pj_param (P->ctx, P->params, "tdrx").i) + Q->dopk.o = pj_param (P->ctx, P->params, "ddrx").f * ARCSEC_TO_RAD; + + if (pj_param (P->ctx, P->params, "tdry").i) + Q->dopk.p = pj_param (P->ctx, P->params, "ddry").f * ARCSEC_TO_RAD; + + if (pj_param (P->ctx, P->params, "tdrz").i) + Q->dopk.k = pj_param (P->ctx, P->params, "ddrz").f * ARCSEC_TO_RAD; + + if (pj_param (P->ctx, P->params, "tdtheta").i) + Q->dtheta = pj_param (P->ctx, P->params, "ddtheta").f * ARCSEC_TO_RAD; + + /* Scale rate */ + if (pj_param (P->ctx, P->params, "tds").i) + Q->dscale = pj_param (P->ctx, P->params, "dds").f; + + + /* Epoch */ + if (pj_param(P->ctx, P->params, "tt_epoch").i) + Q->t_epoch = pj_param (P->ctx, P->params, "dt_epoch").f; + + if (pj_param(P->ctx, P->params, "tt_obs").i) + Q->t_obs = pj_param (P->ctx, P->params, "dt_obs").f; + + Q->xyz = Q->xyz_0; + Q->opk = Q->opk_0; + Q->scale = Q->scale_0; + Q->theta = Q->theta_0; + + if ((Q->opk.o==0) && (Q->opk.p==0) && (Q->opk.k==0) && (Q->scale==0) && + (Q->dopk.o==0) && (Q->dopk.p==0) && (Q->dopk.k==0)) { + Q->no_rotation = 1; + } + + if( !read_convention(P) ) { + return nullptr; + } + + /* Let's help with debugging */ + if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_DEBUG) { + proj_log_debug(P, "Helmert parameters:"); + proj_log_debug(P, "x= %8.5f y= %8.5f z= %8.5f", Q->xyz.x, Q->xyz.y, Q->xyz.z); + proj_log_debug(P, "rx= %8.5f ry= %8.5f rz= %8.5f", + Q->opk.o / ARCSEC_TO_RAD, Q->opk.p / ARCSEC_TO_RAD, Q->opk.k / ARCSEC_TO_RAD); + proj_log_debug(P, "s= %8.5f exact=%d%s", Q->scale, Q->exact, + Q->no_rotation ? "" : + Q->is_position_vector ? " convention=position_vector" : + " convention=coordinate_frame"); + proj_log_debug(P, "dx= %8.5f dy= %8.5f dz= %8.5f", Q->dxyz.x, Q->dxyz.y, Q->dxyz.z); + proj_log_debug(P, "drx=%8.5f dry=%8.5f drz=%8.5f", Q->dopk.o, Q->dopk.p, Q->dopk.k); + proj_log_debug(P, "ds= %8.5f t_epoch=%8.5f t_obs=%8.5f", Q->dscale, Q->t_epoch, Q->t_obs); + } + + if (Q->no_rotation) { + return P; + } + + update_parameters(P); + build_rot_matrix(P); + + return P; +} + + +/***********************************************************************/ +PJ *TRANSFORMATION(molobadekas, 0) { +/***********************************************************************/ + + struct pj_opaque_helmert *Q; + + if( !init_helmert_six_parameters(P) ) { + return nullptr; + } + + P->fwd3d = helmert_forward_3d; + P->inv3d = helmert_reverse_3d; + + Q = (struct pj_opaque_helmert *)P->opaque; + + /* Scale */ + if (pj_param (P->ctx, P->params, "ts").i) { + Q->scale_0 = pj_param (P->ctx, P->params, "ds").f; + } + + Q->opk = Q->opk_0; + Q->scale = Q->scale_0; + + if( !read_convention(P) ) { + return nullptr; + } + + /* Reference point */ + if (pj_param (P->ctx, P->params, "tpx").i) + Q->refp.x = pj_param (P->ctx, P->params, "dpx").f; + + if (pj_param (P->ctx, P->params, "tpy").i) + Q->refp.y = pj_param (P->ctx, P->params, "dpy").f; + + if (pj_param (P->ctx, P->params, "tpz").i) + Q->refp.z = pj_param (P->ctx, P->params, "dpz").f; + + + /* Let's help with debugging */ + if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_DEBUG) { + proj_log_debug(P, "Molodensky-Badekas parameters:"); + proj_log_debug(P, "x= %8.5f y= %8.5f z= %8.5f", Q->xyz_0.x, Q->xyz_0.y, Q->xyz_0.z); + proj_log_debug(P, "rx= %8.5f ry= %8.5f rz= %8.5f", + Q->opk.o / ARCSEC_TO_RAD, Q->opk.p / ARCSEC_TO_RAD, Q->opk.k / ARCSEC_TO_RAD); + proj_log_debug(P, "s= %8.5f exact=%d%s", Q->scale, Q->exact, + Q->is_position_vector ? " convention=position_vector" : + " convention=coordinate_frame"); + proj_log_debug(P, "px= %8.5f py= %8.5f pz= %8.5f", Q->refp.x, Q->refp.y, Q->refp.z); + } + + /* as an optimization, we incorporate the refp in the translation terms */ + Q->xyz_0.x += Q->refp.x; + Q->xyz_0.y += Q->refp.y; + Q->xyz_0.z += Q->refp.z; + + Q->xyz = Q->xyz_0; + + build_rot_matrix(P); + + return P; +} diff --git a/src/transformations/hgridshift.cpp b/src/transformations/hgridshift.cpp new file mode 100644 index 00000000..f0e57251 --- /dev/null +++ b/src/transformations/hgridshift.cpp @@ -0,0 +1,133 @@ +#define PJ_LIB__ + +#include +#include +#include +#include + +#include "proj_internal.h" +#include "projects.h" + +PROJ_HEAD(hgridshift, "Horizontal grid shift"); + +namespace { // anonymous namespace +struct pj_opaque_hgridshift { + double t_final; + double t_epoch; +}; +} // anonymous namespace + +static XYZ forward_3d(LPZ lpz, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + point.lpz = lpz; + + if (P->gridlist != nullptr) { + /* Only try the gridshift if at least one grid is loaded, + * otherwise just pass the coordinate through unchanged. */ + point.lp = proj_hgrid_apply(P, point.lp, PJ_FWD); + } + + return point.xyz; +} + + +static LPZ reverse_3d(XYZ xyz, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + point.xyz = xyz; + + if (P->gridlist != nullptr) { + /* Only try the gridshift if at least one grid is loaded, + * otherwise just pass the coordinate through unchanged. */ + point.lp = proj_hgrid_apply(P, point.lp, PJ_INV); + } + + return point.lpz; +} + +static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { + struct pj_opaque_hgridshift *Q = (struct pj_opaque_hgridshift *) P->opaque; + PJ_COORD point = obs; + + /* If transformation is not time restricted, we always call it */ + if (Q->t_final==0 || Q->t_epoch==0) { + point.xyz = forward_3d (obs.lpz, P); + return point; + } + + /* Time restricted - only apply transform if within time bracket */ + if (obs.lpzt.t < Q->t_epoch && Q->t_final > Q->t_epoch) + point.xyz = forward_3d (obs.lpz, P); + + + return point; +} + +static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { + struct pj_opaque_hgridshift *Q = (struct pj_opaque_hgridshift *) P->opaque; + PJ_COORD point = obs; + + /* If transformation is not time restricted, we always call it */ + if (Q->t_final==0 || Q->t_epoch==0) { + point.lpz = reverse_3d (obs.xyz, P); + return point; + } + + /* Time restricted - only apply transform if within time bracket */ + if (obs.lpzt.t < Q->t_epoch && Q->t_final > Q->t_epoch) + point.lpz = reverse_3d (obs.xyz, P); + + return point; +} + + +PJ *TRANSFORMATION(hgridshift,0) { + struct pj_opaque_hgridshift *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque_hgridshift))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = (void *) Q; + + P->fwd4d = forward_4d; + P->inv4d = reverse_4d; + P->fwd3d = forward_3d; + P->inv3d = reverse_3d; + P->fwd = nullptr; + P->inv = nullptr; + + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_ANGULAR; + + if (0==pj_param(P->ctx, P->params, "tgrids").i) { + proj_log_error(P, "hgridshift: +grids parameter missing."); + return pj_default_destructor (P, PJD_ERR_NO_ARGS); + } + + /* TODO: Refactor into shared function that can be used */ + /* by both vgridshift and hgridshift */ + if (pj_param(P->ctx, P->params, "tt_final").i) { + Q->t_final = pj_param (P->ctx, P->params, "dt_final").f; + if (Q->t_final == 0) { + /* a number wasn't passed to +t_final, let's see if it was "now" */ + /* and set the time accordingly. */ + if (!strcmp("now", pj_param(P->ctx, P->params, "st_final").s)) { + time_t now; + struct tm *date; + time(&now); + date = localtime(&now); + Q->t_final = 1900.0 + date->tm_year + date->tm_yday/365.0; + } + } + } + + if (pj_param(P->ctx, P->params, "tt_epoch").i) + Q->t_epoch = pj_param (P->ctx, P->params, "dt_epoch").f; + + + proj_hgrid_init(P, "grids"); + /* Was gridlist compiled properly? */ + if ( proj_errno(P) ) { + proj_log_error(P, "hgridshift: could not find required grid(s)."); + return pj_default_destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID); + } + + return P; +} diff --git a/src/transformations/horner.cpp b/src/transformations/horner.cpp new file mode 100644 index 00000000..73977de6 --- /dev/null +++ b/src/transformations/horner.cpp @@ -0,0 +1,513 @@ +/*********************************************************************** + + Interfacing to a classic piece of geodetic software + +************************************************************************ + + gen_pol is a highly efficient, classic implementation of a generic + 2D Horner's Scheme polynomial evaluation routine by Knud Poder and + Karsten Engsager, originating in the vivid geodetic environment at + what was then (1960-ish) the Danish Geodetic Institute. + + The original Poder/Engsager gen_pol implementation (where + the polynomial degree and two sets of polynomial coefficients + are packed together in one compound array, handled via a plain + double pointer) is compelling and "true to the code history": + + It has a beautiful classical 1960s ring to it, not unlike the + original fft implementations, which revolutionized spectral + analysis in twenty lines of code. + + The Poder coding sound, as classic 1960s as Phil Spector's Wall + of Sound, is beautiful and inimitable. + + On the other hand: For the uninitiated, the gen_pol code is hard + to follow, despite being compact. + + Also, since adding metadata and improving maintainability + of the code are among the implied goals of a current SDFE/DTU Space + project, the material in this file introduces a version with a + more modern (or at least 1990s) look, introducing a "double 2D + polynomial" data type, HORNER. + + Despite introducing a new data type for handling the polynomial + coefficients, great care has been taken to keep the coefficient + array organization identical to that of gen_pol. + + Hence, on one hand, the HORNER data type helps improving the + long term maintainability of the code by making the data + organization more mentally accessible. + + On the other hand, it allows us to preserve the business end of + the original gen_pol implementation - although not including the + famous "Poder dual autocheck" in all its enigmatic elegance. + + ********************************************************************** + + The material included here was written by Knud Poder, starting + around 1960, and Karsten Engsager, starting around 1970. It was + originally written in Algol 60, later (1980s) reimplemented in C. + + The HORNER data type interface, and the organization as a header + library was implemented by Thomas Knudsen, starting around 2015. + + *********************************************************************** + * + * Copyright (c) 2016, SDFE http://www.sdfe.dk / Thomas Knudsen / Karsten Engsager + * + * 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 +#include + +#include "proj_internal.h" +#include "projects.h" + +PROJ_HEAD(horner, "Horner polynomial evaluation"); + +/* make horner.h interface with proj's memory management */ +#define horner_dealloc(x) pj_dealloc(x) +#define horner_calloc(n,x) pj_calloc(n,x) + +namespace { // anonymous namespace +struct horner { + int uneg; /* u axis negated? */ + int vneg; /* v axis negated? */ + int order; /* maximum degree of polynomium */ + int coefs; /* number of coefficients for each polynomium */ + double range; /* radius of the region of validity */ + + double *fwd_u; /* coefficients for the forward transformations */ + double *fwd_v; /* i.e. latitude/longitude to northing/easting */ + + double *inv_u; /* coefficients for the inverse transformations */ + double *inv_v; /* i.e. northing/easting to latitude/longitude */ + + double *fwd_c; /* coefficients for the complex forward transformations */ + double *inv_c; /* coefficients for the complex inverse transformations */ + + UV *fwd_origin; /* False longitude/latitude */ + UV *inv_origin; /* False easting/northing */ +}; +} // anonymous namespace + +typedef struct horner HORNER; +static UV horner_func (const HORNER *transformation, PJ_DIRECTION direction, UV position); +static HORNER *horner_alloc (size_t order, int complex_polynomia); +static void horner_free (HORNER *h); + +/* e.g. degree = 2: a + bx + cy + dxx + eyy + fxy, i.e. 6 coefficients */ +#define horner_number_of_coefficients(order) \ + (((order + 1)*(order + 2)/2)) + + +static void horner_free (HORNER *h) { + horner_dealloc (h->inv_v); + horner_dealloc (h->inv_u); + horner_dealloc (h->fwd_v); + horner_dealloc (h->fwd_u); + horner_dealloc (h->fwd_c); + horner_dealloc (h->inv_c); + horner_dealloc (h->fwd_origin); + horner_dealloc (h->inv_origin); + horner_dealloc (h); +} + + +static HORNER *horner_alloc (size_t order, int complex_polynomia) { + /* size_t is unsigned, so we need not check for order > 0 */ + int n = (int)horner_number_of_coefficients(order); + int polynomia_ok = 0; + HORNER *h = static_cast(horner_calloc (1, sizeof (HORNER))); + + if (nullptr==h) + return nullptr; + + if (complex_polynomia) + n = 2*(int)order + 2; + h->order = (int)order; + h->coefs = n; + + if (complex_polynomia) { + h->fwd_c = static_cast(horner_calloc (n, sizeof(double))); + h->inv_c = static_cast(horner_calloc (n, sizeof(double))); + if (h->fwd_c && h->inv_c) + polynomia_ok = 1; + } + else { + h->fwd_u = static_cast(horner_calloc (n, sizeof(double))); + h->fwd_v = static_cast(horner_calloc (n, sizeof(double))); + h->inv_u = static_cast(horner_calloc (n, sizeof(double))); + h->inv_v = static_cast(horner_calloc (n, sizeof(double))); + if (h->fwd_u && h->fwd_v && h->inv_u && h->inv_v) + polynomia_ok = 1; + } + + h->fwd_origin = static_cast(horner_calloc (1, sizeof(UV))); + h->inv_origin = static_cast(horner_calloc (1, sizeof(UV))); + + if (polynomia_ok && h->fwd_origin && h->inv_origin) + return h; + + /* safe, since all pointers are null-initialized (by calloc) */ + horner_free (h); + return nullptr; +} + + + + +/**********************************************************************/ +static UV horner_func (const HORNER *transformation, PJ_DIRECTION direction, UV position) { +/*********************************************************************** + +A reimplementation of the classic Engsager/Poder 2D Horner polynomial +evaluation engine "gen_pol". + +This version omits the inimitable Poder "dual autocheck"-machinery, +which here is intended to be implemented at a higher level of the +library: We separate the polynomial evaluation from the quality +control (which, given the limited MTBF for "computing machinery", +typical when Knud Poder invented the dual autocheck method, +was not defensible at that time). + +Another difference from the original version is that we return the +result on the stack, rather than accepting pointers to result variables +as input. This results in code that is easy to read: + + projected = horner (s34j, 1, geographic); + geographic = horner (s34j, -1, projected ); + +and experiments have shown that on contemporary architectures, the time +taken for returning even comparatively large objects on the stack (and +the UV is not that large - typically only 16 bytes) is negligibly +different from passing two pointers (i.e. typically also 16 bytes) the +other way. + +The polynomium has the form: + +P = sum (i = [0 : order]) + sum (j = [0 : order - i]) + pow(par_1, i) * pow(par_2, j) * coef(index(order, i, j)) + +For numerical stability, the summation is carried out backwards, +summing the tiny high order elements first. + +***********************************************************************/ + + /* These variable names follow the Engsager/Poder implementation */ + int sz; /* Number of coefficients per polynomial */ + double *tcx, *tcy; /* Coefficient pointers */ + double range; /* Equivalent to the gen_pol's FLOATLIMIT constant */ + double n, e; + UV uv_error; + uv_error.u = uv_error.v = HUGE_VAL; + + if (nullptr==transformation) + return uv_error; + + /* Check for valid value of direction (-1, 0, 1) */ + switch (direction) { + case PJ_IDENT: /* no-op */ + return position; + case PJ_FWD: /* forward */ + case PJ_INV: /* inverse */ + break; + default: /* invalid */ + errno = EINVAL; + return uv_error; + } + + /* Prepare for double Horner */ + sz = horner_number_of_coefficients(transformation->order); + range = transformation->range; + + + if (direction==PJ_FWD) { /* forward */ + tcx = transformation->fwd_u + sz; + tcy = transformation->fwd_v + sz; + e = position.u - transformation->fwd_origin->u; + n = position.v - transformation->fwd_origin->v; + } else { /* inverse */ + tcx = transformation->inv_u + sz; + tcy = transformation->inv_v + sz; + e = position.u - transformation->inv_origin->u; + n = position.v - transformation->inv_origin->v; + } + + if ((fabs(n) > range) || (fabs(e) > range)) { + errno = EDOM; + return uv_error; + } + + /* The melody of this block is straight out of the great Engsager/Poder songbook */ + else { + int g = transformation->order; + int r = g, c; + double u, v, N, E; + + /* Double Horner's scheme: N = n*Cy*e -> yout, E = e*Cx*n -> xout */ + N = *--tcy; + E = *--tcx; + for (; r > 0; r--) { + u = *--tcy; + v = *--tcx; + for (c = g; c >= r; c--) { + u = n*u + *--tcy; + v = e*v + *--tcx; + } + N = e*N + u; + E = n*E + v; + } + + position.u = E; + position.v = N; + } + + return position; +} + + + + + + + +static PJ_COORD horner_forward_4d (PJ_COORD point, PJ *P) { + point.uv = horner_func ((HORNER *) P->opaque, PJ_FWD, point.uv); + return point; +} + +static PJ_COORD horner_reverse_4d (PJ_COORD point, PJ *P) { + point.uv = horner_func ((HORNER *) P->opaque, PJ_INV, point.uv); + return point; +} + + + + +/**********************************************************************/ +static UV complex_horner (const HORNER *transformation, PJ_DIRECTION direction, UV position) { +/*********************************************************************** + +A reimplementation of a classic Engsager/Poder Horner complex +polynomial evaluation engine. + +***********************************************************************/ + + /* These variable names follow the Engsager/Poder implementation */ + int sz; /* Number of coefficients */ + double *c, *cb; /* Coefficient pointers */ + double range; /* Equivalent to the gen_pol's FLOATLIMIT constant */ + double n, e, w, N, E; + UV uv_error; + uv_error.u = uv_error.v = HUGE_VAL; + + if (nullptr==transformation) + return uv_error; + + /* Check for valid value of direction (-1, 0, 1) */ + switch (direction) { + case PJ_IDENT: /* no-op */ + return position; + case PJ_FWD: /* forward */ + case PJ_INV: /* inverse */ + break; + default: /* invalid */ + errno = EINVAL; + return uv_error; + } + + /* Prepare for double Horner */ + sz = 2*transformation->order + 2; + range = transformation->range; + + if (direction==PJ_FWD) { /* forward */ + cb = transformation->fwd_c; + c = cb + sz; + e = position.u - transformation->fwd_origin->u; + n = position.v - transformation->fwd_origin->v; + if (transformation->uneg) + e = -e; + if (transformation->vneg) + n = -n; + } else { /* inverse */ + cb = transformation->inv_c; + c = cb + sz; + e = position.u - transformation->inv_origin->u; + n = position.v - transformation->inv_origin->v; + if (transformation->uneg) + e = -e; + if (transformation->vneg) + n = -n; + } + + if ((fabs(n) > range) || (fabs(e) > range)) { + errno = EDOM; + return uv_error; + } + + /* Everything's set up properly - now do the actual polynomium evaluation */ + E = *--c; + N = *--c; + while (c > cb) { + w = n*E + e*N + *--c; + N = n*N - e*E + *--c; + E = w; + } + + position.u = E; + position.v = N; + return position; +} + + + +static PJ_COORD complex_horner_forward_4d (PJ_COORD point, PJ *P) { + point.uv = complex_horner ((HORNER *) P->opaque, PJ_FWD, point.uv); + return point; +} + +static PJ_COORD complex_horner_reverse_4d (PJ_COORD point, PJ *P) { + point.uv = complex_horner ((HORNER *) P->opaque, PJ_INV, point.uv); + return point; +} + + +static PJ *horner_freeup (PJ *P, int errlev) { /* Destructor */ + if (nullptr==P) + return nullptr; + if (nullptr==P->opaque) + return pj_default_destructor (P, errlev); + horner_free ((HORNER *) P->opaque); + P->opaque = nullptr; + return pj_default_destructor (P, errlev); +} + + +static int parse_coefs (PJ *P, double *coefs, const char *param, int ncoefs) { + char *buf, *init, *next = nullptr; + int i; + + buf = static_cast(pj_calloc (strlen (param) + 2, sizeof(char))); + if (nullptr==buf) { + proj_log_error (P, "Horner: No memory left"); + return 0; + } + + sprintf (buf, "t%s", param); + if (0==pj_param (P->ctx, P->params, buf).i) { + pj_dealloc (buf); + return 0; + } + sprintf (buf, "s%s", param); + init = pj_param(P->ctx, P->params, buf).s; + pj_dealloc (buf); + + for (i = 0; i < ncoefs; i++) { + if (i > 0) { + if ( next == nullptr || ','!=*next) { + proj_log_error (P, "Horner: Malformed polynomium set %s. need %d coefs", param, ncoefs); + return 0; + } + init = ++next; + } + coefs[i] = pj_strtod (init, &next); + } + return 1; +} + + +/*********************************************************************/ +PJ *PROJECTION(horner) { +/*********************************************************************/ + int degree = 0, n, complex_polynomia = 0; + HORNER *Q; + P->fwd4d = horner_forward_4d; + P->inv4d = horner_reverse_4d; + P->fwd3d = nullptr; + P->inv3d = nullptr; + P->fwd = nullptr; + P->inv = nullptr; + P->left = P->right = PJ_IO_UNITS_PROJECTED; + P->destructor = horner_freeup; + + /* Polynomial degree specified? */ + if (pj_param (P->ctx, P->params, "tdeg").i) { /* degree specified? */ + degree = pj_param(P->ctx, P->params, "ideg").i; + if (degree < 0 || degree > 10000) { + /* What are reasonable minimum and maximums for degree? */ + proj_log_debug (P, "Horner: Degree is unreasonable: %d", degree); + return horner_freeup (P, PJD_ERR_INVALID_ARG); + } + } else { + proj_log_debug (P, "Horner: Must specify polynomial degree, (+deg=n)"); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + } + + if (pj_param (P->ctx, P->params, "tfwd_c").i || pj_param (P->ctx, P->params, "tinv_c").i) /* complex polynomium? */ + complex_polynomia = 1; + + Q = horner_alloc (degree, complex_polynomia); + if (Q == nullptr) + return horner_freeup (P, ENOMEM); + P->opaque = Q; + + if (complex_polynomia) { + /* Westings and/or southings? */ + Q->uneg = pj_param_exists (P->params, "uneg") ? 1 : 0; + Q->vneg = pj_param_exists (P->params, "vneg") ? 1 : 0; + + n = 2*degree + 2; + if (0==parse_coefs (P, Q->fwd_c, "fwd_c", n)) + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + if (0==parse_coefs (P, Q->inv_c, "inv_c", n)) + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + P->fwd4d = complex_horner_forward_4d; + P->inv4d = complex_horner_reverse_4d; + } + + else { + n = horner_number_of_coefficients (degree); + if (0==parse_coefs (P, Q->fwd_u, "fwd_u", n)) + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + if (0==parse_coefs (P, Q->fwd_v, "fwd_v", n)) + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + if (0==parse_coefs (P, Q->inv_u, "inv_u", n)) + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + if (0==parse_coefs (P, Q->inv_v, "inv_v", n)) + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + } + + if (0==parse_coefs (P, (double *)(Q->fwd_origin), "fwd_origin", 2)) + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + if (0==parse_coefs (P, (double *)(Q->inv_origin), "inv_origin", 2)) + return horner_freeup (P, PJD_ERR_MISSING_ARGS); + if (0==parse_coefs (P, &Q->range, "range", 1)) + Q->range = 500000; + + return P; +} diff --git a/src/transformations/molodensky.cpp b/src/transformations/molodensky.cpp new file mode 100644 index 00000000..91743fda --- /dev/null +++ b/src/transformations/molodensky.cpp @@ -0,0 +1,329 @@ +/*********************************************************************** + + (Abridged) Molodensky Transform + + Kristian Evers, 2017-07-07 + +************************************************************************ + + Implements the (abridged) Molodensky transformations for 2D and 3D + data. + + Primarily useful for implementation of datum shifts in transformation + pipelines. + + The code in this file is mostly based on + + The Standard and Abridged Molodensky Coordinate Transformation + Formulae, 2004, R.E. Deaking, + http://www.mygeodesy.id.au/documents/Molodensky%20V2.pdf + + + +************************************************************************ +* Copyright (c) 2017, Kristian Evers / SDFE +* +* 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 "proj_internal.h" +#include "projects.h" + +PROJ_HEAD(molodensky, "Molodensky transform"); + +static XYZ forward_3d(LPZ lpz, PJ *P); +static LPZ reverse_3d(XYZ xyz, PJ *P); + +namespace { // anonymous namespace +struct pj_opaque_molodensky { + double dx; + double dy; + double dz; + double da; + double df; + int abridged; +}; +} // anonymous namespace + + +static double RN (double a, double es, double phi) { +/********************************************************** + N(phi) - prime vertical radius of curvature + ------------------------------------------- + + This is basically the same function as in PJ_cart.c + should probably be refactored into it's own file at some + point. + +**********************************************************/ + double s = sin(phi); + if (es==0) + return a; + + return a / sqrt (1 - es*s*s); +} + + +static double RM (double a, double es, double phi) { +/********************************************************** + M(phi) - Meridian radius of curvature + ------------------------------------- + + Source: + + E.J Krakiwsky & D.B. Thomson, 1974, + GEODETIC POSITION COMPUTATIONS, + + Fredericton NB, Canada: + University of New Brunswick, + Department of Geodesy and Geomatics Engineering, + Lecture Notes No. 39, + 99 pp. + + http://www2.unb.ca/gge/Pubs/LN39.pdf + +**********************************************************/ + double s = sin(phi); + if (es==0) + return a; + + /* eq. 13a */ + if (phi == 0) + return a * (1-es); + + /* eq. 13b */ + if (fabs(phi) == M_PI_2) + return a / sqrt(1-es); + + /* eq. 13 */ + return (a * (1 - es) ) / pow(1 - es*s*s, 1.5); + +} + + +static LPZ calc_standard_params(LPZ lpz, PJ *P) { + struct pj_opaque_molodensky *Q = (struct pj_opaque_molodensky *) P->opaque; + double dphi, dlam, dh; + + /* sines and cosines */ + double slam = sin(lpz.lam); + double clam = cos(lpz.lam); + double sphi = sin(lpz.phi); + double cphi = cos(lpz.phi); + + /* ellipsoid parameters and differences */ + double f = P->f, a = P->a; + double dx = Q->dx, dy = Q->dy, dz = Q->dz; + double da = Q->da, df = Q->df; + + /* ellipsoid radii of curvature */ + double rho = RM(a, P->es, lpz.phi); + double nu = RN(a, P->e2s, lpz.phi); + + /* delta phi */ + dphi = (-dx*sphi*clam) - (dy*sphi*slam) + (dz*cphi) + + ((nu * P->es * sphi * cphi * da) / a) + + (sphi*cphi * ( rho/(1-f) + nu*(1-f))*df); + dphi /= (rho + lpz.z); + + /* delta lambda */ + dlam = (-dx*slam + dy*clam) / ((nu+lpz.z)*cphi); + + /* delta h */ + dh = dx*cphi*clam + dy*cphi*slam + dz*sphi - (a/nu)*da + nu*(1-f)*sphi*sphi*df; + + lpz.phi = dphi; + lpz.lam = dlam; + lpz.z = dh; + + return lpz; +} + + +static LPZ calc_abridged_params(LPZ lpz, PJ *P) { + struct pj_opaque_molodensky *Q = (struct pj_opaque_molodensky *) P->opaque; + double dphi, dlam, dh; + + /* sines and cosines */ + double slam = sin(lpz.lam); + double clam = cos(lpz.lam); + double sphi = sin(lpz.phi); + double cphi = cos(lpz.phi); + + /* ellipsoid parameters and differences */ + double dx = Q->dx, dy = Q->dy, dz = Q->dz; + double da = Q->da, df = Q->df; + double adffda = (P->a*df + P->f*da); + + /* delta phi */ + dphi = -dx*sphi*clam - dy*sphi*slam + dz*cphi + adffda*sin(2*lpz.phi); + dphi /= RM(P->a, P->es, lpz.phi); + + /* delta lambda */ + dlam = -dx*slam + dy*clam; + dlam /= RN(P->a, P->e2s, lpz.phi)*cphi; + + /* delta h */ + dh = dx*cphi*clam + dy*cphi*slam + dz*sphi - da + adffda*sphi*sphi; + + /* offset coordinate */ + lpz.phi = dphi; + lpz.lam = dlam; + lpz.z = dh; + + return lpz; +} + + +static XY forward_2d(LP lp, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + + point.lp = lp; + point.xyz = forward_3d(point.lpz, P); + + return point.xy; +} + + +static LP reverse_2d(XY xy, PJ *P) { + PJ_COORD point = {{0,0,0,0}}; + + point.xy = xy; + point.xyz.z = 0; + point.lpz = reverse_3d(point.xyz, P); + + return point.lp; +} + + +static XYZ forward_3d(LPZ lpz, PJ *P) { + struct pj_opaque_molodensky *Q = (struct pj_opaque_molodensky *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + + point.lpz = lpz; + + /* calculate parameters depending on the mode we are in */ + if (Q->abridged) { + lpz = calc_abridged_params(lpz, P); + } else { + lpz = calc_standard_params(lpz, P); + } + + /* offset coordinate */ + point.lpz.phi += lpz.phi; + point.lpz.lam += lpz.lam; + point.lpz.z += lpz.z; + + return point.xyz; +} + + +static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { + obs.xyz = forward_3d(obs.lpz, P); + return obs; +} + + +static LPZ reverse_3d(XYZ xyz, PJ *P) { + struct pj_opaque_molodensky *Q = (struct pj_opaque_molodensky *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + LPZ lpz; + + /* calculate parameters depending on the mode we are in */ + point.xyz = xyz; + if (Q->abridged) + lpz = calc_abridged_params(point.lpz, P); + else + lpz = calc_standard_params(point.lpz, P); + + /* offset coordinate */ + point.lpz.phi -= lpz.phi; + point.lpz.lam -= lpz.lam; + point.lpz.z -= lpz.z; + + return point.lpz; +} + + +static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { + obs.lpz = reverse_3d(obs.xyz, P); + return obs; +} + + +PJ *TRANSFORMATION(molodensky,1) { + int count_required_params = 0; + struct pj_opaque_molodensky *Q = static_cast(pj_calloc(1, sizeof(struct pj_opaque_molodensky))); + if (nullptr==Q) + return pj_default_destructor(P, ENOMEM); + P->opaque = (void *) Q; + + P->fwd4d = forward_4d; + P->inv4d = reverse_4d; + P->fwd3d = forward_3d; + P->inv3d = reverse_3d; + P->fwd = forward_2d; + P->inv = reverse_2d; + + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_ANGULAR; + + /* read args */ + if (pj_param(P->ctx, P->params, "tdx").i) { + count_required_params ++; + Q->dx = pj_param(P->ctx, P->params, "ddx").f; + } + + if (pj_param(P->ctx, P->params, "tdy").i) { + count_required_params ++; + Q->dy = pj_param(P->ctx, P->params, "ddy").f; + } + + if (pj_param(P->ctx, P->params, "tdz").i) { + count_required_params ++; + Q->dz = pj_param(P->ctx, P->params, "ddz").f; + } + + if (pj_param(P->ctx, P->params, "tda").i) { + count_required_params ++; + Q->da = pj_param(P->ctx, P->params, "dda").f; + } + + if (pj_param(P->ctx, P->params, "tdf").i) { + count_required_params ++; + Q->df = pj_param(P->ctx, P->params, "ddf").f; + } + + Q->abridged = pj_param(P->ctx, P->params, "tabridged").i; + + /* We want all parameters (except +abridged) to be set */ + if (count_required_params == 0) + return pj_default_destructor(P, PJD_ERR_NO_ARGS); + + if (count_required_params != 5) + return pj_default_destructor(P, PJD_ERR_MISSING_ARGS); + + return P; +} diff --git a/src/transformations/vgridshift.cpp b/src/transformations/vgridshift.cpp new file mode 100644 index 00000000..b3da906d --- /dev/null +++ b/src/transformations/vgridshift.cpp @@ -0,0 +1,144 @@ +#define PJ_LIB__ + +#include +#include +#include +#include + +#include "proj_internal.h" +#include "projects.h" + +PROJ_HEAD(vgridshift, "Vertical grid shift"); + +namespace { // anonymous namespace +struct pj_opaque_vgridshift { + double t_final; + double t_epoch; + double forward_multiplier; +}; +} // anonymous namespace + +static XYZ forward_3d(LPZ lpz, PJ *P) { + struct pj_opaque_vgridshift *Q = (struct pj_opaque_vgridshift *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + point.lpz = lpz; + + if (P->vgridlist_geoid != nullptr) { + /* Only try the gridshift if at least one grid is loaded, + * otherwise just pass the coordinate through unchanged. */ + point.xyz.z += Q->forward_multiplier * proj_vgrid_value(P, point.lp); + } + + return point.xyz; +} + + +static LPZ reverse_3d(XYZ xyz, PJ *P) { + struct pj_opaque_vgridshift *Q = (struct pj_opaque_vgridshift *) P->opaque; + PJ_COORD point = {{0,0,0,0}}; + point.xyz = xyz; + + if (P->vgridlist_geoid != nullptr) { + /* Only try the gridshift if at least one grid is loaded, + * otherwise just pass the coordinate through unchanged. */ + point.xyz.z -= Q->forward_multiplier * proj_vgrid_value(P, point.lp); + } + + return point.lpz; +} + + +static PJ_COORD forward_4d(PJ_COORD obs, PJ *P) { + struct pj_opaque_vgridshift *Q = (struct pj_opaque_vgridshift *) P->opaque; + PJ_COORD point = obs; + + /* If transformation is not time restricted, we always call it */ + if (Q->t_final==0 || Q->t_epoch==0) { + point.xyz = forward_3d (obs.lpz, P); + return point; + } + + /* Time restricted - only apply transform if within time bracket */ + if (obs.lpzt.t < Q->t_epoch && Q->t_final > Q->t_epoch) + point.xyz = forward_3d (obs.lpz, P); + + + return point; +} + +static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { + struct pj_opaque_vgridshift *Q = (struct pj_opaque_vgridshift *) P->opaque; + PJ_COORD point = obs; + + /* If transformation is not time restricted, we always call it */ + if (Q->t_final==0 || Q->t_epoch==0) { + point.lpz = reverse_3d (obs.xyz, P); + return point; + } + + /* Time restricted - only apply transform if within time bracket */ + if (obs.lpzt.t < Q->t_epoch && Q->t_final > Q->t_epoch) + point.lpz = reverse_3d (obs.xyz, P); + + return point; +} + + +PJ *TRANSFORMATION(vgridshift,0) { + struct pj_opaque_vgridshift *Q = static_cast(pj_calloc (1, sizeof (struct pj_opaque_vgridshift))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = (void *) Q; + + if (!pj_param(P->ctx, P->params, "tgrids").i) { + proj_log_error(P, "vgridshift: +grids parameter missing."); + return pj_default_destructor(P, PJD_ERR_NO_ARGS); + } + + /* TODO: Refactor into shared function that can be used */ + /* by both vgridshift and hgridshift */ + if (pj_param(P->ctx, P->params, "tt_final").i) { + Q->t_final = pj_param (P->ctx, P->params, "dt_final").f; + if (Q->t_final == 0) { + /* a number wasn't passed to +t_final, let's see if it was "now" */ + /* and set the time accordingly. */ + if (!strcmp("now", pj_param(P->ctx, P->params, "st_final").s)) { + time_t now; + struct tm *date; + time(&now); + date = localtime(&now); + Q->t_final = 1900.0 + date->tm_year + date->tm_yday/365.0; + } + } + } + + if (pj_param(P->ctx, P->params, "tt_epoch").i) + Q->t_epoch = pj_param (P->ctx, P->params, "dt_epoch").f; + + /* historical: the forward direction subtracts the grid offset. */ + Q->forward_multiplier = -1.0; + if (pj_param(P->ctx, P->params, "tmultiplier").i) { + Q->forward_multiplier = pj_param(P->ctx, P->params, "dmultiplier").f; + } + + /* Build gridlist. P->vgridlist_geoid can be empty if +grids only ask for optional grids. */ + proj_vgrid_init(P, "grids"); + + /* Was gridlist compiled properly? */ + if ( proj_errno(P) ) { + proj_log_error(P, "vgridshift: could not find required grid(s)."); + return pj_default_destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID); + } + + P->fwd4d = forward_4d; + P->inv4d = reverse_4d; + P->fwd3d = forward_3d; + P->inv3d = reverse_3d; + P->fwd = nullptr; + P->inv = nullptr; + + P->left = PJ_IO_UNITS_ANGULAR; + P->right = PJ_IO_UNITS_ANGULAR; + + return P; +} diff --git a/src/tsfn.cpp b/src/tsfn.cpp new file mode 100644 index 00000000..ea3b896d --- /dev/null +++ b/src/tsfn.cpp @@ -0,0 +1,16 @@ +/* determine small t */ +#include +#include "projects.h" + +double pj_tsfn(double phi, double sinphi, double e) { + double denominator; + sinphi *= e; + + /* avoid zero division, fail gracefully */ + denominator = 1.0 + sinphi; + if (denominator == 0.0) + return HUGE_VAL; + + return (tan (.5 * (M_HALFPI - phi)) / + pow((1. - sinphi) / (denominator), .5 * e)); +} diff --git a/src/units.cpp b/src/units.cpp new file mode 100644 index 00000000..50f11396 --- /dev/null +++ b/src/units.cpp @@ -0,0 +1,58 @@ +/* definition of standard cartesian units */ + +#include + +#include "proj.h" + +#define PJ_UNITS__ +#include "projects.h" + +/* Field 2 that contains the multiplier to convert named units to meters +** may be expressed by either a simple floating point constant or a +** numerator/denomenator values (e.g. 1/1000) */ +static const struct PJ_UNITS +pj_units[] = { + {"km", "1000", "Kilometer", 1000.0}, + {"m", "1", "Meter", 1.0}, + {"dm", "1/10", "Decimeter", 0.1}, + {"cm", "1/100", "Centimeter", 0.01}, + {"mm", "1/1000", "Millimeter", 0.001}, + {"kmi", "1852", "International Nautical Mile", 1852.0}, + {"in", "0.0254", "International Inch", 0.0254}, + {"ft", "0.3048", "International Foot", 0.3048}, + {"yd", "0.9144", "International Yard", 0.9144}, + {"mi", "1609.344", "International Statute Mile", 1609.344}, + {"fath", "1.8288", "International Fathom", 1.8288}, + {"ch", "20.1168", "International Chain", 20.1168}, + {"link", "0.201168", "International Link", 0.201168}, + {"us-in", "1/39.37", "U.S. Surveyor's Inch", 100/3937.0}, + {"us-ft", "0.304800609601219", "U.S. Surveyor's Foot", 1200/3937.0}, + {"us-yd", "0.914401828803658", "U.S. Surveyor's Yard", 3600/3937.0}, + {"us-ch", "20.11684023368047", "U.S. Surveyor's Chain", 79200/3937.0}, + {"us-mi", "1609.347218694437", "U.S. Surveyor's Statute Mile", 6336000/3937.0}, + {"ind-yd", "0.91439523", "Indian Yard", 0.91439523}, + {"ind-ft", "0.30479841", "Indian Foot", 0.30479841}, + {"ind-ch", "20.11669506", "Indian Chain", 20.11669506}, + {nullptr, nullptr, nullptr, 0.0} +}; + +const PJ_UNITS *proj_list_units() +{ + return pj_units; +} + +/* M_PI / 200 */ +#define GRAD_TO_RAD 0.015707963267948967 + +const struct PJ_UNITS +pj_angular_units[] = { + {"rad", "1.0", "Radian", 1.0}, + {"deg", "0.017453292519943296", "Degree", DEG_TO_RAD}, + {"grad", "0.015707963267948967", "Grad", GRAD_TO_RAD}, + {nullptr, nullptr, nullptr, 0.0} +}; + +const PJ_UNITS *proj_list_angular_units() +{ + return pj_angular_units; +} diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 00000000..8587dc30 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,181 @@ +/****************************************************************************** + * Project: PROJ.4 + * Purpose: Some utility functions we don't want to bother putting in + * their own source files. + * Author: Frank Warmerdam, warmerdam@pobox.com + * + ****************************************************************************** + * Copyright (c) 2001, 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. + *****************************************************************************/ + +#define PJ_LIB__ + +#include +#include + +#include "projects.h" + +/************************************************************************/ +/* pj_is_latlong() */ +/* */ +/* Returns TRUE if this coordinate system object is */ +/* geographic. */ +/************************************************************************/ + +int pj_is_latlong( PJ *pj ) + +{ + return pj == nullptr || pj->is_latlong; +} + +/************************************************************************/ +/* pj_is_geocent() */ +/* */ +/* Returns TRUE if this coordinate system object is geocentric. */ +/************************************************************************/ + +int pj_is_geocent( PJ *pj ) + +{ + return pj != nullptr && pj->is_geocent; +} + +/************************************************************************/ +/* pj_latlong_from_proj() */ +/* */ +/* Return a PJ* definition defining the lat/long coordinate */ +/* system on which a projection is based. If the coordinate */ +/* system passed in is latlong, a clone of the same will be */ +/* returned. */ +/************************************************************************/ + +PJ *pj_latlong_from_proj( PJ *pj_in ) + +{ + char defn[512]; + int got_datum = FALSE; + + pj_errno = 0; + strcpy( defn, "+proj=latlong" ); + + if( pj_param(pj_in->ctx, pj_in->params, "tdatum").i ) + { + got_datum = TRUE; + sprintf( defn+strlen(defn), " +datum=%s", + pj_param(pj_in->ctx, pj_in->params,"sdatum").s ); + } + else if( pj_param(pj_in->ctx, pj_in->params, "tellps").i ) + { + sprintf( defn+strlen(defn), " +ellps=%s", + pj_param(pj_in->ctx, pj_in->params,"sellps").s ); + } + else if( pj_param(pj_in->ctx,pj_in->params, "ta").i ) + { + sprintf( defn+strlen(defn), " +a=%s", + pj_param(pj_in->ctx,pj_in->params,"sa").s ); + + if( pj_param(pj_in->ctx,pj_in->params, "tb").i ) + sprintf( defn+strlen(defn), " +b=%s", + pj_param(pj_in->ctx,pj_in->params,"sb").s ); + else if( pj_param(pj_in->ctx,pj_in->params, "tes").i ) + sprintf( defn+strlen(defn), " +es=%s", + pj_param(pj_in->ctx,pj_in->params,"ses").s ); + else if( pj_param(pj_in->ctx,pj_in->params, "tf").i ) + sprintf( defn+strlen(defn), " +f=%s", + pj_param(pj_in->ctx,pj_in->params,"sf").s ); + else + { + char* ptr = defn+strlen(defn); + sprintf( ptr, " +es=%.16g", pj_in->es ); + /* TODO later: use C++ ostringstream with imbue(std::locale::classic()) */ + /* to be locale unaware */ + for(; *ptr; ptr++) + { + if( *ptr == ',' ) + *ptr = '.'; + } + } + } + else + { + pj_ctx_set_errno( pj_in->ctx, PJD_ERR_MAJOR_AXIS_NOT_GIVEN ); + + return nullptr; + } + + if( !got_datum ) + { + if( pj_param(pj_in->ctx,pj_in->params, "ttowgs84").i ) + sprintf( defn+strlen(defn), " +towgs84=%s", + pj_param(pj_in->ctx,pj_in->params,"stowgs84").s ); + + if( pj_param(pj_in->ctx,pj_in->params, "tnadgrids").i ) + sprintf( defn+strlen(defn), " +nadgrids=%s", + pj_param(pj_in->ctx,pj_in->params,"snadgrids").s ); + } + + /* copy over some other information related to ellipsoid */ + if( pj_param(pj_in->ctx,pj_in->params, "tR").i ) + sprintf( defn+strlen(defn), " +R=%s", + pj_param(pj_in->ctx,pj_in->params,"sR").s ); + + if( pj_param(pj_in->ctx,pj_in->params, "tR_A").i ) + sprintf( defn+strlen(defn), " +R_A" ); + + if( pj_param(pj_in->ctx,pj_in->params, "tR_V").i ) + sprintf( defn+strlen(defn), " +R_V" ); + + if( pj_param(pj_in->ctx,pj_in->params, "tR_a").i ) + sprintf( defn+strlen(defn), " +R_a" ); + + if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_a").i ) + sprintf( defn+strlen(defn), " +R_lat_a=%s", + pj_param(pj_in->ctx,pj_in->params,"sR_lat_a").s ); + + if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_g").i ) + sprintf( defn+strlen(defn), " +R_lat_g=%s", + pj_param(pj_in->ctx,pj_in->params,"sR_lat_g").s ); + + /* copy over prime meridian */ + if( pj_param(pj_in->ctx,pj_in->params, "tpm").i ) + sprintf( defn+strlen(defn), " +pm=%s", + pj_param(pj_in->ctx,pj_in->params,"spm").s ); + + return pj_init_plus_ctx( pj_in->ctx, defn ); +} + +/************************************************************************/ +/* pj_get_spheroid_defn() */ +/* */ +/* Fetch the internal definition of the spheroid. Note that */ +/* you can compute "b" from eccentricity_squared as: */ +/* */ +/* b = a * sqrt(1 - es) */ +/************************************************************************/ + +void pj_get_spheroid_defn(projPJ defn, double *major_axis, double *eccentricity_squared) +{ + if ( major_axis ) + *major_axis = defn->a; + + if ( eccentricity_squared ) + *eccentricity_squared = defn->es; +} diff --git a/src/wkt1_generated_parser.c b/src/wkt1_generated_parser.c new file mode 100644 index 00000000..7a590f80 --- /dev/null +++ b/src/wkt1_generated_parser.c @@ -0,0 +1,1664 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse pj_wkt1_parse +#define yylex pj_wkt1_lex +#define yyerror pj_wkt1_error +#define yydebug pj_wkt1_debug +#define yynerrs pj_wkt1_nerrs + + +/* Copy the first part of user declarations. */ + + +/****************************************************************************** + * Project: PROJ + * Purpose: WKT1 parser grammar + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2013-2018 Even Rouault, + * + * 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. + ****************************************************************************/ + +#include "wkt1_parser.h" + + + + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "wkt1_generated_parser.h". */ +#ifndef YY_PJ_WKT1_SRC_WKT1_GENERATED_PARSER_H_INCLUDED +# define YY_PJ_WKT1_SRC_WKT1_GENERATED_PARSER_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int pj_wkt1_debug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + END = 0, + T_PARAM_MT = 258, + T_CONCAT_MT = 259, + T_INVERSE_MT = 260, + T_PASSTHROUGH_MT = 261, + T_PROJCS = 262, + T_PROJECTION = 263, + T_GEOGCS = 264, + T_DATUM = 265, + T_SPHEROID = 266, + T_PRIMEM = 267, + T_UNIT = 268, + T_GEOCCS = 269, + T_AUTHORITY = 270, + T_VERT_CS = 271, + T_VERT_DATUM = 272, + T_COMPD_CS = 273, + T_AXIS = 274, + T_TOWGS84 = 275, + T_FITTED_CS = 276, + T_LOCAL_CS = 277, + T_LOCAL_DATUM = 278, + T_PARAMETER = 279, + T_EXTENSION = 280, + T_STRING = 281, + T_NUMBER = 282, + T_IDENTIFIER = 283 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int pj_wkt1_parse (pj_wkt1_parse_context *context); + +#endif /* !YY_PJ_WKT1_SRC_WKT1_GENERATED_PARSER_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 28 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 215 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 34 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 66 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 99 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 257 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 283 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 30, 32, 2, 2, 33, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 29, 2, 31, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 76, 76, 88, 88, 91, 94, 94, 97, 97, + 97, 97, 100, 103, 105, 106, 109, 111, 112, 115, + 118, 122, 127, 127, 127, 127, 127, 127, 130, 130, + 134, 138, 139, 142, 143, 145, 146, 147, 148, 150, + 151, 154, 157, 160, 164, 166, 167, 168, 169, 172, + 176, 179, 182, 185, 188, 191, 194, 197, 200, 203, + 204, 205, 206, 209, 212, 215, 217, 218, 219, 222, + 224, 225, 226, 229, 232, 235, 238, 240, 243, 248, + 251, 253, 256, 259, 262, 265, 268, 271, 274, 277, + 280, 283, 286, 289, 292, 294, 296, 297, 298, 301 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 1 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of string\"", "error", "$undefined", "\"PARAM_MT\"", + "\"CONCAT_MT\"", "\"INVERSE_MT\"", "\"PASSTHROUGH_MT\"", "\"PROJCS\"", + "\"PROJECTION\"", "\"GEOGCS\"", "\"DATUM\"", "\"SPHEROID\"", + "\"PRIMEM\"", "\"UNIT\"", "\"GEOCCS\"", "\"AUTHORITY\"", "\"VERT_CS\"", + "\"VERT_DATUM\"", "\"COMPD_CS\"", "\"AXIS\"", "\"TOWGS84\"", + "\"FITTED_CS\"", "\"LOCAL_CS\"", "\"LOCAL_DATUM\"", "\"PARAMETER\"", + "\"EXTENSION\"", "\"string\"", "\"number\"", "\"identifier\"", "'['", + "'('", "']'", "')'", "','", "$accept", "input", "begin_node", + "begin_node_name", "end_node", "math_transform", "param_mt", "parameter", + "opt_parameter_list", "concat_mt", "opt_math_transform_list", "inv_mt", + "passthrough_mt", "integer", "coordinate_system", "horz_cs", + "projected_cs", "opt_parameter_list_linear_unit", + "parameter_list_linear_unit", "opt_twin_axis_extension_authority", + "opt_authority", "extension", "projection", "geographic_cs", "datum", + "opt_towgs84_authority_extension", "spheroid", "semi_major_axis", + "inverse_flattening", "prime_meridian", "longitude", "angular_unit", + "linear_unit", "unit", "conversion_factor", "geocentric_cs", + "opt_three_axis_extension_authority", "three_axis", "authority", + "vert_cs", "opt_axis_authority", "vert_datum", "opt_extension_authority", + "datum_type", "compd_cs", "head_cs", "tail_cs", "twin_axis", "axis", + "towgs84", "towgs84_parameters", "three_parameters", "seven_parameters", + "dx", "dy", "dz", "ex", "ey", "ez", "ppm", "fitted_cs", "to_base", + "base_cs", "local_cs", "opt_axis_list_authority", "local_datum", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 91, + 40, 93, 41, 44 +}; +# endif + +#define YYPACT_NINF -127 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-127))) + +#define YYTABLE_NINF -1 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 136, 2, 2, 2, 2, 2, 2, 2, 26, -127, + -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, + 11, 5, 18, 32, 36, 40, 42, 53, -127, -127, + 35, 66, 66, 61, 136, 85, -127, -127, 59, -127, + 67, 2, 68, 69, 2, 70, -127, 72, 2, 2, + 2, 2, -127, -127, -127, -127, -127, 76, 2, 77, + 84, 79, 87, 87, 82, 105, 136, 88, 85, 85, + 93, 136, 89, 105, 2, 90, 113, 2, 95, 96, + 103, 2, 98, -127, -127, 99, 109, 25, 101, 25, + -127, 107, -127, 25, 103, 111, 114, 1, 2, 115, + 120, 105, 105, -127, 99, 122, 14, 25, 34, 25, + 2, 88, -127, 85, 25, -127, 85, -127, 114, 119, + 141, 25, 126, 127, -127, -127, 128, 15, 25, 135, + 127, -127, 130, 25, 137, 2, 2, -127, 114, -127, + 2, 114, -127, -127, 132, -127, 101, -127, 25, 25, + 133, -127, -127, 1, 33, 25, 140, 2, 114, -127, + 99, -127, -127, 114, 25, 33, 25, -127, -127, 114, + 138, 139, -127, 142, -127, 143, -127, -127, -127, 14, + 25, -127, -127, 114, -127, 99, 144, -127, -127, 145, + 146, -127, -127, 25, -127, 114, 99, -127, 147, -127, + 25, 148, 151, 150, 25, -127, 133, -127, -127, -127, + 119, 154, -127, 25, -127, -127, 149, -127, -127, -127, + 119, -127, 25, 25, 25, -127, -127, -127, -127, 114, + -127, 156, 153, -127, -127, -127, 25, -127, 155, 119, + -127, 157, -127, -127, 158, 160, -127, 159, 162, -127, + 161, 163, -127, 164, 166, -127, -127 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 22, 29, 28, 23, 24, 25, 26, 27, 3, 4, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, + 0, 0, 0, 0, 0, 0, 6, 7, 0, 95, + 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, + 0, 0, 92, 8, 9, 10, 11, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 66, 55, 76, 70, 0, 0, 17, 0, + 21, 0, 93, 0, 0, 0, 39, 0, 0, 45, + 0, 0, 0, 73, 70, 0, 0, 0, 0, 0, + 0, 14, 12, 0, 0, 19, 0, 91, 39, 0, + 0, 0, 0, 35, 32, 31, 0, 0, 0, 0, + 35, 54, 59, 0, 0, 0, 0, 68, 39, 65, + 0, 39, 72, 74, 0, 15, 17, 16, 0, 0, + 96, 40, 42, 0, 0, 0, 0, 0, 39, 48, + 70, 44, 53, 39, 0, 0, 0, 69, 57, 39, + 0, 0, 67, 0, 71, 0, 18, 20, 99, 0, + 0, 33, 34, 39, 38, 70, 0, 30, 50, 0, + 0, 47, 46, 0, 43, 39, 70, 62, 0, 58, + 0, 0, 0, 0, 0, 97, 96, 94, 37, 36, + 0, 0, 84, 0, 81, 80, 0, 52, 61, 60, + 0, 56, 0, 0, 0, 13, 98, 77, 51, 39, + 79, 0, 0, 64, 78, 41, 0, 85, 0, 0, + 49, 0, 63, 86, 82, 0, 87, 0, 0, 88, + 0, 0, 89, 0, 0, 90, 83 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -127, -127, -46, 6, -87, -50, -127, 83, 57, -127, + 49, -127, -127, -127, -11, -127, -127, -127, 43, 71, + -44, -126, -127, 168, 167, -127, -127, -127, -127, 152, + -127, -127, -81, -56, -127, -127, -127, -127, -84, -127, + -127, -127, -89, 106, -127, -127, -127, -127, -112, -127, + -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, + -127, -127, -127, -127, -4, -127 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 8, 20, 21, 39, 52, 53, 122, 87, 54, + 114, 55, 56, 91, 9, 10, 11, 123, 124, 155, + 121, 141, 75, 12, 42, 128, 99, 189, 229, 78, + 163, 130, 82, 83, 169, 13, 166, 196, 137, 14, + 107, 45, 109, 104, 15, 47, 85, 185, 138, 160, + 213, 214, 215, 216, 238, 244, 247, 250, 253, 256, + 16, 57, 93, 17, 180, 59 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint8 yytable[] = +{ + 112, 158, 115, 68, 69, 70, 117, 150, 22, 23, + 24, 25, 26, 27, 81, 133, 125, 95, 88, 89, + 139, 132, 143, 46, 142, 110, 28, 147, 183, 135, + 135, 18, 19, 136, 152, 157, 151, 29, 30, 195, + 140, 161, 186, 159, 2, 131, 167, 61, 135, 135, + 64, 31, 136, 198, 67, 84, 36, 37, 140, 140, + 92, 177, 178, 146, 72, 32, 148, 206, 187, 33, + 184, 192, 182, 34, 149, 35, 41, 194, 44, 199, + 96, 197, 58, 100, 36, 37, 38, 105, 48, 49, + 50, 51, 74, 207, 172, 205, 209, 174, 227, 77, + 60, 62, 63, 65, 126, 66, 217, 219, 232, 71, + 73, 190, 76, 221, 191, 80, 144, 225, 81, 193, + 90, 86, 94, 97, 98, 200, 230, 242, 101, 102, + 103, 106, 108, 110, 113, 233, 234, 235, 136, 208, + 116, 170, 171, 1, 119, 2, 173, 120, 127, 240, + 3, 218, 4, 129, 5, 134, 135, 6, 7, 153, + 154, 156, 162, 165, 168, 175, 179, 188, 145, 111, + 204, 201, 202, 212, 222, 203, 224, 210, 211, 223, + 220, 228, 231, 237, 243, 236, 239, 246, 241, 249, + 252, 245, 248, 255, 251, 176, 181, 254, 40, 43, + 118, 164, 226, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 79 +}; + +static const yytype_int16 yycheck[] = +{ + 87, 127, 89, 49, 50, 51, 93, 119, 2, 3, + 4, 5, 6, 7, 13, 104, 97, 73, 68, 69, + 107, 102, 109, 34, 108, 24, 0, 114, 154, 15, + 15, 29, 30, 19, 121, 20, 120, 26, 33, 165, + 25, 128, 154, 127, 9, 101, 133, 41, 15, 15, + 44, 33, 19, 165, 48, 66, 31, 32, 25, 25, + 71, 148, 149, 113, 58, 33, 116, 179, 155, 33, + 154, 160, 153, 33, 118, 33, 10, 164, 17, 166, + 74, 165, 23, 77, 31, 32, 33, 81, 3, 4, + 5, 6, 8, 180, 138, 179, 185, 141, 210, 12, + 33, 33, 33, 33, 98, 33, 193, 196, 220, 33, + 33, 157, 33, 200, 158, 33, 110, 204, 13, 163, + 27, 33, 33, 33, 11, 169, 213, 239, 33, 33, + 27, 33, 33, 24, 33, 222, 223, 224, 19, 183, + 33, 135, 136, 7, 33, 9, 140, 33, 33, 236, + 14, 195, 16, 33, 18, 33, 15, 21, 22, 33, + 33, 33, 27, 33, 27, 33, 33, 27, 111, 86, + 27, 33, 33, 27, 26, 33, 26, 33, 33, 28, + 33, 27, 33, 27, 27, 229, 33, 27, 33, 27, + 27, 33, 33, 27, 33, 146, 153, 33, 30, 32, + 94, 130, 206, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 63 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 7, 9, 14, 16, 18, 21, 22, 35, 48, + 49, 50, 57, 69, 73, 78, 94, 97, 29, 30, + 36, 37, 37, 37, 37, 37, 37, 37, 0, 26, + 33, 33, 33, 33, 33, 33, 31, 32, 33, 38, + 57, 10, 58, 58, 17, 75, 48, 79, 3, 4, + 5, 6, 39, 40, 43, 45, 46, 95, 23, 99, + 33, 37, 33, 33, 37, 33, 33, 37, 36, 36, + 36, 33, 37, 33, 8, 56, 33, 12, 63, 63, + 33, 13, 66, 67, 48, 80, 33, 42, 39, 39, + 27, 47, 48, 96, 33, 67, 37, 33, 11, 60, + 37, 33, 33, 27, 77, 37, 33, 74, 33, 76, + 24, 41, 38, 33, 44, 38, 33, 38, 77, 33, + 33, 54, 41, 51, 52, 66, 37, 33, 59, 33, + 65, 67, 66, 76, 33, 15, 19, 72, 82, 38, + 25, 55, 72, 38, 37, 42, 39, 38, 39, 54, + 82, 72, 38, 33, 33, 53, 33, 20, 55, 72, + 83, 38, 27, 64, 53, 33, 70, 38, 27, 68, + 37, 37, 54, 37, 54, 33, 44, 38, 38, 33, + 98, 52, 66, 55, 72, 81, 82, 38, 27, 61, + 36, 54, 76, 54, 38, 55, 71, 72, 82, 38, + 54, 33, 33, 33, 27, 72, 82, 38, 54, 76, + 33, 33, 27, 84, 85, 86, 87, 38, 54, 76, + 33, 38, 26, 28, 26, 38, 98, 82, 27, 62, + 38, 33, 82, 38, 38, 38, 54, 27, 88, 33, + 38, 33, 82, 27, 89, 33, 27, 90, 33, 27, + 91, 33, 27, 92, 33, 27, 93 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 34, 35, 36, 36, 37, 38, 38, 39, 39, + 39, 39, 40, 41, 42, 42, 43, 44, 44, 45, + 46, 47, 48, 48, 48, 48, 48, 48, 49, 49, + 50, 51, 51, 52, 52, 53, 53, 53, 53, 54, + 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, + 70, 70, 70, 71, 72, 73, 74, 74, 74, 75, + 76, 76, 76, 77, 78, 79, 80, 81, 82, 83, + 84, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 97, 98, 98, 98, 99 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 1, 2, 1, 1, 1, 1, + 1, 1, 4, 5, 0, 3, 5, 0, 3, 4, + 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 10, 1, 1, 3, 3, 0, 3, 3, 2, 0, + 2, 5, 4, 10, 6, 0, 3, 3, 2, 8, + 1, 1, 6, 1, 1, 1, 6, 1, 10, 0, + 3, 3, 2, 5, 5, 8, 0, 3, 2, 6, + 0, 3, 2, 1, 8, 1, 1, 3, 5, 4, + 1, 1, 5, 13, 1, 1, 1, 1, 1, 1, + 1, 7, 1, 1, 10, 3, 0, 2, 3, 6 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, context); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt1_parse_context *context) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (context); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt1_parse_context *context) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, context); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, pj_wkt1_parse_context *context) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , context); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, context); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr && yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, pj_wkt1_parse_context *context) +{ + YYUSE (yyvaluep); + YYUSE (context); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (pj_wkt1_parse_context *context) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = (yytype_int16)yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, context); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (context, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (context, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, context); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +#if 0 +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +#endif +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, context); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (context, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, context); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, context); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} diff --git a/src/wkt1_generated_parser.h b/src/wkt1_generated_parser.h new file mode 100644 index 00000000..989f1f32 --- /dev/null +++ b/src/wkt1_generated_parser.h @@ -0,0 +1,89 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_PJ_WKT1_SRC_WKT1_GENERATED_PARSER_H_INCLUDED +# define YY_PJ_WKT1_SRC_WKT1_GENERATED_PARSER_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int pj_wkt1_debug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + END = 0, + T_PARAM_MT = 258, + T_CONCAT_MT = 259, + T_INVERSE_MT = 260, + T_PASSTHROUGH_MT = 261, + T_PROJCS = 262, + T_PROJECTION = 263, + T_GEOGCS = 264, + T_DATUM = 265, + T_SPHEROID = 266, + T_PRIMEM = 267, + T_UNIT = 268, + T_GEOCCS = 269, + T_AUTHORITY = 270, + T_VERT_CS = 271, + T_VERT_DATUM = 272, + T_COMPD_CS = 273, + T_AXIS = 274, + T_TOWGS84 = 275, + T_FITTED_CS = 276, + T_LOCAL_CS = 277, + T_LOCAL_DATUM = 278, + T_PARAMETER = 279, + T_EXTENSION = 280, + T_STRING = 281, + T_NUMBER = 282, + T_IDENTIFIER = 283 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int pj_wkt1_parse (pj_wkt1_parse_context *context); + +#endif /* !YY_PJ_WKT1_SRC_WKT1_GENERATED_PARSER_H_INCLUDED */ diff --git a/src/wkt1_grammar.y b/src/wkt1_grammar.y new file mode 100644 index 00000000..28ff7a6e --- /dev/null +++ b/src/wkt1_grammar.y @@ -0,0 +1,301 @@ +%{ +/****************************************************************************** + * Project: PROJ + * Purpose: WKT1 parser grammar + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2013-2018 Even Rouault, + * + * 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. + ****************************************************************************/ + +#include "wkt1_parser.h" + +%} + +%define api.pure +/* if the next %define is commented out, Bison 2.4 should be sufficient */ +/* but will produce less prettier error messages */ +%define parse.error verbose +%require "3.0" + +%parse-param {pj_wkt1_parse_context *context} +%lex-param {pj_wkt1_parse_context *context} + +%token T_PARAM_MT "PARAM_MT" +%token T_CONCAT_MT "CONCAT_MT" +%token T_INVERSE_MT "INVERSE_MT" +%token T_PASSTHROUGH_MT "PASSTHROUGH_MT" +%token T_PROJCS "PROJCS" +%token T_PROJECTION "PROJECTION" +%token T_GEOGCS "GEOGCS" +%token T_DATUM "DATUM" +%token T_SPHEROID "SPHEROID" +%token T_PRIMEM "PRIMEM" +%token T_UNIT "UNIT" +%token T_GEOCCS "GEOCCS" +%token T_AUTHORITY "AUTHORITY" +%token T_VERT_CS "VERT_CS" +%token T_VERT_DATUM "VERT_DATUM" +%token T_COMPD_CS "COMPD_CS" +%token T_AXIS "AXIS" +%token T_TOWGS84 "TOWGS84" +%token T_FITTED_CS "FITTED_CS" +%token T_LOCAL_CS "LOCAL_CS" +%token T_LOCAL_DATUM "LOCAL_DATUM" +%token T_PARAMETER "PARAMETER" + +%token T_EXTENSION "EXTENSION" + +%token T_STRING "string" +%token T_NUMBER "number" +%token T_IDENTIFIER "identifier" + +%token END 0 "end of string" + +%% + +input: + coordinate_system + +/* Derived from BNF grammar in OGC 01-009 OpenGIS Implementation */ +/* Coordinate Transformation Services Revision 1.00 */ +/* with the following additions : */ +/* - accept an EXTENSION node at the end of GEOGCS, GEOCCS, PROJCS, COMPD_CS, VERT_DATUM */ +/* - accept 3 parameters in TOWGS84 */ +/* - accept LOCAL_CS["foo"] */ + +/* 7.1 Math Transform WKT */ + +begin_node: + '[' | '(' + +begin_node_name: + begin_node T_STRING + +end_node: + ']' | ')' + +math_transform: + param_mt | concat_mt | inv_mt | passthrough_mt + +param_mt: + T_PARAM_MT begin_node_name opt_parameter_list end_node + +parameter: + T_PARAMETER begin_node_name ',' T_NUMBER end_node + +opt_parameter_list: + | ',' parameter opt_parameter_list + +concat_mt: + T_CONCAT_MT begin_node math_transform opt_math_transform_list end_node + +opt_math_transform_list: + | ',' math_transform opt_math_transform_list + +inv_mt: + T_INVERSE_MT begin_node math_transform end_node + +passthrough_mt: + T_PASSTHROUGH_MT begin_node integer ',' math_transform end_node + +/* FIXME */ +integer: + T_NUMBER + +/* 7.2 Coordinate System WKT */ + +coordinate_system: + horz_cs | geocentric_cs | vert_cs | compd_cs | fitted_cs | local_cs + +horz_cs: + geographic_cs | projected_cs + +/* opt_extension is an extension of the CT spec */ +projected_cs: + T_PROJCS begin_node_name ',' geographic_cs ',' projection ',' + opt_parameter_list_linear_unit opt_twin_axis_extension_authority end_node + +opt_parameter_list_linear_unit: + linear_unit + | parameter_list_linear_unit + +parameter_list_linear_unit: + parameter ',' parameter_list_linear_unit + | parameter ',' linear_unit + +opt_twin_axis_extension_authority: + | ',' twin_axis opt_extension_authority + | ',' extension opt_authority + | ',' authority + +opt_authority: + | ',' authority + +extension: + T_EXTENSION begin_node_name ',' T_STRING end_node + +projection: + T_PROJECTION begin_node_name opt_authority end_node + +geographic_cs: + T_GEOGCS begin_node_name',' datum ',' prime_meridian ',' + angular_unit opt_twin_axis_extension_authority end_node + +datum: + T_DATUM begin_node_name ',' spheroid opt_towgs84_authority_extension end_node + +opt_towgs84_authority_extension: + | ',' towgs84 opt_extension_authority + | ',' extension opt_authority + | ',' authority + +spheroid: + T_SPHEROID begin_node_name ',' semi_major_axis ',' + inverse_flattening opt_authority end_node + +semi_major_axis: + T_NUMBER + +inverse_flattening: + T_NUMBER + +prime_meridian: + T_PRIMEM begin_node_name ',' longitude opt_authority end_node + +longitude: + T_NUMBER + +angular_unit: + unit + +linear_unit: + unit + +unit: + T_UNIT begin_node_name ',' conversion_factor opt_authority end_node + +conversion_factor: + T_NUMBER + +geocentric_cs: + T_GEOCCS begin_node_name ',' datum ',' prime_meridian ',' + linear_unit opt_three_axis_extension_authority end_node + +opt_three_axis_extension_authority: + | ',' three_axis opt_extension_authority + | ',' extension opt_authority + | ',' authority + +three_axis: + axis ',' axis ',' axis + +authority: + T_AUTHORITY begin_node_name ',' T_STRING end_node + +vert_cs: + T_VERT_CS begin_node_name ',' vert_datum ',' linear_unit opt_axis_authority end_node + +opt_axis_authority: + | ',' axis opt_authority + | ',' authority + +vert_datum: + T_VERT_DATUM begin_node_name ',' datum_type opt_extension_authority end_node + +opt_extension_authority: + | ',' extension opt_authority + | ',' authority + +datum_type: + T_NUMBER + +compd_cs: + T_COMPD_CS begin_node_name ',' head_cs ',' tail_cs opt_extension_authority end_node + +head_cs: + coordinate_system + +tail_cs: + coordinate_system + +twin_axis: axis ',' axis + +axis: + T_AXIS begin_node_name ',' T_IDENTIFIER end_node +/* Extension of the CT spec */ +/* | T_AXIS '[' T_STRING ',' T_STRING ']'*/ + +towgs84: + T_TOWGS84 begin_node towgs84_parameters end_node + +towgs84_parameters: + seven_parameters +/* Extension of the CT spec */ + | three_parameters + +three_parameters: + dx ',' dy ',' dz + +seven_parameters: + dx ',' dy ',' dz ',' ex ',' ey ',' ez ',' ppm + +dx: + T_NUMBER + +dy: + T_NUMBER + +dz: + T_NUMBER + +ex: + T_NUMBER + +ey: + T_NUMBER + +ez: + T_NUMBER + +ppm: + T_NUMBER + +fitted_cs: + T_FITTED_CS begin_node_name ',' to_base ',' base_cs end_node + +to_base: + math_transform + +base_cs: + coordinate_system + +local_cs: + T_LOCAL_CS begin_node_name ',' local_datum ',' unit ',' axis opt_axis_list_authority end_node +/* Extension of the CT spec: accept only name */ + | T_LOCAL_CS begin_node_name end_node + +opt_axis_list_authority: + | ',' authority + | ',' axis opt_axis_list_authority + +local_datum: + T_LOCAL_DATUM begin_node_name ',' datum_type opt_authority end_node diff --git a/src/wkt1_parser.cpp b/src/wkt1_parser.cpp new file mode 100644 index 00000000..9db7d4bd --- /dev/null +++ b/src/wkt1_parser.cpp @@ -0,0 +1,193 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: WKT1 parser grammar + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2013, Even Rouault + * + * 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. + ****************************************************************************/ + +#ifndef FROM_PROJ_CPP +#define FROM_PROJ_CPP +#endif + +#include "proj/internal/internal.hpp" + +#include +#include +#include + +#include "wkt1_parser.h" +#include "wkt_parser.hpp" + +using namespace NS_PROJ::internal; + +//! @cond Doxygen_Suppress + +// --------------------------------------------------------------------------- + +struct pj_wkt1_parse_context : public pj_wkt_parse_context {}; + +// --------------------------------------------------------------------------- + +void pj_wkt1_error(pj_wkt1_parse_context *context, const char *msg) { + pj_wkt_error(context, msg); +} + +// --------------------------------------------------------------------------- + +std::string pj_wkt1_parse(const std::string &wkt) { + pj_wkt1_parse_context context; + context.pszInput = wkt.c_str(); + context.pszLastSuccess = wkt.c_str(); + context.pszNext = wkt.c_str(); + if (pj_wkt1_parse(&context) != 0) { + return context.errorMsg; + } + return std::string(); +} + +// --------------------------------------------------------------------------- + +typedef struct { + const char *pszToken; + int nTokenVal; +} osr_cs_wkt_tokens; + +#define PAIR(X) \ + { #X, T_##X } + +static const osr_cs_wkt_tokens tokens[] = { + PAIR(PARAM_MT), PAIR(PARAMETER), PAIR(CONCAT_MT), PAIR(INVERSE_MT), + PAIR(PASSTHROUGH_MT), + + PAIR(PROJCS), PAIR(PROJECTION), PAIR(GEOGCS), PAIR(DATUM), + PAIR(SPHEROID), PAIR(PRIMEM), PAIR(UNIT), PAIR(GEOCCS), + PAIR(AUTHORITY), PAIR(VERT_CS), PAIR(VERT_DATUM), PAIR(COMPD_CS), + PAIR(AXIS), PAIR(TOWGS84), PAIR(FITTED_CS), PAIR(LOCAL_CS), + PAIR(LOCAL_DATUM), + + PAIR(EXTENSION)}; + +// --------------------------------------------------------------------------- + +int pj_wkt1_lex(YYSTYPE * /*pNode */, pj_wkt1_parse_context *context) { + size_t i; + const char *pszInput = context->pszNext; + + /* -------------------------------------------------------------------- */ + /* Skip white space. */ + /* -------------------------------------------------------------------- */ + while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 || + *pszInput == 13) + pszInput++; + + context->pszLastSuccess = pszInput; + + if (*pszInput == '\0') { + context->pszNext = pszInput; + return EOF; + } + + /* -------------------------------------------------------------------- */ + /* Recognize node names. */ + /* -------------------------------------------------------------------- */ + if (isalpha(*pszInput)) { + for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) { + if (ci_starts_with(pszInput, tokens[i].pszToken) && + !isalpha(pszInput[strlen(tokens[i].pszToken)])) { + context->pszNext = pszInput + strlen(tokens[i].pszToken); + return tokens[i].nTokenVal; + } + } + } + + /* -------------------------------------------------------------------- */ + /* Recognize double quoted strings. */ + /* -------------------------------------------------------------------- */ + if (*pszInput == '"') { + pszInput++; + while (*pszInput != '\0' && *pszInput != '"') + pszInput++; + if (*pszInput == '\0') { + context->pszNext = pszInput; + return EOF; + } + context->pszNext = pszInput + 1; + return T_STRING; + } + + /* -------------------------------------------------------------------- */ + /* Recognize numerical values. */ + /* -------------------------------------------------------------------- */ + + if (((*pszInput == '-' || *pszInput == '+') && pszInput[1] >= '0' && + pszInput[1] <= '9') || + (*pszInput >= '0' && *pszInput <= '9')) { + if (*pszInput == '-' || *pszInput == '+') + pszInput++; + + // collect non-decimal part of number + while (*pszInput >= '0' && *pszInput <= '9') + pszInput++; + + // collect decimal places. + if (*pszInput == '.') { + pszInput++; + while (*pszInput >= '0' && *pszInput <= '9') + pszInput++; + } + + // collect exponent + if (*pszInput == 'e' || *pszInput == 'E') { + pszInput++; + if (*pszInput == '-' || *pszInput == '+') + pszInput++; + while (*pszInput >= '0' && *pszInput <= '9') + pszInput++; + } + + context->pszNext = pszInput; + + return T_NUMBER; + } + + /* -------------------------------------------------------------------- */ + /* Recognize identifiers. */ + /* -------------------------------------------------------------------- */ + if ((*pszInput >= 'A' && *pszInput <= 'Z') || + (*pszInput >= 'a' && *pszInput <= 'z')) { + pszInput++; + while ((*pszInput >= 'A' && *pszInput <= 'Z') || + (*pszInput >= 'a' && *pszInput <= 'z')) + pszInput++; + context->pszNext = pszInput; + return T_IDENTIFIER; + } + + /* -------------------------------------------------------------------- */ + /* Handle special tokens. */ + /* -------------------------------------------------------------------- */ + context->pszNext = pszInput + 1; + return *pszInput; +} + +//! @endcond diff --git a/src/wkt1_parser.h b/src/wkt1_parser.h new file mode 100644 index 00000000..f04ee67f --- /dev/null +++ b/src/wkt1_parser.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: WKT1 parser grammar + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2013, Even Rouault + * + * 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. + ****************************************************************************/ + +#ifndef PJ_WKT1_PARSER_H_INCLUDED +#define PJ_WKT1_PARSER_H_INCLUDED + +#ifndef DOXYGEN_SKIP + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pj_wkt1_parse_context pj_wkt1_parse_context; + +#include "wkt1_generated_parser.h" + +void pj_wkt1_error( pj_wkt1_parse_context *context, const char *msg ); +int pj_wkt1_lex(YYSTYPE* pNode, pj_wkt1_parse_context *context); +int pj_wkt1_parse(pj_wkt1_parse_context *context); + +#ifdef __cplusplus +} + +std::string pj_wkt1_parse(const std::string& wkt); + +#endif + +#endif /* #ifndef DOXYGEN_SKIP */ + +#endif /* PJ_WKT1_PARSER_H_INCLUDED */ diff --git a/src/wkt2_generated_parser.c b/src/wkt2_generated_parser.c new file mode 100644 index 00000000..6d816135 --- /dev/null +++ b/src/wkt2_generated_parser.c @@ -0,0 +1,3140 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse pj_wkt2_parse +#define yylex pj_wkt2_lex +#define yyerror pj_wkt2_error +#define yydebug pj_wkt2_debug +#define yynerrs pj_wkt2_nerrs + + +/* Copy the first part of user declarations. */ + + +/****************************************************************************** + * Project: PROJ + * Purpose: WKT2 parser grammar + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2018 Even Rouault, + * + * 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. + ****************************************************************************/ + +#include "wkt2_parser.h" + + + + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "wkt2_generated_parser.h". */ +#ifndef YY_PJ_WKT2_SRC_WKT2_GENERATED_PARSER_H_INCLUDED +# define YY_PJ_WKT2_SRC_WKT2_GENERATED_PARSER_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int pj_wkt2_debug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + END = 0, + T_PROJECTION = 258, + T_DATUM = 259, + T_SPHEROID = 260, + T_PRIMEM = 261, + T_UNIT = 262, + T_AXIS = 263, + T_PARAMETER = 264, + T_GEODCRS = 265, + T_LENGTHUNIT = 266, + T_ANGLEUNIT = 267, + T_SCALEUNIT = 268, + T_TIMEUNIT = 269, + T_ELLIPSOID = 270, + T_CS = 271, + T_ID = 272, + T_PROJCRS = 273, + T_BASEGEODCRS = 274, + T_MERIDIAN = 275, + T_BEARING = 276, + T_ORDER = 277, + T_ANCHOR = 278, + T_CONVERSION = 279, + T_METHOD = 280, + T_REMARK = 281, + T_GEOGCRS = 282, + T_BASEGEOGCRS = 283, + T_SCOPE = 284, + T_AREA = 285, + T_BBOX = 286, + T_CITATION = 287, + T_URI = 288, + T_VERTCRS = 289, + T_VDATUM = 290, + T_GEOIDMODEL = 291, + T_COMPOUNDCRS = 292, + T_PARAMETERFILE = 293, + T_COORDINATEOPERATION = 294, + T_SOURCECRS = 295, + T_TARGETCRS = 296, + T_INTERPOLATIONCRS = 297, + T_OPERATIONACCURACY = 298, + T_CONCATENATEDOPERATION = 299, + T_STEP = 300, + T_BOUNDCRS = 301, + T_ABRIDGEDTRANSFORMATION = 302, + T_DERIVINGCONVERSION = 303, + T_TDATUM = 304, + T_CALENDAR = 305, + T_TIMEORIGIN = 306, + T_TIMECRS = 307, + T_VERTICALEXTENT = 308, + T_TIMEEXTENT = 309, + T_USAGE = 310, + T_DYNAMIC = 311, + T_FRAMEEPOCH = 312, + T_MODEL = 313, + T_VELOCITYGRID = 314, + T_ENSEMBLE = 315, + T_MEMBER = 316, + T_ENSEMBLEACCURACY = 317, + T_DERIVEDPROJCRS = 318, + T_BASEPROJCRS = 319, + T_EDATUM = 320, + T_ENGCRS = 321, + T_PDATUM = 322, + T_PARAMETRICCRS = 323, + T_PARAMETRICUNIT = 324, + T_BASEVERTCRS = 325, + T_BASEENGCRS = 326, + T_BASEPARAMCRS = 327, + T_BASETIMECRS = 328, + T_EPOCH = 329, + T_COORDEPOCH = 330, + T_COORDINATEMETADATA = 331, + T_POINTMOTIONOPERATION = 332, + T_GEODETICCRS = 333, + T_GEODETICDATUM = 334, + T_PROJECTEDCRS = 335, + T_PRIMEMERIDIAN = 336, + T_GEOGRAPHICCRS = 337, + T_TRF = 338, + T_VERTICALCRS = 339, + T_VERTICALDATUM = 340, + T_VRF = 341, + T_TIMEDATUM = 342, + T_TEMPORALQUANTITY = 343, + T_ENGINEERINGDATUM = 344, + T_ENGINEERINGCRS = 345, + T_PARAMETRICDATUM = 346, + T_AFFINE = 347, + T_CARTESIAN = 348, + T_CYLINDRICAL = 349, + T_ELLIPSOIDAL = 350, + T_LINEAR = 351, + T_PARAMETRIC = 352, + T_POLAR = 353, + T_SPHERICAL = 354, + T_VERTICAL = 355, + T_TEMPORAL = 356, + T_TEMPORALCOUNT = 357, + T_TEMPORALMEASURE = 358, + T_ORDINAL = 359, + T_TEMPORALDATETIME = 360, + T_NORTH = 361, + T_NORTHNORTHEAST = 362, + T_NORTHEAST = 363, + T_EASTNORTHEAST = 364, + T_EAST = 365, + T_EASTSOUTHEAST = 366, + T_SOUTHEAST = 367, + T_SOUTHSOUTHEAST = 368, + T_SOUTH = 369, + T_SOUTHSOUTHWEST = 370, + T_SOUTHWEST = 371, + T_WESTSOUTHWEST = 372, + T_WEST = 373, + T_WESTNORTHWEST = 374, + T_NORTHWEST = 375, + T_NORTHNORTHWEST = 376, + T_UP = 377, + T_DOWN = 378, + T_GEOCENTRICX = 379, + T_GEOCENTRICY = 380, + T_GEOCENTRICZ = 381, + T_COLUMNPOSITIVE = 382, + T_COLUMNNEGATIVE = 383, + T_ROWPOSITIVE = 384, + T_ROWNEGATIVE = 385, + T_DISPLAYRIGHT = 386, + T_DISPLAYLEFT = 387, + T_DISPLAYUP = 388, + T_DISPLAYDOWN = 389, + T_FORWARD = 390, + T_AFT = 391, + T_PORT = 392, + T_STARBOARD = 393, + T_CLOCKWISE = 394, + T_COUNTERCLOCKWISE = 395, + T_TOWARDS = 396, + T_AWAYFROM = 397, + T_FUTURE = 398, + T_PAST = 399, + T_UNSPECIFIED = 400, + T_STRING = 401, + T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE = 402 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int pj_wkt2_parse (pj_wkt2_parse_context *context); + +#endif /* !YY_PJ_WKT2_SRC_WKT2_GENERATED_PARSER_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 99 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 3313 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 163 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 324 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 651 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 1343 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 402 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 159, 161, 2, 153, 162, 154, 148, 2, 2, 150, + 151, 152, 2, 2, 2, 2, 2, 2, 155, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 149, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 156, 2, 2, 2, 2, 2, + 157, 158, 2, 160, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 206, 206, 206, 206, 206, 206, 206, 207, 207, + 207, 208, 211, 211, 212, 212, 212, 213, 216, 216, + 216, 216, 217, 217, 217, 217, 218, 218, 218, 219, + 219, 219, 223, 227, 227, 229, 231, 233, 233, 235, + 235, 237, 239, 241, 243, 245, 245, 247, 247, 249, + 249, 249, 249, 251, 251, 255, 257, 261, 262, 263, + 265, 265, 267, 269, 271, 273, 277, 278, 281, 282, + 284, 286, 288, 291, 292, 293, 295, 297, 299, 299, + 301, 304, 305, 307, 307, 312, 312, 314, 314, 316, + 318, 320, 324, 325, 328, 329, 330, 332, 332, 333, + 336, 337, 341, 342, 343, 347, 348, 349, 350, 352, + 356, 358, 361, 363, 366, 367, 368, 369, 370, 371, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 383, + 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 401, 403, 405, 409, 414, 416, + 418, 420, 422, 426, 431, 432, 434, 436, 438, 442, + 446, 448, 448, 450, 450, 455, 460, 461, 462, 463, + 464, 465, 466, 468, 470, 472, 472, 474, 474, 476, + 478, 480, 482, 484, 486, 490, 492, 496, 496, 499, + 502, 507, 507, 507, 507, 507, 510, 515, 515, 515, + 515, 518, 522, 523, 525, 541, 545, 546, 548, 548, + 550, 550, 556, 556, 558, 560, 567, 567, 567, 569, + 576, 577, 578, 579, 581, 588, 595, 596, 597, 599, + 601, 601, 601, 601, 601, 601, 601, 601, 601, 604, + 604, 604, 606, 606, 608, 608, 608, 610, 615, 621, + 626, 629, 632, 633, 634, 635, 636, 637, 638, 639, + 640, 643, 644, 645, 646, 647, 648, 649, 650, 653, + 654, 655, 656, 657, 658, 659, 660, 663, 664, 667, + 668, 669, 670, 675, 676, 677, 678, 679, 680, 681, + 682, 683, 686, 687, 688, 689, 692, 693, 694, 695, + 698, 699, 702, 703, 708, 709, 712, 713, 714, 715, + 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, + 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, + 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, + 748, 749, 750, 751, 752, 753, 755, 758, 760, 762, + 764, 766, 768, 784, 784, 786, 794, 795, 797, 798, + 800, 808, 809, 811, 813, 815, 820, 821, 823, 825, + 827, 829, 831, 833, 835, 840, 844, 846, 849, 852, + 853, 854, 856, 857, 859, 864, 865, 867, 867, 869, + 873, 873, 873, 873, 875, 883, 891, 900, 910, 911, + 913, 915, 915, 917, 917, 920, 921, 925, 931, 932, + 933, 935, 935, 937, 939, 941, 945, 950, 950, 952, + 955, 956, 960, 965, 965, 965, 967, 969, 970, 971, + 972, 974, 977, 979, 983, 989, 989, 993, 993, 995, + 1000, 1001, 1002, 1003, 1005, 1011, 1011, 1013, 1015, 1019, + 1027, 1028, 1030, 1032, 1034, 1038, 1038, 1040, 1042, 1047, + 1048, 1050, 1052, 1054, 1056, 1060, 1060, 1062, 1068, 1075, + 1075, 1078, 1085, 1086, 1087, 1088, 1089, 1091, 1095, 1097, + 1099, 1099, 1103, 1108, 1108, 1108, 1112, 1117, 1117, 1119, + 1123, 1123, 1127, 1132, 1134, 1138, 1138, 1142, 1147, 1149, + 1153, 1154, 1155, 1156, 1157, 1159, 1159, 1161, 1164, 1166, + 1166, 1168, 1170, 1172, 1176, 1183, 1183, 1185, 1186, 1187, + 1188, 1190, 1192, 1196, 1201, 1203, 1206, 1211, 1215, 1221, + 1221, 1221, 1221, 1221, 1221, 1225, 1230, 1232, 1238, 1245, + 1255, 1261, 1263, 1265, 1270, 1275, 1281, 1281, 1283, 1286, + 1290, 1295, 1301, 1304, 1309, 1315, 1318, 1323, 1329, 1332, + 1337, 1343, 1344, 1345, 1346, 1347, 1349, 1351, 1353, 1353, + 1353, 1355, 1355, 1360, 1363, 1363, 1366, 1367, 1368, 1370, + 1374, 1375, 1377, 1379, 1379, 1380, 1380, 1381, 1381, 1381, + 1382, 1382, 1383, 1383, 1384, 1384, 1385, 1385, 1387, 1387, + 1388, 1388, 1389, 1389, 1390, 1390, 1394, 1401, 1402, 1403, + 1404, 1405, 1406, 1407, 1409, 1411, 1413, 1415, 1417, 1419, + 1421, 1423, 1425, 1427, 1432, 1439, 1440, 1441, 1442, 1443, + 1445, 1450, 1458, 1458, 1458, 1460, 1461, 1462, 1463, 1465, + 1467, 1472, 1478, 1480, 1487, 1487, 1489, 1490, 1491, 1492, + 1494, 1496 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 1 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of string\"", "error", "$undefined", "\"PROJECTION\"", + "\"DATUM\"", "\"SPHEROID\"", "\"PRIMEM\"", "\"UNIT\"", "\"AXIS\"", + "\"PARAMETER\"", "\"GEODCRS\"", "\"LENGTHUNIT\"", "\"ANGLEUNIT\"", + "\"SCALEUNIT\"", "\"TIMEUNIT\"", "\"ELLIPSOID\"", "\"CS\"", "\"ID\"", + "\"PROJCRS\"", "\"BASEGEODCRS\"", "\"MERIDIAN\"", "\"BEARING\"", + "\"ORDER\"", "\"ANCHOR\"", "\"CONVERSION\"", "\"METHOD\"", "\"REMARK\"", + "\"GEOGCRS\"", "\"BASEGEOGCRS\"", "\"SCOPE\"", "\"AREA\"", "\"BBOX\"", + "\"CITATION\"", "\"URI\"", "\"VERTCRS\"", "\"VDATUM\"", "\"GEOIDMODEL\"", + "\"COMPOUNDCRS\"", "\"PARAMETERFILE\"", "\"COORDINATEOPERATION\"", + "\"SOURCECRS\"", "\"TARGETCRS\"", "\"INTERPOLATIONCRS\"", + "\"OPERATIONACCURACY\"", "\"CONCATENATEDOPERATION\"", "\"STEP\"", + "\"BOUNDCRS\"", "\"ABRIDGEDTRANSFORMATION\"", "\"DERIVINGCONVERSION\"", + "\"TDATUM\"", "\"CALENDAR\"", "\"TIMEORIGIN\"", "\"TIMECRS\"", + "\"VERTICALEXTENT\"", "\"TIMEEXTENT\"", "\"USAGE\"", "\"DYNAMIC\"", + "\"FRAMEEPOCH\"", "\"MODEL\"", "\"VELOCITYGRID\"", "\"ENSEMBLE\"", + "\"MEMBER\"", "\"ENSEMBLEACCURACY\"", "\"DERIVEDPROJCRS\"", + "\"BASEPROJCRS\"", "\"EDATUM\"", "\"ENGCRS\"", "\"PDATUM\"", + "\"PARAMETRICCRS\"", "\"PARAMETRICUNIT\"", "\"BASEVERTCRS\"", + "\"BASEENGCRS\"", "\"BASEPARAMCRS\"", "\"BASETIMECRS\"", "\"EPOCH\"", + "\"COORDEPOCH\"", "\"COORDINATEMETADATA\"", "\"POINTMOTIONOPERATION\"", + "\"GEODETICCRS\"", "\"GEODETICDATUM\"", "\"PROJECTEDCRS\"", + "\"PRIMEMERIDIAN\"", "\"GEOGRAPHICCRS\"", "\"TRF\"", "\"VERTICALCRS\"", + "\"VERTICALDATUM\"", "\"VRF\"", "\"TIMEDATUM\"", "\"TEMPORALQUANTITY\"", + "\"ENGINEERINGDATUM\"", "\"ENGINEERINGCRS\"", "\"PARAMETRICDATUM\"", + "\"affine\"", "\"Cartesian\"", "\"cylindrical\"", "\"ellipsoidal\"", + "\"linear\"", "\"parametric\"", "\"polar\"", "\"spherical\"", + "\"vertical\"", "\"temporal\"", "\"temporalCount\"", + "\"temporalMeasure\"", "\"ordinal\"", "\"temporalDateTime\"", + "\"north\"", "\"northNorthEast\"", "\"northEast\"", "\"eastNorthEast\"", + "\"east\"", "\"eastSouthEast\"", "\"southEast\"", "\"southSouthEast\"", + "\"south\"", "\"southSouthWest\"", "\"southWest\"", "\"westSouthWest\"", + "\"west\"", "\"westNorthWest\"", "\"northWest\"", "\"northNorthWest\"", + "\"up\"", "\"down\"", "\"geocentricX\"", "\"geocentricY\"", + "\"geocentricZ\"", "\"columnPositive\"", "\"columnNegative\"", + "\"rowPositive\"", "\"rowNegative\"", "\"displayRight\"", + "\"displayLeft\"", "\"displayUp\"", "\"displayDown\"", "\"forward\"", + "\"aft\"", "\"port\"", "\"starboard\"", "\"clockwise\"", + "\"counterClockwise\"", "\"towards\"", "\"awayFrom\"", "\"future\"", + "\"part\"", "\"unspecified\"", "\"string\"", "\"unsigned integer\"", + "'.'", "'E'", "'1'", "'2'", "'3'", "'+'", "'-'", "':'", "'T'", "'Z'", + "'['", "'('", "']'", "')'", "','", "$accept", "input", "datum", "crs", + "period", "number", "signed_numeric_literal_with_sign", + "signed_numeric_literal", "unsigned_numeric_literal", "opt_sign", + "approximate_numeric_literal", "mantissa", "exponent", "signed_integer", + "exact_numeric_literal", "opt_period_unsigned_integer", + "unsigned_integer", "sign", "colon", "hyphen", "datetime", + "opt_24_hour_clock", "year", "month", "day", "_24_hour_clock", + "opt_colon_minute_colon_second_time_zone_designator", + "opt_colon_second_time_zone_designator", "time_designator", "hour", + "minute", "second_time_zone_designator", "seconds_integer", + "seconds_fraction", "time_zone_designator", "utc_designator", + "local_time_zone_designator", "opt_colon_minute", "left_delimiter", + "right_delimiter", "wkt_separator", "quoted_latin_text", + "quoted_unicode_text", "opt_separator_scope_extent_identifier_remark", + "no_opt_separator_scope_extent_identifier_remark", + "opt_identifier_list_remark", + "scope_extent_opt_identifier_list_opt_remark", + "scope_extent_opt_identifier_list_remark", + "usage_list_opt_identifier_list_remark", "usage", "usage_keyword", + "scope", "scope_keyword", "scope_text_description", "extent", + "extent_opt_identifier_list_remark", "area_description", + "area_description_keyword", "area_text_description", + "geographic_bounding_box", "geographic_bounding_box_keyword", + "lower_left_latitude", "lower_left_longitude", "upper_right_latitude", + "upper_right_longitude", "vertical_extent", "opt_separator_length_unit", + "vertical_extent_keyword", "vertical_extent_minimum_height", + "vertical_extent_maximum_height", "temporal_extent", + "temporal_extent_keyword", "temporal_extent_start", + "temporal_extent_end", "identifier", + "opt_version_authority_citation_uri", "identifier_keyword", + "authority_name", "authority_unique_identifier", "version", + "authority_citation", "citation_keyword", "citation", "id_uri", + "uri_keyword", "uri", "remark", "remark_keyword", "unit", "spatial_unit", + "angle_or_length_or_parametric_or_scale_unit", + "angle_or_length_or_parametric_or_scale_unit_keyword", + "angle_or_length_or_scale_unit", "angle_or_length_or_scale_unit_keyword", + "angle_unit", "opt_separator_identifier_list", "length_unit", + "time_unit", "opt_separator_conversion_factor_identifier_list", + "angle_unit_keyword", "length_unit_keyword", "time_unit_keyword", + "unit_name", "conversion_factor", + "coordinate_system_scope_extent_identifier_remark", + "spatial_cs_scope_extent_identifier_remark", + "opt_separator_spatial_axis_list_opt_separator_cs_unit_scope_extent_identifier_remark", + "temporalcountmeasure_cs_scope_extent_identifier_remark", + "ordinaldatetime_cs_scope_extent_identifier_remark", + "opt_separator_ordinaldatetime_axis_list_scope_extent_identifier_remark", + "cs_keyword", "spatial_cs_type", "temporalcountmeasure_cs_type", + "ordinaldatetime_cs_type", "dimension", "spatial_axis", + "temporalcountmeasure_axis", "ordinaldatetime_axis", "axis_keyword", + "axis_name_abbrev", + "axis_direction_opt_axis_order_spatial_unit_identifier_list", + "north_south_options_spatial_unit", + "clockwise_counter_clockwise_options_spatial_unit", + "axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list", + "axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list_options", + "axis_direction_opt_axis_order_identifier_list", "north_south_options", + "clockwise_counter_clockwise_options", + "axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list", + "axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list_options", + "opt_separator_axis_time_unit_identifier_list", + "axis_direction_except_n_s_cw_ccw_opt_axis_time_unit_identifier_list_options", + "axis_direction_except_n_s_cw_ccw", "meridian", "meridian_keyword", + "bearing", "bearing_keyword", "axis_order", "axis_order_keyword", + "cs_unit", "datum_ensemble", "geodetic_datum_ensemble_without_pm", + "datum_ensemble_member_list_ellipsoid_accuracy_identifier_list", + "opt_separator_datum_ensemble_identifier_list", + "vertical_datum_ensemble", + "datum_ensemble_member_list_accuracy_identifier_list", + "datum_ensemble_keyword", "datum_ensemble_name", "datum_ensemble_member", + "opt_datum_ensemble_member_identifier_list", + "datum_ensemble_member_keyword", "datum_ensemble_member_name", + "datum_ensemble_member_identifier", "datum_ensemble_accuracy", + "datum_ensemble_accuracy_keyword", "accuracy", + "datum_ensemble_identifier", "dynamic_crs", "dynamic_crs_keyword", + "frame_reference_epoch", "frame_reference_epoch_keyword", + "reference_epoch", "opt_separator_deformation_model_id", + "deformation_model_id", "opt_separator_identifier", + "deformation_model_id_keyword", "deformation_model_name", "geodetic_crs", + "static_geodetic_crs", "static_geographic_crs", "dynamic_geodetic_crs", + "dynamic_geographic_crs", + "opt_prime_meridian_coordinate_system_scope_extent_identifier_remark", + "crs_name", "geodetic_crs_keyword", "geographic_crs_keyword", + "geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm", + "ellipsoid", "opt_separator_length_unit_identifier_list", + "ellipsoid_keyword", "ellipsoid_name", "semi_major_axis", + "inverse_flattening", "prime_meridian", "prime_meridian_keyword", + "prime_meridian_name", "irm_longitude_opt_separator_identifier_list", + "geodetic_reference_frame_without_pm", + "geodetic_reference_frame_keyword", "datum_name", + "opt_separator_datum_anchor_identifier_list", "datum_anchor", + "datum_anchor_keyword", "datum_anchor_description", "projected_crs", + "projected_crs_keyword", "base_geodetic_crs", "base_static_geodetic_crs", + "opt_separator_pm_ellipsoidal_cs_unit", "base_dynamic_geodetic_crs", + "base_geodetic_crs_keyword", "base_crs_name", "ellipsoidal_cs_unit", + "map_projection", "parameter_list_identifier_list", + "map_projection_keyword", "map_projection_name", "map_projection_method", + "map_projection_method_keyword", "map_projection_method_name", + "map_projection_parameter", "opt_separator_param_unit_identifier_list", + "parameter_keyword", "parameter_name", "parameter_value", + "map_projection_parameter_unit", "vertical_crs", "static_vertical_crs", + "dynamic_vertical_crs", + "vertical_reference_frame_or_vertical_datum_ensemble", + "vertical_cs_opt_geoid_model_id_scope_extent_identifier_remark", + "opt_separator_cs_unit_opt_geoid_model_id_scope_extent_identifier_remark", + "geoid_model_id", "geoid_model_keyword", "geoid_model_name", + "vertical_crs_keyword", "vertical_reference_frame", + "vertical_reference_frame_keyword", "engineering_crs", + "engineering_crs_keyword", "engineering_datum", + "engineering_datum_keyword", "parametric_crs", "parametric_crs_keyword", + "parametric_datum", "parametric_datum_keyword", "temporal_crs", + "temporal_crs_keyword", "temporal_datum", + "opt_separator_temporal_datum_end", "temporal_datum_keyword", + "temporal_origin", "temporal_origin_keyword", + "temporal_origin_description", "calendar", "calendar_keyword", + "calendar_identifier", "deriving_conversion", + "parameter_or_parameter_file", "opt_separator_deriving_conversion_end", + "deriving_conversion_keyword", "deriving_conversion_name", + "operation_method", "operation_method_keyword", "operation_method_name", + "operation_parameter", "parameter_unit", + "length_or_angle_or_scale_or_time_or_parametric_unit", + "length_or_angle_or_scale_or_time_or_parametric_unit_keyword", + "operation_parameter_file", "parameter_file_keyword", + "parameter_file_name", "derived_geodetic_crs", "derived_geographic_crs", + "derived_projected_crs", "derived_projected_crs_keyword", + "derived_crs_name", "base_projected_crs", "base_projected_crs_keyword", + "derived_vertical_crs", "base_vertical_crs", "base_static_vertical_crs", + "base_dynamic_vertical_crs", "base_vertical_crs_keyword", + "derived_engineering_crs", "base_engineering_crs", + "base_engineering_crs_keyword", "derived_parametric_crs", + "base_parametric_crs", "base_parametric_crs_keyword", + "derived_temporal_crs", "base_temporal_crs", "base_temporal_crs_keyword", + "compound_crs", "compound_crs_other_components", "compound_crs_keyword", + "compound_crs_name", "horizontal_crs", "geographic2D_crs", + "metadata_coordinate_epoch", "coordinate_epoch_keyword", + "coordinate_epoch", "coordinate_metadata", "coordinate_metadata_crs", + "coordinate_metadata_keyword", "static_crs", + "dynamic_crs_coordinate_metadata", "coordinate_operation", + "opt_coordinate_operation_end", "operation_keyword", "operation_name", + "source_crs", "source_crs_keyword", "target_crs", "target_crs_keyword", + "interpolation_crs", "interpolation_crs_keyword", "operation_accuracy", + "operation_accuracy_keyword", "point_motion_operation", + "opt_point_motion_operation_end", "point_motion_keyword", + "concatenated_operation", "step", "opt_concatenated_operation_end", + "concatenated_operation_keyword", "step_keyword", "bound_crs", + "bound_crs_keyword", "abridged_coordinate_transformation", + "abridged_parameter_or_parameter_file", + "opt_end_abridged_coordinate_transformation", + "abridged_transformation_keyword", "abridged_transformation_parameter", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 399, 400, 401, 402, 46, 69, + 49, 50, 51, 43, 45, 58, 84, 90, 91, 40, + 93, 41, 44 +}; +# endif + +#define YYPACT_NINF -1109 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-1109))) + +#define YYTABLE_NINF -606 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 782, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, 77, -1109, -1109, + -1109, 367, -1109, -1109, -1109, 367, -1109, -1109, -1109, -1109, + -1109, 367, 367, -1109, 367, -1109, 367, -1109, 367, -1109, + 367, -1109, -1109, -1109, 367, -1109, 367, -1109, 367, -1109, + 367, -1109, 367, -1109, 367, -1109, 367, -1109, 367, -1109, + -1109, -1109, 367, -1109, -1109, -1109, -1109, -1109, 367, -1109, + 367, -1109, 367, -1109, 367, -1109, 367, -1109, 367, -1109, + -1109, -1109, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + 681, -44, -44, -44, 239, -1109, -1109, 175, -1109, 175, + -1109, 175, 175, -1109, 175, -1109, 175, 175, -1109, 175, + 175, 175, 175, 175, 175, 175, 175, 175, -1109, 175, + -1109, 175, -1109, -1109, -1109, -1109, 190, -1109, -1109, -1109, + -1109, -1109, 207, 218, 223, 249, -1109, -1109, -1109, -1109, + 409, -1109, 175, -1109, 175, 175, 175, -1109, 175, 367, + -1109, 933, 234, 467, 467, 788, 269, 209, 132, 654, + 295, 409, 56, 409, 391, 409, 299, 312, 409, 354, + 324, -1109, -1109, -1109, 509, 239, 239, 239, 406, 681, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, 644, -1109, -1109, + -1109, -1109, 274, 283, 279, 788, -1109, 175, -1109, 175, + 367, -1109, -1109, -1109, -1109, 367, 175, 367, 175, -1109, + 175, -1109, -1109, 367, 175, 175, 175, -1109, 175, 175, + 175, -1109, -1109, 175, 367, -1109, -1109, 367, 175, 175, + -1109, 175, -1109, -1109, 367, -1109, 175, 175, 367, -1109, + -1109, 175, 175, 367, -1109, -1109, 175, 175, 367, -1109, + -1109, 175, 175, 367, -1109, -1109, 175, 175, 367, 175, + 367, -1109, -1109, 175, 367, -1109, -1109, 367, -1109, -1109, + 367, 175, -1109, -1109, -1109, -1109, 367, 175, 175, 175, + -1109, 175, 367, 409, -1109, 444, 644, -1109, -1109, 298, + 409, 155, 409, 409, -44, -44, 119, 400, 102, 414, + -44, 119, 102, 414, 788, 409, 452, 483, -44, -44, + 99, 497, 414, -44, 499, -1109, 499, -44, 497, 414, + -44, 497, 414, -44, 497, 414, -44, -1109, -1109, 591, + 129, -1109, -44, 414, -44, -44, -44, 289, 644, 406, + 505, 406, 493, 681, -1109, 644, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, 175, 175, 367, -1109, 367, -1109, + -1109, 175, 175, 367, 175, -1109, -1109, -1109, 175, 175, + 175, -1109, 175, 367, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, 367, 409, 175, 367, -1109, 175, 367, -1109, 175, + 175, 409, 175, -1109, 175, -1109, 175, -1109, 409, 175, + 367, -1109, 175, 175, 175, 367, 409, 175, 175, 175, + 175, -1109, 409, 409, 175, 175, 409, 175, 175, 409, + 175, 175, -1109, -1109, 331, -1109, 409, 175, -1109, 409, + 175, 175, 175, 175, 175, 367, 175, 367, 175, 367, + 409, 279, 409, 175, -1109, 175, 367, 175, -1109, 175, + 367, 409, -1109, 515, 527, -44, -44, -1109, -1109, 499, + -1109, 1202, 526, 499, 409, 234, 102, 587, 409, 644, + 1171, -1109, 497, -44, 497, -44, 222, 102, -1109, 497, + 448, 409, 497, -1109, 225, -1109, -44, 409, 234, 497, + 1364, -1109, 497, 323, -1109, -1109, -1109, -1109, 497, 275, + -1109, 497, 345, -1109, 497, 95, -1109, -1109, 644, -1109, + -1109, 644, -1109, -1109, -1109, 497, 209, 83, 275, 960, + -1109, -44, 960, -1109, -44, 826, -1109, -44, -1109, 644, + -1109, 505, 91, -44, 520, 409, -44, -1109, 175, -1109, + -1109, 409, -1109, 409, -1109, 175, -1109, 409, 175, -1109, + 175, -1109, 175, 409, -1109, -1109, -1109, 367, -1109, 279, + 409, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, -1109, 175, 175, 175, -1109, -1109, + 175, 409, -1109, 175, 175, 175, 409, 409, -1109, -1109, + 175, 175, 367, -1109, 409, -1109, -1109, 175, -1109, 175, + 409, 175, 409, 175, 409, 409, 409, 409, 409, 409, + 409, 402, 439, -1109, 958, 409, 175, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, 175, 367, + 175, 367, -1109, 175, 367, 175, 367, 175, 367, 175, + 367, 175, -1109, 367, 175, 175, 175, 175, 175, -1109, + 175, -1109, 367, 175, -1109, -1109, 367, -1109, 175, -1109, + 367, -1109, 175, 527, -1109, -1109, -1109, -1109, -1109, -1109, + 278, -1109, -44, 644, -1109, 386, 386, 386, 444, -1109, + 505, 70, 126, 409, -1109, -1109, -1109, -1109, -44, -1109, + 444, 605, -1109, 386, -1109, 213, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, 644, -1109, -1109, 644, 644, -1109, + 449, -1109, -1109, -1109, -1109, 452, 93, 597, 453, -1109, + -44, 549, -1109, -44, 300, -1109, 1202, 377, -1109, 1202, + 390, -1109, 591, -1109, 471, -1109, 382, -1109, 345, 95, + 91, -44, 888, 409, -44, 499, 409, 92, 505, -1109, + 175, -1109, 175, -1109, -1109, -1109, -1109, 175, 175, 175, + 175, 788, 409, 175, 175, -1109, -1109, -1109, 367, 175, + -1109, -1109, -1109, 175, -1109, 175, 175, 175, 409, -1109, + 464, 449, -1109, 958, 644, -1109, 409, -1109, 175, -1109, + 175, -1109, 175, -1109, -1109, 409, 175, 175, 175, -1109, + 409, 175, 175, -1109, 175, 175, -1109, 175, -1109, -1109, + 175, -1109, 409, 175, 175, -1109, -1109, 175, 175, 175, + 367, -1109, 175, -1109, -1109, -1109, -1109, -1109, 409, 175, + 409, 409, 409, 409, 135, -1109, -1109, -1109, 91, 409, + -44, 229, 788, 621, 409, 409, -1109, -1109, -1109, 644, + -1109, -1109, -1109, -1109, -1109, 443, -1109, -1109, 300, -1109, + 377, -1109, -1109, -1109, 377, -1109, -1109, 1202, -1109, 1202, + 591, -1109, 869, 409, 444, -1109, -1109, -1109, 1202, -44, + 175, 91, -1109, 175, 175, 175, 175, 175, -1109, 175, + -1109, -1109, 175, -1109, -1109, -1109, -1109, -1109, 367, 175, + -1109, 175, -1109, -1109, 1154, 409, 175, 175, 175, -1109, + 175, 175, 175, 175, -1109, 175, -1109, 175, -1109, -1109, + 409, -1109, -1109, 175, 175, 175, 367, 175, -1109, 175, + 409, -1109, 175, 520, 367, -1109, 175, -1109, 632, 632, + 632, -1109, 327, 409, 788, 409, -44, -1109, 632, 627, + -1109, -1109, 261, 619, 602, 377, -1109, -1109, -1109, -1109, + 1202, 348, 409, -1109, -1109, -1109, 1035, -1109, 681, -1109, + 550, -1109, 409, 367, -44, 920, 409, -1109, 175, 367, + 175, 367, 175, 367, 175, 175, 175, -1109, 175, -1109, + 175, 175, 503, 627, -1109, 175, 175, -1109, 175, -1109, + -1109, 175, -1109, 175, -1109, -1109, 175, 409, -1109, -1109, + -1109, -1109, -1109, -1109, 175, -1109, 367, -1109, 92, 175, + -1109, 175, 175, -1109, 560, -1109, -44, -1109, -44, 675, + -1109, -44, -1109, -1109, -1109, 409, 788, 624, -1109, -1109, + 619, 602, 602, -1109, 1202, -1109, -1109, 409, -44, 409, + 444, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, 367, -1109, 367, 175, 175, -1109, + 175, 175, -1109, 175, 175, -1109, 175, -1109, -1109, 175, + 175, 367, 175, -1109, -1109, -1109, -1109, 409, -1109, 175, + 175, 175, -44, -44, -1109, -1109, 1117, 1310, -1109, 1271, + 409, 1065, -1109, -1109, -44, 602, -1109, 788, 409, 784, + 409, 409, 175, 175, 175, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, 175, -1109, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, 175, 175, -1109, + -1109, -1109, -1109, -1109, 409, -1109, 175, 175, 175, 175, + 175, 175, 409, -1109, 175, -1109, 175, -1109, 175, -1109, + 175, -1109, -1109, 175, 367, -1109, -1109, 788, 409, 408, + 408, 507, 507, -1109, 371, 141, 409, 565, 408, 500, + 500, -1109, 353, -1109, 409, -1109, -1109, 92, 175, -1109, + -1109, -1109, 175, 175, -1109, 175, 367, 175, 367, -1109, + -1109, 175, 175, -1109, 175, 367, 175, -1109, 175, 175, + -1109, 175, 175, 175, -1109, 175, -1109, 175, -1109, 175, + 175, -1109, 175, -1109, 175, 175, -1109, 175, -1109, 175, + -1109, 409, 409, -1109, -1109, 371, -1109, 1202, 588, -1109, + 644, -1109, -1109, 371, -1109, 1202, 588, -1109, -1109, -1109, + 588, -1109, -1109, -1109, 103, -1109, -1109, 353, -1109, -1109, + -1109, 353, -1109, -1109, -1109, -1109, 175, -1109, 175, 175, + 175, 175, 409, 175, 175, 409, 175, 175, 175, 175, + 175, -1109, -1109, 588, -1109, 229, -1109, -1109, -1109, 588, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, 175, 409, 175, + -1109, -1109, -1109 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 0, 423, 412, 401, 411, 173, 435, 452, 403, 480, + 483, 566, 614, 639, 642, 505, 498, 363, 541, 490, + 487, 495, 493, 582, 630, 402, 425, 436, 404, 424, + 481, 485, 484, 506, 491, 488, 496, 0, 4, 5, + 2, 0, 13, 353, 354, 0, 18, 390, 391, 392, + 393, 0, 0, 3, 0, 12, 0, 19, 0, 11, + 0, 20, 465, 466, 0, 14, 0, 21, 0, 15, + 0, 22, 0, 16, 0, 23, 0, 17, 0, 24, + 25, 26, 0, 27, 28, 29, 30, 31, 0, 7, + 0, 8, 0, 9, 0, 10, 0, 6, 0, 1, + 85, 86, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 90, 174, 0, 364, 0, + 400, 0, 0, 413, 0, 426, 0, 0, 453, 0, + 0, 427, 0, 427, 0, 427, 0, 500, 542, 0, + 567, 0, 583, 584, 598, 599, 585, 586, 601, 587, + 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, + 0, 580, 0, 615, 0, 0, 0, 617, 0, 0, + 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 87, 88, 579, 0, 0, 0, 0, 0, 0, + 52, 32, 49, 50, 51, 53, 54, 0, 175, 33, + 34, 38, 0, 37, 47, 0, 176, 166, 368, 0, + 0, 445, 446, 376, 406, 0, 0, 0, 0, 405, + 0, 437, 438, 0, 0, 0, 0, 414, 0, 427, + 0, 456, 455, 0, 0, 550, 470, 0, 0, 0, + 469, 0, 546, 547, 0, 432, 202, 428, 0, 482, + 553, 0, 0, 0, 489, 556, 0, 0, 0, 494, + 559, 0, 0, 0, 512, 508, 202, 202, 0, 202, + 0, 499, 544, 0, 0, 571, 572, 0, 569, 570, + 0, 0, 568, 574, 575, 581, 0, 0, 0, 0, + 619, 0, 0, 0, 46, 39, 0, 45, 35, 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, 429, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 504, 503, 0, + 0, 501, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 616, 0, 41, 43, 40, 48, + 180, 183, 177, 178, 167, 170, 0, 172, 0, 165, + 372, 0, 358, 0, 0, 355, 360, 369, 366, 0, + 0, 378, 382, 0, 417, 229, 418, 399, 216, 217, + 218, 0, 0, 0, 0, 521, 0, 0, 447, 0, + 0, 0, 0, 415, 408, 422, 0, 461, 0, 202, + 0, 457, 202, 0, 0, 0, 0, 0, 0, 202, + 202, 433, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 62, 509, 60, 510, 0, 202, 513, 0, + 0, 0, 0, 0, 92, 0, 92, 0, 92, 0, + 0, 576, 0, 0, 524, 0, 0, 0, 650, 92, + 0, 0, 44, 0, 0, 0, 0, 357, 362, 0, + 361, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 394, 0, 0, 0, 0, 0, 0, 395, 0, + 0, 0, 0, 449, 0, 450, 0, 0, 0, 0, + 0, 467, 0, 0, 203, 430, 431, 486, 0, 0, + 492, 0, 0, 497, 0, 0, 56, 70, 0, 57, + 61, 0, 507, 502, 511, 0, 0, 0, 0, 0, + 561, 0, 0, 562, 0, 0, 563, 0, 560, 577, + 573, 0, 0, 0, 0, 0, 0, 618, 168, 171, + 181, 0, 184, 0, 374, 358, 373, 0, 358, 370, + 366, 365, 0, 0, 387, 388, 383, 0, 375, 379, + 0, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 0, 0, 0, 398, 419, + 0, 0, 522, 0, 0, 440, 0, 0, 211, 210, + 202, 202, 0, 407, 0, 451, 462, 0, 454, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 60, 0, 71, 0, 0, 0, 186, 112, 145, + 148, 156, 160, 110, 93, 94, 100, 101, 105, 0, + 97, 0, 104, 97, 0, 97, 0, 97, 0, 97, + 0, 97, 96, 0, 92, 0, 92, 0, 0, 578, + 0, 536, 0, 625, 515, 516, 0, 525, 385, 640, + 0, 641, 0, 0, 179, 182, 359, 371, 356, 367, + 0, 396, 0, 380, 377, 0, 0, 0, 39, 538, + 0, 0, 0, 0, 397, 539, 410, 409, 0, 434, + 39, 0, 468, 0, 545, 0, 548, 551, 552, 554, + 555, 557, 558, 58, 0, 55, 80, 0, 0, 65, + 83, 67, 78, 79, 540, 0, 0, 0, 0, 103, + 0, 0, 129, 0, 0, 130, 0, 0, 131, 0, + 0, 132, 0, 95, 0, 564, 0, 565, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, + 0, 389, 385, 381, 244, 245, 246, 202, 202, 202, + 202, 0, 0, 0, 440, 209, 208, 448, 0, 441, + 443, 439, 214, 0, 463, 459, 0, 202, 0, 64, + 60, 83, 72, 0, 0, 82, 0, 108, 97, 106, + 0, 102, 97, 99, 113, 0, 97, 97, 97, 146, + 0, 97, 97, 149, 0, 97, 157, 0, 161, 162, + 0, 91, 0, 607, 0, 623, 629, 625, 625, 92, + 0, 624, 0, 386, 523, 634, 632, 633, 0, 0, + 0, 0, 0, 0, 0, 421, 36, 416, 0, 0, + 0, 0, 0, 0, 0, 0, 549, 59, 81, 0, + 66, 69, 84, 543, 107, 0, 98, 111, 0, 133, + 0, 134, 135, 144, 0, 136, 137, 0, 138, 0, + 0, 185, 0, 0, 39, 626, 627, 628, 0, 0, + 0, 0, 384, 0, 0, 0, 202, 517, 444, 0, + 442, 215, 202, 200, 198, 197, 199, 464, 0, 202, + 458, 0, 76, 68, 0, 0, 114, 115, 116, 117, + 97, 97, 97, 97, 150, 0, 158, 154, 163, 164, + 0, 621, 613, 607, 607, 92, 0, 92, 606, 0, + 0, 537, 385, 0, 0, 645, 646, 644, 0, 0, + 0, 420, 0, 0, 0, 0, 0, 460, 0, 0, + 75, 109, 0, 0, 0, 0, 139, 140, 141, 142, + 0, 0, 0, 159, 608, 609, 0, 610, 0, 612, + 0, 622, 0, 0, 0, 0, 0, 250, 220, 0, + 92, 0, 226, 0, 385, 517, 517, 514, 202, 204, + 0, 472, 77, 0, 73, 118, 119, 120, 121, 122, + 123, 97, 151, 0, 155, 153, 92, 0, 534, 529, + 530, 531, 532, 533, 385, 527, 0, 535, 0, 0, + 649, 646, 646, 643, 0, 219, 0, 224, 0, 0, + 225, 0, 520, 518, 519, 0, 0, 0, 471, 74, + 0, 0, 0, 143, 0, 611, 620, 0, 0, 0, + 39, 648, 647, 195, 192, 191, 194, 212, 193, 213, + 223, 352, 187, 189, 0, 188, 0, 220, 92, 251, + 0, 0, 228, 226, 0, 201, 202, 478, 476, 92, + 92, 0, 124, 125, 126, 127, 152, 0, 526, 206, + 635, 202, 0, 0, 222, 221, 0, 0, 227, 0, + 0, 0, 473, 475, 0, 0, 147, 0, 0, 0, + 0, 0, 0, 206, 253, 310, 311, 312, 313, 314, + 315, 316, 255, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, + 334, 335, 336, 337, 338, 339, 340, 257, 259, 341, + 342, 343, 344, 345, 0, 252, 277, 304, 284, 286, + 288, 290, 0, 283, 300, 196, 92, 479, 385, 128, + 202, 528, 638, 92, 0, 631, 651, 0, 0, 0, + 0, 0, 0, 247, 0, 0, 0, 0, 0, 0, + 0, 249, 0, 474, 0, 207, 637, 0, 202, 205, + 347, 351, 202, 202, 254, 202, 0, 202, 0, 256, + 349, 202, 202, 258, 202, 0, 202, 260, 202, 202, + 278, 202, 202, 202, 305, 202, 248, 202, 285, 202, + 202, 287, 202, 289, 202, 202, 291, 202, 301, 202, + 477, 0, 0, 261, 268, 0, 265, 0, 0, 267, + 0, 269, 276, 0, 273, 0, 0, 275, 279, 282, + 0, 280, 306, 309, 0, 307, 292, 0, 294, 295, + 296, 0, 298, 299, 302, 303, 635, 190, 202, 202, + 0, 202, 0, 202, 202, 0, 202, 202, 202, 202, + 202, 636, 264, 0, 262, 0, 266, 350, 272, 0, + 270, 348, 274, 281, 308, 293, 297, 202, 0, 202, + 263, 346, 271 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -1109, -1109, -1109, -205, -212, -178, -1109, -57, -184, 344, + -1109, -1109, -1109, -1109, -1109, -1109, -203, -310, -558, 28, + -673, -542, -1109, -1109, -1109, -1109, -1109, -1109, -1109, -493, + -153, -1109, -1109, -1109, -757, -1109, -1109, -136, -43, 1622, + 897, 2179, -1109, -414, -678, -541, -1109, -1109, -59, -1109, + -1109, -53, -1109, -1109, -1109, -58, -187, -1109, -1109, -707, + -1109, -1109, -1109, -1109, -1109, -679, -1109, -1109, -1109, -1109, + -675, -1109, -1109, -1109, 0, -1109, -1109, -1109, -1109, -1109, + 217, -1109, -1109, -421, -1109, -1109, -282, -1109, -1109, -962, + -1109, -1109, -1109, -1109, -844, 1726, -289, -1090, -436, -1109, + -1109, -1109, -790, -905, 140, -1109, -388, -1109, -1109, -392, + -280, 196, -1109, -1109, -208, -880, -1109, -339, -854, -838, + -1109, -709, -489, -1109, -1109, -1109, -1109, -488, -1109, -1109, + -1109, -1109, -847, -490, -1109, -494, -1109, -1108, -1109, -333, + -1109, 736, -351, -253, 745, -363, 7, -188, -287, 170, + -1109, -1109, -1109, 264, -1109, -150, -1109, -157, -1109, -1109, + -1109, -1109, -1109, -1109, -744, -1109, -1109, -1109, 647, -36, + 649, -29, -231, -46, -1109, 583, -93, 57, -1109, -1109, + -1109, -1109, -1109, 73, -1109, -1109, -1109, 6, -1109, 651, + -48, -1109, -1109, -1109, -27, -1109, -141, -1109, -6, -1109, + -1109, 189, -73, -306, 294, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -319, -693, -819, -1109, 451, 691, 704, 485, + 311, -1109, -299, -1109, -1109, 466, 10, -1109, -24, 635, + 19, -1109, -78, 469, 22, -1109, -96, -296, 16, -1109, + -1109, 480, -1109, -1109, -1109, -1109, -1109, 655, -687, -263, + -1109, -1109, -511, -1109, -1109, -714, -1109, -1109, -1109, -699, + -1109, -1109, 721, 724, 726, -1109, -1109, -1109, -1109, 731, + -1109, -1109, -1109, -1109, 733, -1109, -1109, 734, -1109, -1109, + 743, -1109, -1109, 750, -1109, -1109, -1109, -1109, -1109, -1109, + -1109, -1109, -1109, -1109, -1109, -1109, -1109, 874, -151, -1109, + -86, 475, -1109, 133, -1109, -1109, -1109, -842, -1109, -1109, + -25, 875, -1109, -981, -430, -1109, -875, -1109, -1109, -1109, + -1109, -247, -1109, -128 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 37, 38, 39, 217, 576, 219, 804, 220, 791, + 221, 222, 376, 377, 223, 317, 224, 225, 814, 538, + 453, 539, 454, 642, 810, 540, 739, 880, 541, 740, + 813, 933, 934, 1023, 741, 742, 743, 815, 102, 203, + 344, 130, 842, 550, 654, 749, 655, 656, 657, 658, + 659, 660, 661, 825, 935, 662, 663, 664, 830, 665, + 666, 834, 945, 1033, 1117, 667, 992, 668, 837, 947, + 669, 670, 840, 950, 439, 320, 41, 127, 227, 384, + 385, 386, 571, 387, 388, 573, 672, 673, 1091, 1233, + 1093, 1094, 927, 928, 797, 345, 621, 1095, 1138, 798, + 622, 1096, 803, 922, 407, 408, 1055, 409, 410, 1060, + 411, 605, 606, 607, 787, 1008, 1010, 1012, 1009, 1100, + 1184, 1234, 1243, 1185, 1250, 1192, 1258, 1263, 1193, 1268, + 1216, 1254, 1186, 1235, 1236, 1244, 1245, 1237, 1238, 1098, + 42, 234, 322, 490, 256, 323, 235, 129, 229, 494, + 230, 398, 580, 392, 393, 577, 575, 244, 237, 402, + 403, 590, 498, 586, 776, 587, 782, 46, 47, 48, + 49, 50, 412, 131, 51, 52, 245, 394, 511, 54, + 134, 248, 424, 413, 414, 610, 792, 239, 56, 136, + 191, 267, 268, 442, 57, 58, 240, 241, 713, 242, + 243, 419, 800, 59, 428, 60, 139, 253, 254, 432, + 429, 874, 682, 627, 805, 929, 61, 62, 63, 259, + 436, 1068, 1110, 1111, 1198, 64, 260, 66, 67, 68, + 271, 70, 71, 72, 276, 74, 75, 76, 281, 198, + 78, 287, 288, 456, 289, 290, 459, 855, 683, 973, + 417, 613, 475, 476, 688, 684, 1044, 1045, 1046, 685, + 686, 962, 79, 80, 81, 82, 149, 293, 294, 83, + 261, 262, 263, 264, 84, 272, 273, 85, 277, 278, + 86, 282, 283, 87, 470, 88, 151, 301, 302, 305, + 306, 472, 89, 170, 90, 171, 172, 856, 903, 92, + 174, 178, 179, 311, 312, 955, 956, 849, 850, 93, + 773, 857, 95, 858, 1140, 96, 690, 97, 98, 479, + 966, 1006, 480, 967 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_int16 yytable[] = +{ + 40, 247, 103, 218, 313, 378, 55, 45, 104, 105, + 65, 106, 316, 107, 314, 108, 77, 109, 430, 69, + 916, 110, 73, 111, 161, 112, 236, 113, 488, 114, + 426, 115, 258, 116, 391, 117, 175, 176, 860, 118, + 487, 318, 160, 246, 826, 119, 250, 120, 644, 121, + 680, 122, 553, 123, 556, 124, 881, 53, 847, 132, + 957, 435, 137, 569, 140, 565, 142, 1079, 144, 1018, + 146, 469, 827, 848, 1, 831, 828, 99, 844, 832, + 919, 852, 835, 843, 153, 959, 738, 1, 1003, 838, + 238, 155, 1092, 156, 846, 193, 159, 195, 1021, 733, + 427, 421, 125, 1246, 1246, 1092, 1251, 1255, 404, 1260, + 5, 1265, 1265, 379, 1269, 1011, 1013, 1087, 405, 647, + 5, 19, 752, 1, 755, 1253, 758, 270, 761, 681, + 763, 12, 404, 795, 10, 251, 209, 399, 796, 233, + 415, 382, 795, 17, 15, 34, 5, 796, 653, 26, + 423, 433, 5, 29, 1036, 1087, 452, 252, 5, 17, + 2, 1106, 26, 1231, 295, 471, 29, 1309, 481, 24, + 4, 296, 482, 298, 1097, 1314, 299, 980, 937, 17, + 285, 917, 33, 406, 31, 32, 1020, 324, 953, 1319, + 266, 1089, 325, 1320, 327, 430, 257, 286, 26, 793, + 330, 335, 29, 954, 1318, 1013, 938, 406, 582, 940, + 939, 338, 965, 941, 339, 942, 228, 390, 1002, 943, + 1101, 343, 1024, 1104, 952, 347, 1, 948, 231, 1089, + 350, 629, 1200, 400, 427, 353, 795, 232, 420, 435, + 356, 796, 5, 249, 811, 359, 1271, 362, 10, 1242, + 1242, 364, 1249, 469, 365, 879, 469, 366, 1015, 559, + 765, 1121, 767, 368, 1204, 583, 1069, 859, 877, 373, + 1062, 468, 779, 1016, 2, 1025, 616, 884, 233, 177, + 1187, 886, 1194, 2, 4, 889, 891, 892, 1119, 466, + 895, 896, 650, 4, 898, 228, 589, 1203, 31, 32, + 1077, 26, 1228, 1026, 1028, 29, 1051, 1027, 1029, 1030, + 1031, 1049, 5, 1308, 651, 652, 1311, 5, 265, 462, + 463, 1313, 696, 9, 1316, 698, 647, 1050, 1317, 5, + 380, 381, 1142, 1143, 737, 641, 427, 180, 643, 228, + 19, 16, 6, 485, 5, 486, 440, 257, 15, 614, + 491, 8, -600, 651, 652, 618, 679, 22, 10, 619, + 499, 1337, 284, 285, 34, 681, 633, 1339, 500, -602, + 5, 503, 280, 30, 505, 1231, 1090, 703, 1083, 233, + -603, 1102, 1084, 1085, 1086, -604, 33, 516, 5, 1108, + 20, 1112, 520, 1231, 5, 1113, 1114, 1115, 378, 986, + 987, 988, 989, 647, 27, 646, 28, 5, 31, 32, + 378, -605, 21, 780, 35, 1083, 647, 10, 292, 1084, + 1085, 1086, 551, 315, 554, 5, 557, 211, 1230, 487, + 1231, 652, -42, 563, 806, 907, 36, 566, 233, 816, + 1088, 643, 17, 488, 125, 210, 211, 310, 212, 213, + 214, 215, 216, 674, 1224, 618, 676, 401, 21, 619, + 1199, 1202, 415, 275, 819, 5, 823, 31, 32, 823, + 5, 1, 823, 649, 650, 823, 7, 1088, 823, 647, + 692, 1338, 36, 649, 650, 536, 231, 537, 443, 574, + 1073, 446, 427, 579, 449, 232, 651, 652, 788, 789, + 783, 1239, 473, 737, 477, 675, 651, 652, 677, 1261, + 620, 678, 615, 405, 1083, 807, 5, 5, 1084, 1085, + 1086, 1240, 1231, 233, 5, 100, 101, 17, 1240, 1231, + 474, 809, 438, 634, 643, 812, 784, 785, 786, 445, + 478, 997, 448, 999, 702, 451, 26, 380, 636, 671, + 29, 640, 671, 461, 638, 671, -63, 1038, 537, 452, + 381, 1039, 1040, 1041, 1042, 689, 5, 1083, 1007, 201, + 202, 1084, 1085, 1086, 1087, 647, 1088, 5, 833, 718, + 650, 836, 5, 303, 304, 1230, 647, 1231, 390, 648, + 649, 650, 964, 536, 378, 1083, 1057, 215, 216, 1084, + 1085, 1086, 651, 652, 735, 5, 823, 866, 823, 258, + 643, 812, 823, 651, 652, 653, 747, 841, 750, 1043, + 537, 753, 1075, 756, 737, 759, 648, 762, 923, 1088, + 764, 1083, 924, 925, 926, 1084, 1085, 1086, 1087, 771, + 1007, 5, 608, 774, 611, 584, 585, 777, 1089, 617, + 647, 790, 624, 648, 649, 650, 652, 1088, -71, 375, + 1107, 882, 632, -71, -71, -71, 228, 390, 635, 737, + 734, 637, 651, 652, 639, 878, 932, 651, 652, 653, + 307, 308, 309, 1007, 1125, 645, 964, 817, 921, 10, + 821, 3, 5, 1088, 820, 1132, 1133, 452, 936, 6, + 568, 647, 1034, 823, 648, 649, 650, 1208, 8, 1124, + 233, 1128, 1089, 737, 17, 9, 631, 794, 11, 944, + 1103, 946, 979, 1247, 255, 1264, 1264, 1259, 651, 652, + 653, 643, 1266, 16, 1109, 808, 43, 125, 210, 31, + 32, 212, 213, 214, 18, 44, 818, 20, 822, 22, + 699, 822, 1063, 1064, 822, 870, 578, 822, 960, 25, + 822, 27, 141, 28, 143, 30, 145, 152, 147, 154, + 378, 35, 671, 257, 210, 853, 1022, 212, 213, 214, + 215, 216, 1223, 297, 736, 799, 1, 2, 869, 1226, + 921, 210, 3, 1037, 212, 213, 214, 4, 920, 5, + 6, 5, 994, 995, 1081, 1082, 7, 908, 625, 8, + 647, 157, 1032, 648, 649, 650, 9, 10, 464, 11, + 643, 12, 905, 906, 158, 434, 13, 845, 14, 689, + 630, 15, 1196, 465, 16, 300, 467, 651, 652, 653, + 457, 162, 17, 5, 163, 18, 164, 19, 20, 21, + 22, 165, 647, 166, 167, 648, 649, 650, 23, 24, + 25, 26, 27, 168, 28, 29, 30, 31, 32, 33, + 169, 34, 35, 36, 91, 94, 1321, 1052, 427, 651, + 652, 653, 921, 0, 0, 976, 5, 0, 822, 0, + 822, 0, 0, 0, 822, 647, 1116, 427, 648, 649, + 650, 0, 671, 0, 0, 5, 0, 681, 0, 0, + 0, 951, 845, 998, 647, 0, 0, 648, 649, 650, + 0, 1004, 651, 652, 653, 0, 681, 0, 0, 427, + 0, 845, 0, 0, 0, 210, 211, 5, 212, 213, + 214, 651, 652, 653, 0, 0, 647, 0, 0, 648, + 649, 650, 0, 921, 0, 0, 0, 0, 681, 0, + 1048, 0, 0, 0, 0, 0, 1056, 0, 1058, 0, + 1061, 0, 1014, 651, 652, 653, 0, 5, 0, 0, + 0, 0, 0, 0, 416, 822, 647, 0, 422, 648, + 649, 650, 0, 0, 0, 0, 671, 437, 0, 0, + 0, 0, 0, 1078, 444, 671, 0, 447, 0, 0, + 450, 0, 16, 651, 652, 653, 0, 0, 460, 0, + 0, 0, 0, 921, 181, 0, 182, 0, 183, 184, + 0, 185, 0, 186, 187, 0, 188, 189, 190, 192, + 190, 194, 190, 196, 197, 0, 199, 0, 200, 0, + 0, 1122, 5, 1123, 671, 0, 0, 0, 0, 671, + 0, 647, 0, 0, 648, 649, 650, 671, 1134, 204, + 0, 205, 206, 207, 0, 208, 0, 1312, 845, 125, + 210, 211, 5, 212, 213, 214, 215, 216, 651, 652, + 653, 647, 0, 0, 648, 649, 650, 0, 0, 1310, + 0, 1107, 0, 0, 0, 210, 0, 1315, 212, 213, + 214, 215, 216, 735, 0, 736, 0, 0, 651, 652, + 653, 0, 0, 0, 319, 0, 321, 0, 0, 0, + 0, 671, 0, 326, 0, 328, 0, 329, 0, 671, + 0, 331, 332, 333, 0, 334, 190, 336, 0, 0, + 337, 0, 0, 0, 0, 340, 341, 0, 342, 0, + 0, 1227, 0, 0, 346, 0, 0, 0, 348, 349, + 0, 0, 0, 351, 352, 0, 0, 0, 354, 355, + 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, + 363, 0, 0, 1277, 0, 1280, 0, 0, 367, 0, + 0, 0, 1285, 0, 369, 370, 371, 0, 372, 1232, + 1232, 1241, 1241, 0, 1248, 1252, 0, 1257, 1232, 1262, + 1262, 0, 1267, 1144, 1145, 1146, 1147, 1148, 1149, 1150, + 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, + 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, + 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, + 1181, 1182, 1183, 591, 592, 593, 594, 595, 596, 597, + 598, 599, 600, 601, 602, 603, 604, 0, 0, 0, + 0, 483, 484, 0, 0, 0, 0, 0, 321, 489, + 0, 492, 0, 0, 0, 493, 495, 496, 0, 497, + 0, 210, 211, 0, 212, 213, 214, 215, 216, 0, + 502, 736, 0, 504, 0, 0, 506, 507, 0, 509, + 0, 510, 0, 512, 0, 0, 514, 0, 0, 0, + 518, 519, 0, 0, 522, 523, 0, 0, 0, 0, + 0, 528, 529, 0, 531, 532, 0, 534, 535, 210, + 211, 0, 212, 213, 214, 215, 216, 545, 546, 547, + 548, 549, 0, 552, 0, 555, 0, 0, 0, 0, + 561, 0, 562, 0, 564, 0, 555, 1188, 1145, 1146, + 1147, 1148, 1149, 1150, 1151, 1189, 1153, 1154, 1155, 1156, + 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, + 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, + 1190, 1191, 1179, 1180, 1181, 1182, 1183, 1145, 1146, 1147, + 1148, 1149, 1150, 1151, 0, 1153, 1154, 1155, 1156, 1157, + 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, + 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 0, + 0, 1179, 1180, 1181, 1182, 1183, 591, 592, 593, 594, + 595, 596, 597, 598, 599, 693, 0, 0, 0, 0, + 0, 0, 489, 0, 0, 489, 0, 493, 0, 700, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 705, 706, 707, 0, 0, 708, 0, 0, + 710, 711, 712, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 720, 0, 721, 0, 723, 0, + 725, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 745, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 746, 0, 748, 0, 0, + 751, 0, 754, 0, 757, 0, 760, 0, 760, 0, + 0, 555, 766, 555, 768, 769, 0, 770, 0, 0, + 772, 0, 0, 0, 0, 775, 0, 0, 0, 778, + 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, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 700, 0, 775, + 0, 0, 0, 0, 0, 0, 0, 864, 0, 0, + 868, 712, 0, 0, 0, 0, 871, 0, 0, 0, + 872, 0, 873, 721, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 760, 0, 885, 0, 760, + 0, 0, 0, 888, 890, 760, 0, 0, 894, 760, + 0, 897, 760, 0, 899, 0, 0, 900, 0, 0, + 902, 904, 0, 0, 772, 772, 555, 0, 0, 909, + 0, 0, 0, 0, 0, 0, 911, 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, 963, 0, 0, + 968, 969, 970, 269, 972, 274, 974, 279, 0, 0, + 291, 0, 0, 0, 0, 0, 0, 0, 978, 0, + 0, 0, 0, 982, 983, 984, 0, 985, 760, 760, + 760, 0, 990, 0, 991, 0, 0, 0, 0, 0, + 902, 902, 996, 0, 555, 0, 1000, 0, 0, 775, + 0, 0, 0, 1005, 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, 1054, 0, 555, 0, 1059, + 0, 775, 972, 972, 0, 0, 0, 1066, 1067, 0, + 0, 0, 1070, 1071, 0, 1072, 0, 0, 760, 0, + 1074, 0, 0, 555, 0, 374, 0, 0, 0, 0, + 0, 775, 389, 0, 395, 396, 1080, 0, 1005, 1005, + 0, 0, 0, 0, 0, 0, 0, 425, 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, 1054, 555, 0, 1126, 1127, 0, + 1059, 1129, 0, 0, 0, 0, 1131, 555, 0, 1135, + 0, 0, 357, 358, 0, 361, 1137, 1139, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 501, 0, 0, 0, 0, 1207, + 1137, 1209, 0, 508, 0, 0, 0, 0, 0, 1210, + 513, 0, 0, 0, 0, 0, 0, 0, 521, 0, + 0, 0, 0, 0, 526, 527, 0, 0, 530, 0, + 0, 533, 0, 0, 1211, 1212, 0, 0, 542, 0, + 0, 544, 0, 1214, 1215, 1217, 1218, 1219, 1220, 0, + 0, 1222, 558, 555, 560, 775, 0, 0, 0, 0, + 555, 0, 0, 567, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 581, 0, 0, 0, + 588, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1275, 623, 1278, 0, 0, 0, 0, 628, + 0, 1283, 0, 1286, 0, 0, 0, 0, 1290, 0, + 0, 0, 1294, 0, 0, 515, 1297, 0, 517, 0, + 0, 1301, 0, 0, 0, 524, 525, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 543, 0, 0, 0, 691, 0, 0, + 0, 0, 0, 694, 0, 695, 0, 0, 0, 697, + 0, 0, 0, 1139, 0, 701, 1323, 1325, 0, 0, + 0, 1329, 704, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 709, 0, 0, 0, 0, 714, 715, + 0, 0, 0, 0, 0, 0, 719, 0, 0, 0, + 0, 0, 722, 0, 724, 0, 726, 727, 728, 729, + 730, 731, 732, 0, 0, 0, 0, 744, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 126, 128, 0, 0, 133, 135, 0, 138, 0, + 135, 0, 135, 0, 135, 0, 135, 148, 150, 0, + 173, 173, 173, 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, 801, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 716, 717, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 226, 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, 851, 0, 0, 854, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 867, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 876, 0, 0, 0, 0, 0, 0, 0, 883, 0, + 0, 0, 0, 0, 0, 0, 0, 887, 0, 0, + 0, 0, 893, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 901, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 910, 0, 912, 913, 914, 915, 0, 0, 0, 0, + 0, 918, 0, 0, 0, 0, 930, 931, 383, 0, + 0, 0, 0, 397, 128, 0, 0, 0, 0, 418, + 0, 0, 0, 861, 862, 863, 865, 431, 128, 0, + 0, 0, 418, 0, 0, 958, 441, 0, 0, 418, + 0, 0, 418, 875, 0, 418, 0, 0, 455, 0, + 0, 458, 0, 418, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 981, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 993, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1001, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1017, 0, 1019, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1035, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1047, 0, 0, 0, 1053, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 971, 0, 0, 0, 0, 0, 975, 0, + 0, 0, 0, 0, 0, 977, 0, 0, 0, 1076, + 0, 0, 0, 0, 570, 572, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 609, 0, 612, 0, 0, 1105, 0, 0, + 0, 0, 0, 0, 0, 626, 0, 0, 0, 1118, + 0, 1120, 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, 1136, + 0, 0, 687, 0, 1065, 173, 0, 0, 0, 0, + 0, 0, 1195, 0, 0, 0, 0, 0, 0, 0, + 1201, 0, 1205, 1206, 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, 1213, 0, 0, 0, + 0, 0, 0, 0, 1221, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1229, 0, 1130, 0, 0, 0, 0, 0, 1256, 0, + 0, 0, 0, 0, 0, 0, 1270, 1141, 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, 781, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1306, 1307, 0, 0, 802, 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, 1225, 0, 0, 824, + 0, 0, 829, 0, 1327, 0, 0, 1331, 0, 0, + 0, 839, 0, 0, 0, 0, 0, 0, 0, 0, + 626, 0, 0, 626, 1272, 0, 0, 0, 1273, 1274, + 1341, 1276, 0, 1279, 0, 0, 0, 1281, 1282, 0, + 1284, 0, 1287, 0, 1288, 1289, 0, 1291, 1292, 1293, + 0, 1295, 0, 1296, 0, 1298, 1299, 0, 1300, 0, + 1302, 1303, 0, 1304, 0, 1305, 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, 1322, 1324, 0, 1326, 0, 1328, + 1330, 0, 1332, 1333, 1334, 1335, 1336, 0, 0, 802, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1340, 0, 1342, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 949, + 0, 0, 0, 0, 0, 0, 0, 0, 961, 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, 802, 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, 626, 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, 1099, 0, 1099, 0, 0, + 1099, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 802, 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, 802, 802, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1197 +}; + +static const yytype_int16 yycheck[] = +{ + 0, 185, 45, 181, 209, 315, 0, 0, 51, 52, + 0, 54, 224, 56, 217, 58, 0, 60, 337, 0, + 864, 64, 0, 66, 120, 68, 183, 70, 391, 72, + 336, 74, 189, 76, 321, 78, 122, 123, 782, 82, + 391, 225, 120, 184, 751, 88, 187, 90, 541, 92, + 561, 94, 466, 96, 468, 98, 813, 0, 772, 105, + 902, 341, 108, 484, 110, 479, 112, 1048, 114, 974, + 116, 367, 751, 772, 4, 754, 751, 0, 771, 754, + 870, 774, 757, 770, 120, 904, 644, 4, 963, 762, + 183, 120, 1054, 120, 772, 143, 120, 145, 978, 641, + 9, 332, 146, 1211, 1212, 1067, 1214, 1215, 6, 1217, + 17, 1219, 1220, 316, 1222, 969, 970, 14, 16, 26, + 17, 65, 663, 4, 665, 1215, 667, 71, 669, 38, + 671, 39, 6, 7, 35, 3, 179, 325, 12, 56, + 48, 319, 7, 60, 49, 89, 17, 12, 55, 79, + 334, 339, 17, 83, 996, 14, 359, 25, 17, 60, + 5, 1066, 79, 22, 200, 368, 83, 1275, 373, 77, + 15, 200, 375, 200, 1054, 1283, 200, 934, 885, 60, + 51, 868, 87, 81, 85, 86, 976, 230, 902, 1297, + 190, 88, 235, 1301, 237, 514, 189, 197, 79, 710, + 243, 249, 83, 902, 1294, 1059, 885, 81, 495, 888, + 885, 254, 911, 888, 257, 890, 61, 62, 962, 894, + 1058, 264, 979, 1061, 902, 268, 4, 900, 19, 88, + 273, 518, 1137, 326, 9, 278, 7, 28, 331, 519, + 283, 12, 17, 186, 737, 288, 1227, 290, 35, 1211, + 1212, 294, 1214, 549, 297, 813, 552, 300, 972, 471, + 674, 1080, 676, 306, 1139, 496, 1023, 778, 810, 312, + 1014, 367, 693, 972, 5, 982, 507, 818, 56, 40, + 1127, 822, 1129, 5, 15, 826, 827, 828, 1078, 367, + 831, 832, 31, 15, 835, 61, 499, 1139, 85, 86, + 1044, 79, 1207, 982, 983, 83, 1005, 982, 983, 984, + 985, 1004, 17, 1275, 53, 54, 1278, 17, 23, 365, + 366, 1283, 575, 34, 1286, 578, 26, 1005, 1290, 17, + 32, 33, 1122, 1123, 644, 538, 9, 162, 541, 61, + 65, 52, 18, 386, 17, 388, 346, 340, 49, 506, + 393, 27, 162, 53, 54, 7, 559, 68, 35, 11, + 403, 1323, 50, 51, 89, 38, 523, 1329, 411, 162, + 17, 414, 73, 84, 417, 22, 1054, 589, 7, 56, + 162, 1059, 11, 12, 13, 162, 87, 430, 17, 1067, + 66, 1070, 435, 22, 17, 1070, 1071, 1072, 708, 940, + 941, 942, 943, 26, 80, 546, 82, 17, 85, 86, + 720, 162, 67, 700, 90, 7, 26, 35, 64, 11, + 12, 13, 465, 149, 467, 17, 469, 148, 20, 780, + 22, 54, 149, 476, 721, 849, 91, 480, 56, 745, + 69, 644, 60, 806, 146, 147, 148, 41, 150, 151, + 152, 153, 154, 549, 1198, 7, 552, 57, 67, 11, + 1135, 1139, 48, 72, 746, 17, 748, 85, 86, 751, + 17, 4, 754, 30, 31, 757, 24, 69, 760, 26, + 566, 1325, 91, 30, 31, 154, 19, 156, 348, 489, + 1031, 351, 9, 493, 354, 28, 53, 54, 706, 707, + 703, 1210, 369, 813, 371, 551, 53, 54, 554, 1218, + 510, 557, 506, 16, 7, 723, 17, 17, 11, 12, + 13, 21, 22, 56, 17, 158, 159, 60, 21, 22, + 25, 734, 343, 523, 737, 738, 150, 151, 152, 350, + 47, 955, 353, 957, 587, 356, 79, 32, 529, 549, + 83, 535, 552, 364, 532, 555, 154, 7, 156, 762, + 33, 11, 12, 13, 14, 45, 17, 7, 8, 160, + 161, 11, 12, 13, 14, 26, 69, 17, 756, 622, + 31, 759, 17, 74, 75, 20, 26, 22, 62, 29, + 30, 31, 911, 154, 904, 7, 1010, 153, 154, 11, + 12, 13, 53, 54, 155, 17, 888, 791, 890, 766, + 813, 814, 894, 53, 54, 55, 659, 146, 661, 69, + 156, 664, 1036, 666, 934, 668, 29, 670, 7, 69, + 673, 7, 11, 12, 13, 11, 12, 13, 14, 682, + 8, 17, 502, 686, 504, 58, 59, 690, 88, 509, + 26, 708, 512, 29, 30, 31, 54, 69, 155, 315, + 36, 814, 522, 160, 161, 162, 61, 62, 528, 979, + 642, 531, 53, 54, 534, 811, 879, 53, 54, 55, + 205, 206, 207, 8, 1098, 545, 1005, 746, 872, 35, + 748, 10, 17, 69, 747, 1109, 1110, 900, 885, 18, + 483, 26, 991, 985, 29, 30, 31, 1143, 27, 1097, + 56, 1103, 88, 1023, 60, 34, 520, 711, 37, 897, + 1059, 899, 934, 1212, 70, 1219, 1220, 1217, 53, 54, + 55, 934, 1220, 52, 1067, 725, 0, 146, 147, 85, + 86, 150, 151, 152, 63, 0, 746, 66, 748, 68, + 580, 751, 1015, 1016, 754, 798, 492, 757, 908, 78, + 760, 80, 111, 82, 113, 84, 115, 120, 117, 120, + 1080, 90, 772, 766, 147, 775, 979, 150, 151, 152, + 153, 154, 1196, 200, 157, 712, 4, 5, 794, 1203, + 974, 147, 10, 998, 150, 151, 152, 15, 871, 17, + 18, 17, 953, 954, 1051, 1052, 24, 850, 514, 27, + 26, 120, 990, 29, 30, 31, 34, 35, 367, 37, + 1023, 39, 847, 848, 120, 340, 44, 43, 46, 45, + 519, 49, 1131, 367, 52, 200, 367, 53, 54, 55, + 360, 120, 60, 17, 120, 63, 120, 65, 66, 67, + 68, 120, 26, 120, 120, 29, 30, 31, 76, 77, + 78, 79, 80, 120, 82, 83, 84, 85, 86, 87, + 120, 89, 90, 91, 0, 0, 1306, 1005, 9, 53, + 54, 55, 1066, -1, -1, 928, 17, -1, 888, -1, + 890, -1, -1, -1, 894, 26, 1074, 9, 29, 30, + 31, -1, 902, -1, -1, 17, -1, 38, -1, -1, + -1, 42, 43, 956, 26, -1, -1, 29, 30, 31, + -1, 964, 53, 54, 55, -1, 38, -1, -1, 9, + -1, 43, -1, -1, -1, 147, 148, 17, 150, 151, + 152, 53, 54, 55, -1, -1, 26, -1, -1, 29, + 30, 31, -1, 1137, -1, -1, -1, -1, 38, -1, + 1003, -1, -1, -1, -1, -1, 1009, -1, 1011, -1, + 1013, -1, 972, 53, 54, 55, -1, 17, -1, -1, + -1, -1, -1, -1, 329, 985, 26, -1, 333, 29, + 30, 31, -1, -1, -1, -1, 996, 342, -1, -1, + -1, -1, -1, 1046, 349, 1005, -1, 352, -1, -1, + 355, -1, 52, 53, 54, 55, -1, -1, 363, -1, + -1, -1, -1, 1207, 127, -1, 129, -1, 131, 132, + -1, 134, -1, 136, 137, -1, 139, 140, 141, 142, + 143, 144, 145, 146, 147, -1, 149, -1, 151, -1, + -1, 1094, 17, 1096, 1054, -1, -1, -1, -1, 1059, + -1, 26, -1, -1, 29, 30, 31, 1067, 1111, 172, + -1, 174, 175, 176, -1, 178, -1, 1280, 43, 146, + 147, 148, 17, 150, 151, 152, 153, 154, 53, 54, + 55, 26, -1, -1, 29, 30, 31, -1, -1, 1277, + -1, 36, -1, -1, -1, 147, -1, 1285, 150, 151, + 152, 153, 154, 155, -1, 157, -1, -1, 53, 54, + 55, -1, -1, -1, 227, -1, 229, -1, -1, -1, + -1, 1131, -1, 236, -1, 238, -1, 240, -1, 1139, + -1, 244, 245, 246, -1, 248, 249, 250, -1, -1, + 253, -1, -1, -1, -1, 258, 259, -1, 261, -1, + -1, 1204, -1, -1, 267, -1, -1, -1, 271, 272, + -1, -1, -1, 276, 277, -1, -1, -1, 281, 282, + -1, -1, -1, -1, -1, -1, 289, -1, -1, -1, + 293, -1, -1, 1236, -1, 1238, -1, -1, 301, -1, + -1, -1, 1245, -1, 307, 308, 309, -1, 311, 1209, + 1210, 1211, 1212, -1, 1214, 1215, -1, 1217, 1218, 1219, + 1220, -1, 1222, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, -1, -1, -1, + -1, 384, 385, -1, -1, -1, -1, -1, 391, 392, + -1, 394, -1, -1, -1, 398, 399, 400, -1, 402, + -1, 147, 148, -1, 150, 151, 152, 153, 154, -1, + 413, 157, -1, 416, -1, -1, 419, 420, -1, 422, + -1, 424, -1, 426, -1, -1, 429, -1, -1, -1, + 433, 434, -1, -1, 437, 438, -1, -1, -1, -1, + -1, 444, 445, -1, 447, 448, -1, 450, 451, 147, + 148, -1, 150, 151, 152, 153, 154, 460, 461, 462, + 463, 464, -1, 466, -1, 468, -1, -1, -1, -1, + 473, -1, 475, -1, 477, -1, 479, 106, 107, 108, + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 140, 141, 142, 143, 144, 145, 107, 108, 109, + 110, 111, 112, 113, -1, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, -1, + -1, 141, 142, 143, 144, 145, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 568, -1, -1, -1, -1, + -1, -1, 575, -1, -1, 578, -1, 580, -1, 582, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 605, 606, 607, -1, -1, 610, -1, -1, + 613, 614, 615, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 627, -1, 629, -1, 631, -1, + 633, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 646, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 658, -1, 660, -1, -1, + 663, -1, 665, -1, 667, -1, 669, -1, 671, -1, + -1, 674, 675, 676, 677, 678, -1, 680, -1, -1, + 683, -1, -1, -1, -1, 688, -1, -1, -1, 692, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 780, -1, 782, + -1, -1, -1, -1, -1, -1, -1, 790, -1, -1, + 793, 794, -1, -1, -1, -1, 799, -1, -1, -1, + 803, -1, 805, 806, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 818, -1, 820, -1, 822, + -1, -1, -1, 826, 827, 828, -1, -1, 831, 832, + -1, 834, 835, -1, 837, -1, -1, 840, -1, -1, + 843, 844, -1, -1, 847, 848, 849, -1, -1, 852, + -1, -1, -1, -1, -1, -1, 859, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 910, -1, -1, + 913, 914, 915, 191, 917, 193, 919, 195, -1, -1, + 198, -1, -1, -1, -1, -1, -1, -1, 931, -1, + -1, -1, -1, 936, 937, 938, -1, 940, 941, 942, + 943, -1, 945, -1, 947, -1, -1, -1, -1, -1, + 953, 954, 955, -1, 957, -1, 959, -1, -1, 962, + -1, -1, -1, 966, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1008, -1, 1010, -1, 1012, + -1, 1014, 1015, 1016, -1, -1, -1, 1020, 1021, -1, + -1, -1, 1025, 1026, -1, 1028, -1, -1, 1031, -1, + 1033, -1, -1, 1036, -1, 313, -1, -1, -1, -1, + -1, 1044, 320, -1, 322, 323, 1049, -1, 1051, 1052, + -1, -1, -1, -1, -1, -1, -1, 335, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1097, 1098, -1, 1100, 1101, -1, + 1103, 1104, -1, -1, -1, -1, 1109, 1110, -1, 1112, + -1, -1, 286, 287, -1, 289, 1119, 1120, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 412, -1, -1, -1, -1, 1142, + 1143, 1144, -1, 421, -1, -1, -1, -1, -1, 1152, + 428, -1, -1, -1, -1, -1, -1, -1, 436, -1, + -1, -1, -1, -1, 442, 443, -1, -1, 446, -1, + -1, 449, -1, -1, 1177, 1178, -1, -1, 456, -1, + -1, 459, -1, 1186, 1187, 1188, 1189, 1190, 1191, -1, + -1, 1194, 470, 1196, 472, 1198, -1, -1, -1, -1, + 1203, -1, -1, 481, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 494, -1, -1, -1, + 498, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 1235, 511, 1237, -1, -1, -1, -1, 517, + -1, 1244, -1, 1246, -1, -1, -1, -1, 1251, -1, + -1, -1, 1255, -1, -1, 429, 1259, -1, 432, -1, + -1, 1264, -1, -1, -1, 439, 440, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 457, -1, -1, -1, 565, -1, -1, + -1, -1, -1, 571, -1, 573, -1, -1, -1, 577, + -1, -1, -1, 1306, -1, 583, 1309, 1310, -1, -1, + -1, 1314, 590, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 611, -1, -1, -1, -1, 616, 617, + -1, -1, -1, -1, -1, -1, 624, -1, -1, -1, + -1, -1, 630, -1, 632, -1, 634, 635, 636, 637, + 638, 639, 640, -1, -1, -1, -1, 645, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 102, 103, -1, -1, 106, 107, -1, 109, -1, + 111, -1, 113, -1, 115, -1, 117, 118, 119, -1, + 121, 122, 123, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 713, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 620, 621, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 181, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 773, -1, -1, 776, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 792, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 808, -1, -1, -1, -1, -1, -1, -1, 816, -1, + -1, -1, -1, -1, -1, -1, -1, 825, -1, -1, + -1, -1, 830, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 842, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 858, -1, 860, 861, 862, 863, -1, -1, -1, -1, + -1, 869, -1, -1, -1, -1, 874, 875, 319, -1, + -1, -1, -1, 324, 325, -1, -1, -1, -1, 330, + -1, -1, -1, 787, 788, 789, 790, 338, 339, -1, + -1, -1, 343, -1, -1, 903, 347, -1, -1, 350, + -1, -1, 353, 807, -1, 356, -1, -1, 359, -1, + -1, 362, -1, 364, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 935, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 950, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 960, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 973, -1, 975, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 992, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1002, -1, -1, -1, 1006, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 916, -1, -1, -1, -1, -1, 922, -1, + -1, -1, -1, -1, -1, 929, -1, -1, -1, 1037, + -1, -1, -1, -1, 485, 486, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 503, -1, 505, -1, -1, 1065, -1, -1, + -1, -1, -1, -1, -1, 516, -1, -1, -1, 1077, + -1, 1079, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 1117, + -1, -1, 563, -1, 1018, 566, -1, -1, -1, -1, + -1, -1, 1130, -1, -1, -1, -1, -1, -1, -1, + 1138, -1, 1140, 1141, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1184, -1, -1, -1, + -1, -1, -1, -1, 1192, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1208, -1, 1106, -1, -1, -1, -1, -1, 1216, -1, + -1, -1, -1, -1, -1, -1, 1224, 1121, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 702, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1271, 1272, -1, -1, 718, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1200, -1, -1, 750, + -1, -1, 753, -1, 1312, -1, -1, 1315, -1, -1, + -1, 762, -1, -1, -1, -1, -1, -1, -1, -1, + 771, -1, -1, 774, 1228, -1, -1, -1, 1232, 1233, + 1338, 1235, -1, 1237, -1, -1, -1, 1241, 1242, -1, + 1244, -1, 1246, -1, 1248, 1249, -1, 1251, 1252, 1253, + -1, 1255, -1, 1257, -1, 1259, 1260, -1, 1262, -1, + 1264, 1265, -1, 1267, -1, 1269, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1308, 1309, -1, 1311, -1, 1313, + 1314, -1, 1316, 1317, 1318, 1319, 1320, -1, -1, 870, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1337, -1, 1339, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 900, + -1, -1, -1, -1, -1, -1, -1, -1, 909, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 976, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1004, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1056, -1, 1058, -1, -1, + 1061, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1078, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1122, 1123, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1134 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint16 yystos[] = +{ + 0, 4, 5, 10, 15, 17, 18, 24, 27, 34, + 35, 37, 39, 44, 46, 49, 52, 60, 63, 65, + 66, 67, 68, 76, 77, 78, 79, 80, 82, 83, + 84, 85, 86, 87, 89, 90, 91, 164, 165, 166, + 237, 239, 303, 304, 307, 309, 330, 331, 332, 333, + 334, 337, 338, 340, 342, 350, 351, 357, 358, 366, + 368, 379, 380, 381, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 401, 403, 425, + 426, 427, 428, 432, 437, 440, 443, 446, 448, 455, + 457, 460, 462, 472, 474, 475, 478, 480, 481, 0, + 158, 159, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 146, 204, 240, 204, 310, + 204, 336, 336, 204, 343, 204, 352, 336, 204, 369, + 336, 352, 336, 352, 336, 352, 336, 352, 204, 429, + 204, 449, 331, 332, 333, 334, 357, 380, 381, 391, + 395, 399, 425, 426, 427, 432, 437, 440, 443, 446, + 456, 458, 459, 204, 463, 463, 463, 40, 464, 465, + 162, 203, 203, 203, 203, 203, 203, 203, 203, 203, + 203, 353, 203, 353, 203, 353, 203, 203, 402, 203, + 203, 160, 161, 202, 203, 203, 203, 203, 203, 201, + 147, 148, 150, 151, 152, 153, 154, 167, 168, 169, + 171, 173, 174, 177, 179, 180, 204, 241, 61, 311, + 313, 19, 28, 56, 304, 309, 320, 321, 339, 350, + 359, 360, 362, 363, 320, 339, 359, 171, 344, 340, + 359, 3, 25, 370, 371, 70, 307, 309, 320, 382, + 389, 433, 434, 435, 436, 23, 237, 354, 355, 202, + 71, 393, 438, 439, 202, 72, 397, 441, 442, 202, + 73, 401, 444, 445, 50, 51, 237, 404, 405, 407, + 408, 202, 64, 430, 431, 332, 334, 338, 357, 391, + 392, 450, 451, 74, 75, 452, 453, 464, 464, 464, + 41, 466, 467, 166, 179, 149, 167, 178, 171, 203, + 238, 203, 305, 308, 201, 201, 203, 201, 203, 203, + 201, 203, 203, 203, 203, 353, 203, 203, 201, 201, + 203, 203, 203, 201, 203, 258, 203, 201, 203, 203, + 201, 203, 203, 201, 203, 203, 201, 258, 258, 201, + 203, 258, 201, 203, 201, 201, 201, 203, 201, 203, + 203, 203, 203, 201, 202, 172, 175, 176, 180, 179, + 32, 33, 168, 204, 242, 243, 244, 246, 247, 202, + 62, 311, 316, 317, 340, 202, 202, 204, 314, 310, + 339, 57, 322, 323, 6, 16, 81, 267, 268, 270, + 271, 273, 335, 346, 347, 48, 410, 413, 204, 364, + 339, 335, 410, 171, 345, 202, 366, 9, 367, 373, + 375, 204, 372, 310, 382, 273, 383, 410, 364, 237, + 237, 204, 356, 267, 410, 364, 267, 410, 364, 267, + 410, 364, 179, 183, 185, 204, 406, 404, 204, 409, + 410, 364, 336, 336, 379, 388, 395, 396, 399, 400, + 447, 179, 454, 466, 25, 415, 416, 466, 47, 482, + 485, 166, 179, 203, 203, 201, 201, 305, 308, 203, + 306, 201, 203, 203, 312, 203, 203, 203, 325, 201, + 201, 202, 203, 201, 203, 201, 203, 203, 202, 203, + 203, 341, 203, 202, 203, 258, 201, 258, 203, 203, + 201, 202, 203, 203, 258, 258, 202, 202, 203, 203, + 202, 203, 203, 202, 203, 203, 154, 156, 182, 184, + 188, 191, 202, 258, 202, 203, 203, 203, 203, 203, + 206, 201, 203, 206, 201, 203, 206, 201, 202, 167, + 202, 203, 203, 201, 203, 206, 201, 202, 243, 246, + 204, 245, 204, 248, 237, 319, 168, 318, 316, 237, + 315, 202, 311, 335, 58, 59, 326, 328, 202, 179, + 324, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 274, 275, 276, 267, 204, + 348, 267, 204, 414, 320, 350, 335, 267, 7, 11, + 237, 259, 263, 202, 267, 367, 204, 376, 202, 311, + 383, 274, 267, 320, 389, 267, 393, 267, 397, 267, + 401, 179, 186, 179, 192, 267, 359, 26, 29, 30, + 31, 53, 54, 55, 207, 209, 210, 211, 212, 213, + 214, 215, 218, 219, 220, 222, 223, 228, 230, 233, + 234, 237, 249, 250, 399, 336, 399, 336, 336, 179, + 415, 38, 375, 411, 418, 422, 423, 204, 417, 45, + 479, 202, 463, 203, 202, 202, 306, 202, 306, 312, + 203, 202, 201, 167, 202, 203, 203, 203, 203, 202, + 203, 203, 203, 361, 202, 202, 258, 258, 201, 202, + 203, 203, 202, 203, 202, 203, 202, 202, 202, 202, + 202, 202, 202, 184, 182, 155, 157, 180, 181, 189, + 192, 197, 198, 199, 202, 203, 203, 201, 203, 208, + 201, 203, 208, 201, 203, 208, 201, 203, 208, 201, + 203, 208, 201, 208, 201, 206, 203, 206, 203, 203, + 203, 201, 203, 473, 201, 203, 327, 201, 203, 246, + 311, 204, 329, 179, 150, 151, 152, 277, 277, 277, + 170, 172, 349, 415, 350, 7, 12, 257, 262, 346, + 365, 202, 204, 265, 170, 377, 311, 277, 389, 179, + 187, 192, 179, 193, 181, 200, 366, 211, 237, 249, + 214, 218, 237, 249, 204, 216, 222, 228, 233, 204, + 221, 228, 233, 168, 224, 233, 168, 231, 183, 204, + 235, 146, 205, 411, 376, 43, 207, 418, 422, 470, + 471, 202, 376, 237, 202, 410, 460, 474, 476, 415, + 327, 258, 258, 258, 203, 258, 171, 202, 203, 361, + 201, 203, 203, 203, 374, 258, 202, 184, 200, 181, + 190, 197, 193, 202, 208, 203, 208, 202, 203, 208, + 203, 208, 208, 202, 203, 208, 208, 203, 208, 203, + 203, 202, 203, 461, 203, 473, 473, 206, 201, 203, + 202, 203, 202, 202, 202, 202, 257, 411, 202, 265, + 365, 171, 266, 7, 11, 12, 13, 255, 256, 378, + 202, 202, 179, 194, 195, 217, 219, 222, 228, 233, + 228, 233, 233, 233, 168, 225, 168, 232, 183, 204, + 236, 42, 207, 418, 422, 468, 469, 470, 202, 377, + 318, 204, 424, 203, 375, 422, 483, 486, 203, 203, + 203, 258, 203, 412, 203, 258, 201, 258, 203, 167, + 197, 202, 203, 203, 203, 203, 208, 208, 208, 208, + 203, 203, 229, 202, 461, 461, 203, 206, 201, 206, + 203, 202, 327, 479, 201, 203, 484, 8, 278, 281, + 279, 281, 280, 281, 237, 418, 422, 202, 266, 202, + 265, 278, 179, 196, 197, 222, 228, 233, 228, 233, + 233, 233, 168, 226, 259, 202, 470, 166, 7, 11, + 12, 13, 14, 69, 419, 420, 421, 202, 201, 376, + 207, 422, 486, 202, 203, 269, 201, 206, 201, 203, + 272, 201, 327, 412, 412, 258, 203, 203, 384, 197, + 203, 203, 203, 208, 203, 206, 202, 327, 201, 476, + 203, 484, 484, 7, 11, 12, 13, 14, 69, 88, + 207, 251, 252, 253, 254, 260, 264, 278, 302, 204, + 282, 282, 207, 280, 282, 202, 266, 36, 207, 302, + 385, 386, 228, 233, 233, 233, 168, 227, 202, 265, + 202, 377, 201, 201, 269, 206, 203, 203, 272, 203, + 258, 203, 206, 206, 201, 203, 202, 203, 261, 203, + 477, 258, 265, 265, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 283, 286, 295, 295, 106, 114, + 139, 140, 288, 291, 295, 202, 385, 204, 387, 233, + 266, 202, 207, 470, 479, 202, 202, 203, 261, 203, + 203, 203, 203, 202, 203, 203, 293, 203, 203, 203, + 203, 202, 203, 206, 327, 258, 206, 201, 266, 202, + 20, 22, 237, 252, 284, 296, 297, 300, 301, 284, + 21, 237, 252, 285, 298, 299, 300, 285, 237, 252, + 287, 300, 237, 260, 294, 300, 202, 237, 289, 296, + 300, 284, 237, 290, 298, 300, 290, 237, 292, 300, + 202, 476, 258, 258, 258, 203, 258, 201, 203, 258, + 201, 258, 258, 203, 258, 201, 203, 258, 258, 258, + 203, 258, 258, 258, 203, 258, 258, 203, 258, 258, + 258, 203, 258, 258, 258, 258, 202, 202, 252, 300, + 168, 252, 179, 252, 300, 168, 252, 252, 260, 300, + 300, 477, 258, 203, 258, 203, 258, 202, 258, 203, + 258, 202, 258, 258, 258, 258, 258, 252, 257, 252, + 258, 202, 258 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint16 yyr1[] = +{ + 0, 163, 164, 164, 164, 164, 164, 164, 164, 164, + 164, 164, 165, 165, 165, 165, 165, 165, 166, 166, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 167, 168, 168, 169, 170, 171, 171, 172, + 172, 173, 174, 175, 176, 177, 177, 178, 178, 179, + 179, 179, 179, 180, 180, 181, 182, 183, 183, 183, + 184, 184, 185, 186, 187, 188, 189, 189, 190, 190, + 191, 192, 193, 194, 194, 194, 195, 196, 197, 197, + 198, 199, 199, 200, 200, 201, 201, 202, 202, 203, + 204, 205, 206, 206, 207, 207, 207, 208, 208, 208, + 209, 209, 210, 210, 210, 211, 211, 211, 211, 212, + 213, 214, 215, 216, 217, 217, 217, 217, 217, 217, + 217, 217, 217, 217, 217, 217, 217, 217, 217, 218, + 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, + 234, 235, 235, 236, 236, 237, 238, 238, 238, 238, + 238, 238, 238, 239, 240, 241, 241, 242, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 251, 252, + 253, 254, 254, 254, 254, 254, 255, 256, 256, 256, + 256, 257, 258, 258, 259, 260, 261, 261, 262, 262, + 263, 263, 264, 264, 265, 266, 267, 267, 267, 268, + 269, 269, 269, 269, 270, 271, 272, 272, 272, 273, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 275, + 275, 275, 276, 276, 277, 277, 277, 278, 279, 280, + 281, 282, 283, 283, 283, 283, 283, 283, 283, 283, + 283, 284, 284, 284, 284, 284, 284, 284, 284, 285, + 285, 285, 285, 285, 285, 285, 285, 286, 286, 287, + 287, 287, 287, 288, 288, 288, 288, 288, 288, 288, + 288, 288, 289, 289, 289, 289, 290, 290, 290, 290, + 291, 291, 292, 292, 293, 293, 294, 294, 294, 294, + 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, + 295, 295, 295, 295, 295, 295, 296, 297, 298, 299, + 300, 301, 302, 303, 303, 304, 305, 305, 306, 306, + 307, 308, 308, 309, 310, 311, 312, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 324, 324, 325, 325, 326, 327, 327, 328, 328, 329, + 330, 330, 330, 330, 331, 332, 333, 334, 335, 335, + 336, 337, 337, 338, 338, 339, 339, 340, 341, 341, + 341, 342, 342, 343, 344, 345, 346, 347, 347, 348, + 349, 349, 350, 351, 351, 351, 352, 353, 353, 353, + 353, 354, 355, 356, 357, 358, 358, 359, 359, 360, + 361, 361, 361, 361, 362, 363, 363, 364, 365, 366, + 367, 367, 368, 369, 370, 371, 371, 372, 373, 374, + 374, 375, 376, 377, 378, 379, 379, 380, 381, 382, + 382, 383, 384, 384, 384, 384, 384, 385, 386, 387, + 388, 388, 389, 390, 390, 390, 391, 392, 392, 393, + 394, 394, 395, 396, 397, 398, 398, 399, 400, 401, + 402, 402, 402, 402, 402, 403, 403, 404, 405, 406, + 406, 407, 408, 409, 410, 411, 411, 412, 412, 412, + 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, + 421, 421, 421, 421, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 431, 432, 433, 433, 434, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, + 446, 447, 447, 447, 447, 447, 448, 449, 450, 450, + 450, 451, 451, 452, 453, 453, 454, 454, 454, 455, + 456, 456, 457, 458, 458, 458, 458, 458, 458, 458, + 458, 458, 458, 458, 458, 458, 458, 458, 459, 459, + 459, 459, 459, 459, 459, 459, 460, 461, 461, 461, + 461, 461, 461, 461, 462, 463, 464, 465, 466, 467, + 468, 469, 470, 471, 472, 473, 473, 473, 473, 473, + 474, 475, 476, 476, 476, 477, 477, 477, 477, 478, + 479, 480, 481, 482, 483, 483, 484, 484, 484, 484, + 485, 486 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 1, 1, 0, + 1, 3, 1, 1, 2, 2, 2, 0, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 2, 4, 6, + 0, 1, 1, 1, 1, 3, 3, 1, 2, 1, + 1, 1, 1, 3, 4, 2, 1, 1, 1, 1, + 1, 3, 2, 0, 2, 1, 1, 1, 1, 1, + 1, 1, 0, 2, 1, 2, 1, 0, 3, 2, + 1, 1, 3, 2, 1, 1, 3, 4, 3, 6, + 1, 4, 1, 1, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 5, 5, 5, 5, 7, 2, + 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, + 6, 6, 6, 8, 4, 1, 1, 10, 1, 1, + 1, 1, 1, 7, 0, 2, 1, 1, 1, 6, + 1, 1, 1, 1, 1, 7, 0, 2, 4, 6, + 2, 4, 2, 1, 1, 1, 1, 1, 1, 4, + 1, 1, 4, 1, 1, 4, 1, 1, 1, 1, + 7, 1, 1, 1, 1, 1, 7, 1, 1, 1, + 1, 7, 0, 3, 7, 5, 0, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 10, + 0, 3, 3, 2, 10, 10, 0, 3, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 6, 7, 6, + 1, 1, 1, 1, 3, 1, 3, 1, 3, 1, + 3, 2, 4, 6, 4, 2, 4, 2, 2, 2, + 4, 6, 4, 2, 4, 2, 2, 1, 3, 2, + 2, 4, 2, 1, 1, 3, 1, 3, 1, 3, + 1, 3, 2, 4, 2, 2, 2, 4, 2, 2, + 1, 3, 2, 2, 0, 2, 2, 2, 4, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6, 1, 4, 1, + 4, 1, 1, 1, 1, 7, 5, 3, 0, 3, + 7, 3, 3, 1, 1, 5, 0, 3, 1, 1, + 1, 4, 1, 1, 1, 5, 1, 4, 1, 1, + 2, 3, 0, 2, 5, 0, 2, 1, 1, 1, + 1, 1, 1, 1, 8, 8, 10, 10, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 9, 0, 3, + 3, 1, 1, 1, 1, 1, 6, 1, 1, 1, + 4, 2, 7, 1, 1, 1, 1, 0, 2, 3, + 5, 4, 1, 1, 10, 1, 1, 1, 1, 7, + 0, 2, 4, 2, 9, 1, 1, 1, 1, 8, + 2, 3, 1, 1, 5, 1, 1, 1, 7, 0, + 3, 1, 1, 1, 1, 1, 1, 8, 10, 1, + 1, 10, 0, 3, 5, 3, 2, 5, 1, 1, + 1, 1, 5, 1, 1, 1, 8, 1, 1, 5, + 1, 1, 8, 1, 5, 1, 1, 8, 1, 5, + 0, 3, 5, 3, 3, 1, 1, 4, 1, 1, + 1, 4, 1, 1, 9, 1, 1, 0, 3, 3, + 3, 1, 1, 5, 1, 1, 9, 1, 5, 1, + 1, 1, 1, 1, 1, 7, 1, 1, 10, 10, + 10, 1, 1, 8, 1, 10, 1, 1, 6, 8, + 1, 10, 6, 1, 10, 6, 1, 10, 6, 1, + 8, 2, 2, 2, 4, 4, 1, 1, 1, 1, + 1, 1, 1, 4, 1, 1, 1, 2, 3, 4, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 13, 0, 3, 3, + 3, 5, 3, 2, 1, 1, 4, 1, 4, 1, + 4, 1, 4, 1, 11, 0, 3, 3, 3, 2, + 1, 19, 1, 1, 1, 0, 6, 3, 2, 1, + 1, 9, 1, 9, 1, 1, 0, 3, 3, 2, + 1, 7 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, context); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt2_parse_context *context) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (context); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, pj_wkt2_parse_context *context) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, context); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, pj_wkt2_parse_context *context) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , context); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, context); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr && yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, pj_wkt2_parse_context *context) +{ + YYUSE (yyvaluep); + YYUSE (context); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (pj_wkt2_parse_context *context) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = (yytype_int16)yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, context); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (context, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (context, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, context); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +#if 0 +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +#endif +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, context); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (context, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, context); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, context); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} diff --git a/src/wkt2_generated_parser.h b/src/wkt2_generated_parser.h new file mode 100644 index 00000000..baeb0b4f --- /dev/null +++ b/src/wkt2_generated_parser.h @@ -0,0 +1,208 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_PJ_WKT2_SRC_WKT2_GENERATED_PARSER_H_INCLUDED +# define YY_PJ_WKT2_SRC_WKT2_GENERATED_PARSER_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int pj_wkt2_debug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + END = 0, + T_PROJECTION = 258, + T_DATUM = 259, + T_SPHEROID = 260, + T_PRIMEM = 261, + T_UNIT = 262, + T_AXIS = 263, + T_PARAMETER = 264, + T_GEODCRS = 265, + T_LENGTHUNIT = 266, + T_ANGLEUNIT = 267, + T_SCALEUNIT = 268, + T_TIMEUNIT = 269, + T_ELLIPSOID = 270, + T_CS = 271, + T_ID = 272, + T_PROJCRS = 273, + T_BASEGEODCRS = 274, + T_MERIDIAN = 275, + T_BEARING = 276, + T_ORDER = 277, + T_ANCHOR = 278, + T_CONVERSION = 279, + T_METHOD = 280, + T_REMARK = 281, + T_GEOGCRS = 282, + T_BASEGEOGCRS = 283, + T_SCOPE = 284, + T_AREA = 285, + T_BBOX = 286, + T_CITATION = 287, + T_URI = 288, + T_VERTCRS = 289, + T_VDATUM = 290, + T_GEOIDMODEL = 291, + T_COMPOUNDCRS = 292, + T_PARAMETERFILE = 293, + T_COORDINATEOPERATION = 294, + T_SOURCECRS = 295, + T_TARGETCRS = 296, + T_INTERPOLATIONCRS = 297, + T_OPERATIONACCURACY = 298, + T_CONCATENATEDOPERATION = 299, + T_STEP = 300, + T_BOUNDCRS = 301, + T_ABRIDGEDTRANSFORMATION = 302, + T_DERIVINGCONVERSION = 303, + T_TDATUM = 304, + T_CALENDAR = 305, + T_TIMEORIGIN = 306, + T_TIMECRS = 307, + T_VERTICALEXTENT = 308, + T_TIMEEXTENT = 309, + T_USAGE = 310, + T_DYNAMIC = 311, + T_FRAMEEPOCH = 312, + T_MODEL = 313, + T_VELOCITYGRID = 314, + T_ENSEMBLE = 315, + T_MEMBER = 316, + T_ENSEMBLEACCURACY = 317, + T_DERIVEDPROJCRS = 318, + T_BASEPROJCRS = 319, + T_EDATUM = 320, + T_ENGCRS = 321, + T_PDATUM = 322, + T_PARAMETRICCRS = 323, + T_PARAMETRICUNIT = 324, + T_BASEVERTCRS = 325, + T_BASEENGCRS = 326, + T_BASEPARAMCRS = 327, + T_BASETIMECRS = 328, + T_EPOCH = 329, + T_COORDEPOCH = 330, + T_COORDINATEMETADATA = 331, + T_POINTMOTIONOPERATION = 332, + T_GEODETICCRS = 333, + T_GEODETICDATUM = 334, + T_PROJECTEDCRS = 335, + T_PRIMEMERIDIAN = 336, + T_GEOGRAPHICCRS = 337, + T_TRF = 338, + T_VERTICALCRS = 339, + T_VERTICALDATUM = 340, + T_VRF = 341, + T_TIMEDATUM = 342, + T_TEMPORALQUANTITY = 343, + T_ENGINEERINGDATUM = 344, + T_ENGINEERINGCRS = 345, + T_PARAMETRICDATUM = 346, + T_AFFINE = 347, + T_CARTESIAN = 348, + T_CYLINDRICAL = 349, + T_ELLIPSOIDAL = 350, + T_LINEAR = 351, + T_PARAMETRIC = 352, + T_POLAR = 353, + T_SPHERICAL = 354, + T_VERTICAL = 355, + T_TEMPORAL = 356, + T_TEMPORALCOUNT = 357, + T_TEMPORALMEASURE = 358, + T_ORDINAL = 359, + T_TEMPORALDATETIME = 360, + T_NORTH = 361, + T_NORTHNORTHEAST = 362, + T_NORTHEAST = 363, + T_EASTNORTHEAST = 364, + T_EAST = 365, + T_EASTSOUTHEAST = 366, + T_SOUTHEAST = 367, + T_SOUTHSOUTHEAST = 368, + T_SOUTH = 369, + T_SOUTHSOUTHWEST = 370, + T_SOUTHWEST = 371, + T_WESTSOUTHWEST = 372, + T_WEST = 373, + T_WESTNORTHWEST = 374, + T_NORTHWEST = 375, + T_NORTHNORTHWEST = 376, + T_UP = 377, + T_DOWN = 378, + T_GEOCENTRICX = 379, + T_GEOCENTRICY = 380, + T_GEOCENTRICZ = 381, + T_COLUMNPOSITIVE = 382, + T_COLUMNNEGATIVE = 383, + T_ROWPOSITIVE = 384, + T_ROWNEGATIVE = 385, + T_DISPLAYRIGHT = 386, + T_DISPLAYLEFT = 387, + T_DISPLAYUP = 388, + T_DISPLAYDOWN = 389, + T_FORWARD = 390, + T_AFT = 391, + T_PORT = 392, + T_STARBOARD = 393, + T_CLOCKWISE = 394, + T_COUNTERCLOCKWISE = 395, + T_TOWARDS = 396, + T_AWAYFROM = 397, + T_FUTURE = 398, + T_PAST = 399, + T_UNSPECIFIED = 400, + T_STRING = 401, + T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE = 402 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef int YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int pj_wkt2_parse (pj_wkt2_parse_context *context); + +#endif /* !YY_PJ_WKT2_SRC_WKT2_GENERATED_PARSER_H_INCLUDED */ diff --git a/src/wkt2_grammar.y b/src/wkt2_grammar.y new file mode 100644 index 00000000..f028eb5b --- /dev/null +++ b/src/wkt2_grammar.y @@ -0,0 +1,1499 @@ +%{ +/****************************************************************************** + * Project: PROJ + * Purpose: WKT2 parser grammar + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2018 Even Rouault, + * + * 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. + ****************************************************************************/ + +#include "wkt2_parser.h" + +%} + +%define api.pure +%define parse.error verbose +%require "3.0" + +%parse-param {pj_wkt2_parse_context *context} +%lex-param {pj_wkt2_parse_context *context} + +/* From WKT1 */ +%token T_PROJECTION "PROJECTION" +%token T_DATUM "DATUM" +%token T_SPHEROID "SPHEROID" +%token T_PRIMEM "PRIMEM" +%token T_UNIT "UNIT" +%token T_AXIS "AXIS" +%token T_PARAMETER "PARAMETER" + +/* WKT2 preferred */ +%token T_GEODCRS "GEODCRS"; +%token T_LENGTHUNIT "LENGTHUNIT"; +%token T_ANGLEUNIT "ANGLEUNIT"; +%token T_SCALEUNIT "SCALEUNIT"; +%token T_TIMEUNIT "TIMEUNIT"; +%token T_ELLIPSOID "ELLIPSOID"; +%token T_CS "CS"; +%token T_ID "ID"; +%token T_PROJCRS "PROJCRS"; +%token T_BASEGEODCRS "BASEGEODCRS"; +%token T_MERIDIAN "MERIDIAN"; +%token T_BEARING "BEARING"; +%token T_ORDER "ORDER"; +%token T_ANCHOR "ANCHOR"; +%token T_CONVERSION "CONVERSION"; +%token T_METHOD "METHOD"; +%token T_REMARK "REMARK"; +%token T_GEOGCRS "GEOGCRS"; +%token T_BASEGEOGCRS "BASEGEOGCRS"; +%token T_SCOPE "SCOPE"; +%token T_AREA "AREA"; +%token T_BBOX "BBOX"; +%token T_CITATION "CITATION"; +%token T_URI "URI"; +%token T_VERTCRS "VERTCRS"; +%token T_VDATUM "VDATUM"; +%token T_GEOIDMODEL "GEOIDMODEL"; +%token T_COMPOUNDCRS "COMPOUNDCRS"; +%token T_PARAMETERFILE "PARAMETERFILE"; +%token T_COORDINATEOPERATION "COORDINATEOPERATION"; +%token T_SOURCECRS "SOURCECRS"; +%token T_TARGETCRS "TARGETCRS"; +%token T_INTERPOLATIONCRS "INTERPOLATIONCRS"; +%token T_OPERATIONACCURACY "OPERATIONACCURACY"; +%token T_CONCATENATEDOPERATION "CONCATENATEDOPERATION"; +%token T_STEP "STEP"; +%token T_BOUNDCRS "BOUNDCRS"; +%token T_ABRIDGEDTRANSFORMATION "ABRIDGEDTRANSFORMATION"; +%token T_DERIVINGCONVERSION "DERIVINGCONVERSION"; +%token T_TDATUM "TDATUM"; +%token T_CALENDAR "CALENDAR"; +%token T_TIMEORIGIN "TIMEORIGIN"; +%token T_TIMECRS "TIMECRS"; +%token T_VERTICALEXTENT "VERTICALEXTENT"; +%token T_TIMEEXTENT "TIMEEXTENT"; +%token T_USAGE "USAGE"; +%token T_DYNAMIC "DYNAMIC"; +%token T_FRAMEEPOCH "FRAMEEPOCH"; +%token T_MODEL "MODEL"; +%token T_VELOCITYGRID "VELOCITYGRID"; +%token T_ENSEMBLE "ENSEMBLE"; +%token T_MEMBER "MEMBER"; +%token T_ENSEMBLEACCURACY "ENSEMBLEACCURACY"; +%token T_DERIVEDPROJCRS "DERIVEDPROJCRS"; +%token T_BASEPROJCRS "BASEPROJCRS"; +%token T_EDATUM "EDATUM"; +%token T_ENGCRS "ENGCRS"; +%token T_PDATUM "PDATUM"; +%token T_PARAMETRICCRS "PARAMETRICCRS"; +%token T_PARAMETRICUNIT "PARAMETRICUNIT"; +%token T_BASEVERTCRS "BASEVERTCRS"; +%token T_BASEENGCRS "BASEENGCRS"; +%token T_BASEPARAMCRS "BASEPARAMCRS"; +%token T_BASETIMECRS "BASETIMECRS"; +%token T_EPOCH "EPOCH" +%token T_COORDEPOCH "COORDEPOCH" +%token T_COORDINATEMETADATA "COORDINATEMETADATA" +%token T_POINTMOTIONOPERATION "POINTMOTIONOPERATION" + +/* WKT2 alternate (longer or shorter) */ +%token T_GEODETICCRS "GEODETICCRS"; +%token T_GEODETICDATUM "GEODETICDATUM"; +%token T_PROJECTEDCRS "PROJECTEDCRS"; +%token T_PRIMEMERIDIAN "PRIMEMERIDIAN"; +%token T_GEOGRAPHICCRS "GEOGRAPHICCRS"; +%token T_TRF "TRF"; +%token T_VERTICALCRS "VERTICALCRS"; +%token T_VERTICALDATUM "VERTICALDATUM"; +%token T_VRF "VRF"; +%token T_TIMEDATUM "TIMEDATUM"; +%token T_TEMPORALQUANTITY "TEMPORALQUANTITY"; +%token T_ENGINEERINGDATUM "ENGINEERINGDATUM"; +%token T_ENGINEERINGCRS "ENGINEERINGCRS"; +%token T_PARAMETRICDATUM "PARAMETRICDATUM"; + + +/* CS types */ +%token T_AFFINE "affine"; +%token T_CARTESIAN "Cartesian"; +%token T_CYLINDRICAL "cylindrical"; +%token T_ELLIPSOIDAL "ellipsoidal"; +%token T_LINEAR "linear"; +%token T_PARAMETRIC "parametric"; +%token T_POLAR "polar"; +%token T_SPHERICAL "spherical"; +%token T_VERTICAL "vertical"; +%token T_TEMPORAL "temporal"; // WKT2_2015 only +%token T_TEMPORALCOUNT "temporalCount"; +%token T_TEMPORALMEASURE "temporalMeasure"; +%token T_ORDINAL "ordinal"; +%token T_TEMPORALDATETIME "temporalDateTime"; + +/* Axis directions */ +%token T_NORTH "north"; +%token T_NORTHNORTHEAST "northNorthEast"; +%token T_NORTHEAST "northEast"; +%token T_EASTNORTHEAST "eastNorthEast"; +%token T_EAST "east"; +%token T_EASTSOUTHEAST "eastSouthEast"; +%token T_SOUTHEAST "southEast"; +%token T_SOUTHSOUTHEAST "southSouthEast"; +%token T_SOUTH "south"; +%token T_SOUTHSOUTHWEST "southSouthWest"; +%token T_SOUTHWEST "southWest"; +%token T_WESTSOUTHWEST "westSouthWest"; +%token T_WEST "west"; +%token T_WESTNORTHWEST "westNorthWest"; +%token T_NORTHWEST "northWest"; +%token T_NORTHNORTHWEST "northNorthWest"; +%token T_UP "up"; +%token T_DOWN "down"; +%token T_GEOCENTRICX "geocentricX"; +%token T_GEOCENTRICY "geocentricY"; +%token T_GEOCENTRICZ "geocentricZ"; +%token T_COLUMNPOSITIVE "columnPositive"; +%token T_COLUMNNEGATIVE "columnNegative"; +%token T_ROWPOSITIVE "rowPositive"; +%token T_ROWNEGATIVE "rowNegative"; +%token T_DISPLAYRIGHT "displayRight"; +%token T_DISPLAYLEFT "displayLeft"; +%token T_DISPLAYUP "displayUp"; +%token T_DISPLAYDOWN "displayDown"; +%token T_FORWARD "forward"; +%token T_AFT "aft"; +%token T_PORT "port"; +%token T_STARBOARD "starboard"; +%token T_CLOCKWISE "clockwise"; +%token T_COUNTERCLOCKWISE "counterClockwise"; +%token T_TOWARDS "towards"; +%token T_AWAYFROM "awayFrom"; +%token T_FUTURE "future"; +%token T_PAST "part"; +%token T_UNSPECIFIED "unspecified"; + + +%token T_STRING "string" +%token T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE "unsigned integer" + +%token END 0 "end of string" + +%% + +/* Derived from BNF grammar in OGC 18-010r3 (WKT2:2018), with a few back + additions from GC 12-063r5 (WKT2:2015) */ + +input: + identifier | ellipsoid | datum | crs | bound_crs | coordinate_metadata | + coordinate_operation | point_motion_operation | concatenated_operation | + map_projection + +datum: + geodetic_reference_frame_without_pm | datum_ensemble | + vertical_reference_frame | engineering_datum | parametric_datum | + temporal_datum + +crs: + geodetic_crs | projected_crs | vertical_crs | engineering_crs | + parametric_crs | temporal_crs | derived_geodetic_crs | derived_geographic_crs | + derived_projected_crs | derived_vertical_crs | derived_engineering_crs | + derived_parametric_crs | derived_temporal_crs | compound_crs + +// Basic characters + +period: '.' + +// Numbers + +number: signed_numeric_literal_with_sign | unsigned_numeric_literal + +signed_numeric_literal_with_sign: sign unsigned_numeric_literal + +signed_numeric_literal: opt_sign unsigned_numeric_literal + +unsigned_numeric_literal: exact_numeric_literal | approximate_numeric_literal + +opt_sign: | sign + +approximate_numeric_literal: mantissa 'E' exponent + +mantissa: exact_numeric_literal + +exponent: signed_integer + +signed_integer: opt_sign unsigned_integer + +exact_numeric_literal: unsigned_integer opt_period_unsigned_integer | period unsigned_integer + +opt_period_unsigned_integer: | period unsigned_integer + +unsigned_integer: '1' | '2' | '3' | T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE + +sign: '+' | '-' + +// Date and time + +colon: ':' + +hyphen: '-' + +// Significantly modified to avoid shift-reduce ambiguities for Bison +datetime: + year opt_24_hour_clock + | year hyphen unsigned_integer opt_24_hour_clock + | year hyphen month hyphen day opt_24_hour_clock + +opt_24_hour_clock: | _24_hour_clock + +year: unsigned_integer + +month: unsigned_integer + +day: unsigned_integer + +_24_hour_clock: time_designator hour + opt_colon_minute_colon_second_time_zone_designator + +opt_colon_minute_colon_second_time_zone_designator: + colon minute opt_colon_second_time_zone_designator + | time_zone_designator + +opt_colon_second_time_zone_designator: + colon second_time_zone_designator + | time_zone_designator + +time_designator: 'T' + +hour: unsigned_integer + +minute: unsigned_integer + +second_time_zone_designator: + seconds_integer period time_zone_designator + | seconds_integer period seconds_fraction time_zone_designator + | seconds_integer time_zone_designator + +seconds_integer: unsigned_integer + +seconds_fraction: unsigned_integer + +time_zone_designator: utc_designator | local_time_zone_designator + +utc_designator: 'Z' + +local_time_zone_designator: + sign hour opt_colon_minute + | hour opt_colon_minute + +opt_colon_minute: | colon minute + + +// CRS WKT characters + +left_delimiter: '[' | '(' + +right_delimiter: ']' | ')' + +wkt_separator: ',' + +quoted_latin_text: T_STRING + +quoted_unicode_text: T_STRING + +// Scope, extent, identifier and remark + +opt_separator_scope_extent_identifier_remark: + | wkt_separator no_opt_separator_scope_extent_identifier_remark + +no_opt_separator_scope_extent_identifier_remark: + scope_extent_opt_identifier_list_opt_remark + | identifier opt_identifier_list_remark + | remark + +opt_identifier_list_remark: | wkt_separator identifier opt_identifier_list_remark + | wkt_separator remark + +scope_extent_opt_identifier_list_opt_remark: + scope_extent_opt_identifier_list_remark + | usage_list_opt_identifier_list_remark + +// WKT2-2015 way +scope_extent_opt_identifier_list_remark: + scope wkt_separator extent_opt_identifier_list_remark + | scope opt_identifier_list_remark + | extent_opt_identifier_list_remark + +// WKT2-2018 way +usage_list_opt_identifier_list_remark: + usage + | usage wkt_separator remark + | usage wkt_separator identifier opt_identifier_list_remark + | usage wkt_separator usage_list_opt_identifier_list_remark + +usage: usage_keyword left_delimiter + scope wkt_separator extent + right_delimiter + +usage_keyword: T_USAGE + +scope: scope_keyword left_delimiter + scope_text_description right_delimiter + +scope_keyword: T_SCOPE + +scope_text_description: quoted_latin_text + +extent: + area_description + | geographic_bounding_box + | vertical_extent + | temporal_extent + | area_description wkt_separator geographic_bounding_box + | area_description wkt_separator vertical_extent + | area_description wkt_separator temporal_extent + | geographic_bounding_box wkt_separator vertical_extent + | geographic_bounding_box wkt_separator temporal_extent + | vertical_extent wkt_separator temporal_extent + | area_description wkt_separator geographic_bounding_box wkt_separator vertical_extent + | area_description wkt_separator geographic_bounding_box wkt_separator temporal_extent + | area_description wkt_separator vertical_extent wkt_separator temporal_extent + | geographic_bounding_box wkt_separator vertical_extent wkt_separator temporal_extent + | area_description wkt_separator geographic_bounding_box wkt_separator vertical_extent wkt_separator temporal_extent + +extent_opt_identifier_list_remark: + area_description opt_identifier_list_remark + | geographic_bounding_box opt_identifier_list_remark + | vertical_extent opt_identifier_list_remark + | temporal_extent opt_identifier_list_remark + | area_description wkt_separator geographic_bounding_box opt_identifier_list_remark + | area_description wkt_separator vertical_extent opt_identifier_list_remark + | area_description wkt_separator temporal_extent opt_identifier_list_remark + | geographic_bounding_box wkt_separator vertical_extent opt_identifier_list_remark + | geographic_bounding_box wkt_separator temporal_extent opt_identifier_list_remark + | vertical_extent wkt_separator temporal_extent opt_identifier_list_remark + | area_description wkt_separator geographic_bounding_box wkt_separator vertical_extent opt_identifier_list_remark + | area_description wkt_separator geographic_bounding_box wkt_separator temporal_extent opt_identifier_list_remark + | area_description wkt_separator vertical_extent wkt_separator temporal_extent opt_identifier_list_remark + | geographic_bounding_box wkt_separator vertical_extent wkt_separator temporal_extent opt_identifier_list_remark + | area_description wkt_separator geographic_bounding_box wkt_separator vertical_extent wkt_separator temporal_extent opt_identifier_list_remark + +// Area description + +area_description: area_description_keyword left_delimiter area_text_description right_delimiter + +area_description_keyword: T_AREA + +area_text_description: quoted_latin_text + +// Geographic bounding box + +geographic_bounding_box: geographic_bounding_box_keyword left_delimiter + lower_left_latitude wkt_separator lower_left_longitude + wkt_separator upper_right_latitude wkt_separator + upper_right_longitude right_delimiter + +geographic_bounding_box_keyword: T_BBOX + +lower_left_latitude: number + +lower_left_longitude: number + +upper_right_latitude: number + +upper_right_longitude: number + +// Vertical extent + +vertical_extent: vertical_extent_keyword left_delimiter + vertical_extent_minimum_height wkt_separator + vertical_extent_maximum_height + opt_separator_length_unit right_delimiter + +opt_separator_length_unit: + | wkt_separator length_unit + +vertical_extent_keyword: T_VERTICALEXTENT + +vertical_extent_minimum_height: number + +vertical_extent_maximum_height: number + +// Temporal extent + +temporal_extent: temporal_extent_keyword left_delimiter + temporal_extent_start wkt_separator + temporal_extent_end right_delimiter + +temporal_extent_keyword: T_TIMEEXTENT + +temporal_extent_start: datetime | quoted_latin_text + +temporal_extent_end: datetime | quoted_latin_text + + +// Identifier + +identifier: identifier_keyword left_delimiter authority_name + wkt_separator authority_unique_identifier + opt_version_authority_citation_uri + right_delimiter + +opt_version_authority_citation_uri: + | wkt_separator version + | wkt_separator version wkt_separator authority_citation + | wkt_separator version wkt_separator authority_citation wkt_separator id_uri + | wkt_separator authority_citation + | wkt_separator authority_citation wkt_separator id_uri + | wkt_separator id_uri + +identifier_keyword: T_ID + +authority_name: quoted_latin_text + +authority_unique_identifier: number | quoted_latin_text + +version: number | quoted_latin_text + +authority_citation: citation_keyword left_delimiter citation right_delimiter + +citation_keyword: T_CITATION + +citation: quoted_latin_text + +id_uri: uri_keyword left_delimiter uri right_delimiter + +uri_keyword: T_URI + +uri: quoted_latin_text + +// Remark + +remark: remark_keyword left_delimiter quoted_unicode_text right_delimiter + +remark_keyword: T_REMARK + +// Unit + +unit: spatial_unit | time_unit + +//spatial_unit: angle_unit | length_unit | parametric_unit | scale_unit +spatial_unit: angle_or_length_or_parametric_or_scale_unit + +angle_or_length_or_parametric_or_scale_unit: + angle_or_length_or_parametric_or_scale_unit_keyword + left_delimiter unit_name + wkt_separator conversion_factor + opt_separator_identifier_list right_delimiter + +angle_or_length_or_parametric_or_scale_unit_keyword: T_ANGLEUNIT | T_LENGTHUNIT | T_PARAMETRICUNIT | T_SCALEUNIT | T_UNIT + +angle_or_length_or_scale_unit: + angle_or_length_or_scale_unit_keyword + left_delimiter unit_name + wkt_separator conversion_factor + opt_separator_identifier_list right_delimiter + +angle_or_length_or_scale_unit_keyword: T_ANGLEUNIT | T_LENGTHUNIT | T_SCALEUNIT | T_UNIT + + +angle_unit: angle_unit_keyword left_delimiter unit_name + wkt_separator conversion_factor + opt_separator_identifier_list right_delimiter + +opt_separator_identifier_list: + | wkt_separator identifier opt_separator_identifier_list + +length_unit: length_unit_keyword left_delimiter unit_name + wkt_separator conversion_factor + opt_separator_identifier_list right_delimiter + +/* +parametric_unit: parametric_unit_keyword left_delimiter unit_name + wkt_separator conversion_factor + opt_separator_identifier_list right_delimiter +*/ + +/* +scale_unit: scale_unit_keyword left_delimiter unit_name + wkt_separator conversion_factor + opt_separator_identifier_list right_delimiter +*/ + +time_unit: time_unit_keyword left_delimiter unit_name + opt_separator_conversion_factor_identifier_list + right_delimiter + +opt_separator_conversion_factor_identifier_list: + | wkt_separator conversion_factor opt_separator_identifier_list + +angle_unit_keyword: T_ANGLEUNIT | T_UNIT + +length_unit_keyword: T_LENGTHUNIT | T_UNIT + +// parametric_unit_keyword: T_PARAMETRICUNIT + +// scale_unit_keyword: T_SCALEUNIT | T_UNIT + +time_unit_keyword: T_TIMEUNIT | T_TEMPORALQUANTITY + +unit_name: quoted_latin_text + +conversion_factor: unsigned_numeric_literal + + +// Coordinate system + +// coordinate_system: spatial_cs | temporalcountmeasure_cs | ordinatedatetime_cs + +coordinate_system_scope_extent_identifier_remark: spatial_cs_scope_extent_identifier_remark | temporalcountmeasure_cs_scope_extent_identifier_remark | ordinaldatetime_cs_scope_extent_identifier_remark + +spatial_cs_scope_extent_identifier_remark: cs_keyword left_delimiter spatial_cs_type + wkt_separator dimension + opt_separator_identifier_list + right_delimiter + wkt_separator spatial_axis + opt_separator_spatial_axis_list_opt_separator_cs_unit_scope_extent_identifier_remark + +opt_separator_spatial_axis_list_opt_separator_cs_unit_scope_extent_identifier_remark: + | wkt_separator cs_unit opt_separator_scope_extent_identifier_remark + | wkt_separator spatial_axis opt_separator_spatial_axis_list_opt_separator_cs_unit_scope_extent_identifier_remark + | wkt_separator no_opt_separator_scope_extent_identifier_remark + +temporalcountmeasure_cs_scope_extent_identifier_remark: cs_keyword left_delimiter temporalcountmeasure_cs_type + wkt_separator dimension + opt_separator_identifier_list + right_delimiter + wkt_separator temporalcountmeasure_axis + opt_separator_scope_extent_identifier_remark + +ordinaldatetime_cs_scope_extent_identifier_remark: cs_keyword left_delimiter ordinaldatetime_cs_type + wkt_separator dimension + opt_separator_identifier_list + right_delimiter + wkt_separator ordinaldatetime_axis + opt_separator_ordinaldatetime_axis_list_scope_extent_identifier_remark + +opt_separator_ordinaldatetime_axis_list_scope_extent_identifier_remark: + | wkt_separator ordinaldatetime_axis opt_separator_ordinaldatetime_axis_list_scope_extent_identifier_remark + | wkt_separator no_opt_separator_scope_extent_identifier_remark + +cs_keyword: T_CS + +spatial_cs_type: T_AFFINE | T_CARTESIAN | T_CYLINDRICAL | T_ELLIPSOIDAL | T_LINEAR | T_PARAMETRIC | T_POLAR | T_SPHERICAL | T_VERTICAL + +// T_TEMPORAL: WKT2_2015 +temporalcountmeasure_cs_type: T_TEMPORAL | T_TEMPORALCOUNT | T_TEMPORALMEASURE + +ordinaldatetime_cs_type: T_ORDINAL | T_TEMPORALDATETIME + +dimension: '1' | '2' | '3' + +spatial_axis: axis_keyword left_delimiter axis_name_abbrev + wkt_separator + axis_direction_opt_axis_order_spatial_unit_identifier_list + right_delimiter + +temporalcountmeasure_axis: axis_keyword left_delimiter axis_name_abbrev + wkt_separator + axis_direction_except_n_s_cw_ccw + opt_separator_axis_time_unit_identifier_list + right_delimiter + +ordinaldatetime_axis: axis_keyword left_delimiter axis_name_abbrev + wkt_separator + axis_direction_opt_axis_order_identifier_list + right_delimiter + +axis_keyword: T_AXIS + +// Approximation of { | | } +axis_name_abbrev: quoted_latin_text + +axis_direction_opt_axis_order_spatial_unit_identifier_list: + axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list + | T_NORTH + | T_NORTH wkt_separator north_south_options_spatial_unit + | T_SOUTH + | T_SOUTH wkt_separator north_south_options_spatial_unit + | T_CLOCKWISE + | T_CLOCKWISE wkt_separator clockwise_counter_clockwise_options_spatial_unit + | T_COUNTERCLOCKWISE + | T_COUNTERCLOCKWISE wkt_separator clockwise_counter_clockwise_options_spatial_unit + +north_south_options_spatial_unit: + identifier opt_separator_identifier_list + | meridian wkt_separator axis_order opt_separator_identifier_list + | meridian wkt_separator axis_order wkt_separator spatial_unit opt_separator_identifier_list + | meridian wkt_separator spatial_unit opt_separator_identifier_list + | meridian opt_separator_identifier_list + | axis_order wkt_separator spatial_unit opt_separator_identifier_list + | axis_order opt_separator_identifier_list + | spatial_unit opt_separator_identifier_list + +clockwise_counter_clockwise_options_spatial_unit: + identifier opt_separator_identifier_list + | bearing wkt_separator axis_order opt_separator_identifier_list + | bearing wkt_separator axis_order wkt_separator spatial_unit opt_separator_identifier_list + | bearing wkt_separator spatial_unit opt_separator_identifier_list + | bearing opt_separator_identifier_list + | axis_order wkt_separator spatial_unit opt_separator_identifier_list + | axis_order opt_separator_identifier_list + | spatial_unit opt_separator_identifier_list + +axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list: + axis_direction_except_n_s_cw_ccw + | axis_direction_except_n_s_cw_ccw wkt_separator axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list_options + +axis_direction_except_n_s_cw_ccw_opt_axis_spatial_unit_identifier_list_options: + identifier opt_separator_identifier_list + | axis_order opt_separator_identifier_list + | axis_order wkt_separator spatial_unit opt_separator_identifier_list + | spatial_unit opt_separator_identifier_list + + + +axis_direction_opt_axis_order_identifier_list: + axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list + | T_NORTH + | T_NORTH wkt_separator north_south_options + | T_SOUTH + | T_SOUTH wkt_separator north_south_options_spatial_unit + | T_CLOCKWISE + | T_CLOCKWISE wkt_separator clockwise_counter_clockwise_options + | T_COUNTERCLOCKWISE + | T_COUNTERCLOCKWISE wkt_separator clockwise_counter_clockwise_options + +north_south_options: + identifier opt_separator_identifier_list + | meridian wkt_separator axis_order opt_separator_identifier_list + | meridian opt_separator_identifier_list + | axis_order opt_separator_identifier_list + +clockwise_counter_clockwise_options: + identifier opt_separator_identifier_list + | bearing wkt_separator axis_order opt_separator_identifier_list + | bearing opt_separator_identifier_list + | axis_order opt_separator_identifier_list + +axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list: + axis_direction_except_n_s_cw_ccw + | axis_direction_except_n_s_cw_ccw wkt_separator axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list_options + +axis_direction_except_n_s_cw_ccw_opt_axis_identifier_list_options: + identifier opt_separator_identifier_list + | axis_order opt_separator_identifier_list + + + + +opt_separator_axis_time_unit_identifier_list: + | wkt_separator axis_direction_except_n_s_cw_ccw_opt_axis_time_unit_identifier_list_options + +axis_direction_except_n_s_cw_ccw_opt_axis_time_unit_identifier_list_options: + identifier opt_separator_identifier_list + | axis_order opt_separator_identifier_list + | axis_order wkt_separator time_unit opt_separator_identifier_list + | time_unit opt_separator_identifier_list + +axis_direction_except_n_s_cw_ccw: + T_NORTHNORTHEAST + | T_NORTHEAST + | T_EASTNORTHEAST + | T_EAST + | T_EASTSOUTHEAST + | T_SOUTHEAST + | T_SOUTHSOUTHEAST + | T_SOUTHSOUTHWEST + | T_SOUTHWEST + | T_WESTSOUTHWEST + | T_WEST + | T_WESTNORTHWEST + | T_NORTHWEST + | T_NORTHNORTHWEST + | T_UP + | T_DOWN + | T_GEOCENTRICX + | T_GEOCENTRICY + | T_GEOCENTRICZ + | T_COLUMNPOSITIVE + | T_COLUMNNEGATIVE + | T_ROWPOSITIVE + | T_ROWNEGATIVE + | T_DISPLAYRIGHT + | T_DISPLAYLEFT + | T_DISPLAYUP + | T_DISPLAYDOWN + | T_FORWARD + | T_AFT + | T_PORT + | T_STARBOARD + | T_TOWARDS + | T_AWAYFROM + | T_FUTURE + | T_PAST + | T_UNSPECIFIED + +meridian: meridian_keyword left_delimiter number + wkt_separator angle_unit right_delimiter + +meridian_keyword: T_MERIDIAN + +bearing: bearing_keyword left_delimiter number right_delimiter + +bearing_keyword: T_BEARING + +axis_order: axis_order_keyword left_delimiter unsigned_integer right_delimiter + +axis_order_keyword: T_ORDER + +cs_unit: unit + +/* +ellipsoidal_2D_coordinate_system: cs_keyword left_delimiter ellipsoidal_2D_cs_type + wkt_separator ellipsoidal_2D_dimension + opt_separator_identifier_list right_delimiter + separator_spatial_axis_list + opt_separator_cs_unit + +ellipsoidal_2D_cs_type: T_ELLIPSOIDAL + +ellipsoidal_2D_dimension: '2' +*/ + +// Datum ensemble + +datum_ensemble: geodetic_datum_ensemble_without_pm | vertical_datum_ensemble + +geodetic_datum_ensemble_without_pm: datum_ensemble_keyword + left_delimiter + datum_ensemble_name + wkt_separator datum_ensemble_member + datum_ensemble_member_list_ellipsoid_accuracy_identifier_list + right_delimiter + +datum_ensemble_member_list_ellipsoid_accuracy_identifier_list: + wkt_separator ellipsoid wkt_separator datum_ensemble_accuracy opt_separator_datum_ensemble_identifier_list + | wkt_separator datum_ensemble_member datum_ensemble_member_list_ellipsoid_accuracy_identifier_list + +opt_separator_datum_ensemble_identifier_list: + | wkt_separator datum_ensemble_identifier opt_separator_datum_ensemble_identifier_list + +vertical_datum_ensemble: datum_ensemble_keyword + left_delimiter + datum_ensemble_name + wkt_separator datum_ensemble_member + datum_ensemble_member_list_accuracy_identifier_list + right_delimiter + +datum_ensemble_member_list_accuracy_identifier_list: + wkt_separator datum_ensemble_accuracy opt_separator_datum_ensemble_identifier_list + | wkt_separator datum_ensemble_member datum_ensemble_member_list_accuracy_identifier_list + +datum_ensemble_keyword: T_ENSEMBLE + +datum_ensemble_name: quoted_latin_text + +datum_ensemble_member: datum_ensemble_member_keyword left_delimiter + datum_ensemble_member_name + opt_datum_ensemble_member_identifier_list + right_delimiter + +opt_datum_ensemble_member_identifier_list: + | wkt_separator datum_ensemble_member_identifier opt_datum_ensemble_member_identifier_list + +datum_ensemble_member_keyword: T_MEMBER + +datum_ensemble_member_name: quoted_latin_text + +datum_ensemble_member_identifier: identifier + +datum_ensemble_accuracy: datum_ensemble_accuracy_keyword left_delimiter accuracy right_delimiter + +datum_ensemble_accuracy_keyword: T_ENSEMBLEACCURACY + +accuracy: number + +datum_ensemble_identifier: identifier + + +// Dynamic coordinate reference systems + +dynamic_crs: dynamic_crs_keyword left_delimiter frame_reference_epoch + opt_separator_deformation_model_id + right_delimiter + +dynamic_crs_keyword: T_DYNAMIC + +frame_reference_epoch: frame_reference_epoch_keyword left_delimiter + reference_epoch right_delimiter + +frame_reference_epoch_keyword: T_FRAMEEPOCH + +reference_epoch: + unsigned_integer + | unsigned_integer period + | unsigned_integer period unsigned_integer + +opt_separator_deformation_model_id: + | wkt_separator deformation_model_id + +deformation_model_id: deformation_model_id_keyword left_delimiter + deformation_model_name + opt_separator_identifier + right_delimiter + +opt_separator_identifier: + | wkt_separator identifier + +deformation_model_id_keyword: T_MODEL | T_VELOCITYGRID + +deformation_model_name: quoted_latin_text + +// Geodetic CRS + +geodetic_crs: static_geodetic_crs | static_geographic_crs | dynamic_geodetic_crs | dynamic_geographic_crs + +static_geodetic_crs: geodetic_crs_keyword + left_delimiter crs_name + wkt_separator + geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm + wkt_separator + opt_prime_meridian_coordinate_system_scope_extent_identifier_remark + right_delimiter + +static_geographic_crs: geographic_crs_keyword + left_delimiter crs_name + wkt_separator + geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm + wkt_separator + opt_prime_meridian_coordinate_system_scope_extent_identifier_remark + right_delimiter + +dynamic_geodetic_crs: geodetic_crs_keyword + left_delimiter crs_name + wkt_separator dynamic_crs + wkt_separator + geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm + wkt_separator + opt_prime_meridian_coordinate_system_scope_extent_identifier_remark + right_delimiter + +dynamic_geographic_crs: geographic_crs_keyword + left_delimiter crs_name + wkt_separator dynamic_crs + wkt_separator + geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm + wkt_separator + opt_prime_meridian_coordinate_system_scope_extent_identifier_remark + right_delimiter + +opt_prime_meridian_coordinate_system_scope_extent_identifier_remark: + prime_meridian wkt_separator coordinate_system_scope_extent_identifier_remark + | coordinate_system_scope_extent_identifier_remark + +crs_name: quoted_latin_text + +geodetic_crs_keyword: T_GEODCRS | T_GEODETICCRS + +geographic_crs_keyword: T_GEOGCRS | T_GEOGRAPHICCRS + +geodetic_reference_frame_or_geodetic_datum_ensemble_without_pm: + geodetic_reference_frame_without_pm + | geodetic_datum_ensemble_without_pm + +// Ellipsoid + +ellipsoid: ellipsoid_keyword left_delimiter ellipsoid_name + wkt_separator semi_major_axis + wkt_separator inverse_flattening + opt_separator_length_unit_identifier_list + right_delimiter + +opt_separator_length_unit_identifier_list: + | wkt_separator length_unit opt_separator_identifier_list + | wkt_separator identifier opt_separator_identifier_list + +ellipsoid_keyword: T_ELLIPSOID | T_SPHEROID + +ellipsoid_name: quoted_latin_text + +semi_major_axis: unsigned_numeric_literal + +inverse_flattening: unsigned_numeric_literal + +// Prime meridian + +prime_meridian: prime_meridian_keyword left_delimiter + prime_meridian_name wkt_separator + irm_longitude_opt_separator_identifier_list + right_delimiter + +prime_meridian_keyword: T_PRIMEM | T_PRIMEMERIDIAN + +prime_meridian_name: quoted_latin_text + +irm_longitude_opt_separator_identifier_list: + signed_numeric_literal wkt_separator angle_unit opt_separator_identifier_list + | signed_numeric_literal opt_separator_identifier_list + +// Geodetic reference frame + +geodetic_reference_frame_without_pm: geodetic_reference_frame_keyword + left_delimiter datum_name wkt_separator ellipsoid + opt_separator_datum_anchor_identifier_list + right_delimiter + +geodetic_reference_frame_keyword: T_DATUM | T_TRF | T_GEODETICDATUM + +datum_name: quoted_latin_text + +opt_separator_datum_anchor_identifier_list: + | wkt_separator datum_anchor + | wkt_separator identifier opt_separator_identifier_list + | wkt_separator datum_anchor wkt_separator identifier opt_separator_identifier_list + +datum_anchor: datum_anchor_keyword left_delimiter + datum_anchor_description right_delimiter + +datum_anchor_keyword: T_ANCHOR + +datum_anchor_description: quoted_latin_text + +// Projected CRS + +projected_crs: projected_crs_keyword left_delimiter crs_name + wkt_separator base_geodetic_crs + wkt_separator map_projection + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +projected_crs_keyword: T_PROJCRS | T_PROJECTEDCRS + +// Base CRS + +base_geodetic_crs: base_static_geodetic_crs | base_dynamic_geodetic_crs + +base_static_geodetic_crs: base_geodetic_crs_keyword left_delimiter base_crs_name + wkt_separator geodetic_reference_frame_without_pm + opt_separator_pm_ellipsoidal_cs_unit + right_delimiter + +opt_separator_pm_ellipsoidal_cs_unit: + | wkt_separator prime_meridian + | wkt_separator prime_meridian wkt_separator ellipsoidal_cs_unit + | wkt_separator ellipsoidal_cs_unit + +base_dynamic_geodetic_crs: base_geodetic_crs_keyword left_delimiter base_crs_name + wkt_separator dynamic_crs + wkt_separator geodetic_reference_frame_without_pm + opt_separator_pm_ellipsoidal_cs_unit + right_delimiter + +base_geodetic_crs_keyword: T_BASEGEODCRS | T_BASEGEOGCRS + +base_crs_name: quoted_latin_text + +ellipsoidal_cs_unit: angle_unit + +// Map projection + +map_projection: map_projection_keyword left_delimiter + map_projection_name + wkt_separator map_projection_method + wkt_separator + parameter_list_identifier_list + right_delimiter + +parameter_list_identifier_list: + map_projection_parameter opt_separator_identifier_list + | map_projection_parameter wkt_separator parameter_list_identifier_list + +map_projection_keyword: T_CONVERSION + +map_projection_name: quoted_latin_text + +map_projection_method: map_projection_method_keyword left_delimiter + map_projection_method_name + opt_separator_identifier_list right_delimiter + +map_projection_method_keyword: T_METHOD | T_PROJECTION + +map_projection_method_name: quoted_latin_text + +map_projection_parameter: parameter_keyword left_delimiter parameter_name + wkt_separator parameter_value + opt_separator_param_unit_identifier_list + right_delimiter + +opt_separator_param_unit_identifier_list: + | wkt_separator map_projection_parameter_unit opt_separator_identifier_list + +parameter_keyword: T_PARAMETER + +parameter_name: quoted_latin_text + +parameter_value: signed_numeric_literal + +map_projection_parameter_unit: angle_or_length_or_scale_unit + +// Vertical CRS + +vertical_crs: static_vertical_crs | dynamic_vertical_crs + +static_vertical_crs: vertical_crs_keyword left_delimiter crs_name + wkt_separator vertical_reference_frame_or_vertical_datum_ensemble + wkt_separator + vertical_cs_opt_geoid_model_id_scope_extent_identifier_remark + right_delimiter + +dynamic_vertical_crs: vertical_crs_keyword left_delimiter crs_name + wkt_separator dynamic_crs + wkt_separator vertical_reference_frame_or_vertical_datum_ensemble + wkt_separator + vertical_cs_opt_geoid_model_id_scope_extent_identifier_remark + right_delimiter + +vertical_reference_frame_or_vertical_datum_ensemble: vertical_reference_frame | vertical_datum_ensemble + +vertical_cs_opt_geoid_model_id_scope_extent_identifier_remark: + cs_keyword left_delimiter spatial_cs_type + wkt_separator dimension + opt_separator_identifier_list + right_delimiter + wkt_separator spatial_axis + opt_separator_cs_unit_opt_geoid_model_id_scope_extent_identifier_remark + +opt_separator_cs_unit_opt_geoid_model_id_scope_extent_identifier_remark: + | wkt_separator cs_unit opt_separator_scope_extent_identifier_remark + | wkt_separator cs_unit wkt_separator geoid_model_id opt_separator_scope_extent_identifier_remark + | wkt_separator geoid_model_id opt_separator_scope_extent_identifier_remark + | wkt_separator no_opt_separator_scope_extent_identifier_remark + +geoid_model_id: geoid_model_keyword left_delimiter + geoid_model_name opt_separator_identifier + right_delimiter + +geoid_model_keyword: T_GEOIDMODEL + +geoid_model_name: quoted_latin_text + +vertical_crs_keyword: T_VERTCRS | T_VERTICALCRS + +// Vertical reference frame + +vertical_reference_frame: vertical_reference_frame_keyword left_delimiter + datum_name + opt_separator_datum_anchor_identifier_list + right_delimiter + +vertical_reference_frame_keyword: T_VDATUM | T_VRF | T_VERTICALDATUM + +// Engineering CRS + +engineering_crs: engineering_crs_keyword left_delimiter crs_name + wkt_separator engineering_datum + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +engineering_crs_keyword: T_ENGCRS | T_ENGINEERINGCRS + +engineering_datum: engineering_datum_keyword left_delimiter datum_name + opt_separator_datum_anchor_identifier_list + right_delimiter + +engineering_datum_keyword: T_EDATUM | T_ENGINEERINGDATUM + +// Parametric CRS + +parametric_crs: parametric_crs_keyword left_delimiter crs_name + wkt_separator parametric_datum + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +parametric_crs_keyword: T_PARAMETRICCRS + +parametric_datum: parametric_datum_keyword left_delimiter datum_name + opt_separator_datum_anchor_identifier_list + right_delimiter + +parametric_datum_keyword: T_PDATUM | T_PARAMETRICDATUM + +// Temporal CRS + +temporal_crs: temporal_crs_keyword left_delimiter crs_name + wkt_separator temporal_datum + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +temporal_crs_keyword: T_TIMECRS + +temporal_datum: temporal_datum_keyword left_delimiter datum_name + opt_separator_temporal_datum_end + right_delimiter + +opt_separator_temporal_datum_end: + | wkt_separator calendar opt_separator_identifier_list + | wkt_separator calendar wkt_separator temporal_origin opt_separator_identifier_list + | wkt_separator temporal_origin opt_separator_identifier_list + | wkt_separator identifier opt_separator_identifier_list + +temporal_datum_keyword: T_TDATUM | T_TIMEDATUM + +temporal_origin: temporal_origin_keyword left_delimiter + temporal_origin_description right_delimiter + +temporal_origin_keyword: T_TIMEORIGIN + +temporal_origin_description: datetime | quoted_latin_text + +calendar: calendar_keyword left_delimiter calendar_identifier right_delimiter + +calendar_keyword: T_CALENDAR + +calendar_identifier: quoted_latin_text + +// Deriving conversion + +deriving_conversion: deriving_conversion_keyword left_delimiter + deriving_conversion_name wkt_separator + operation_method + wkt_separator parameter_or_parameter_file + opt_separator_deriving_conversion_end + right_delimiter + +parameter_or_parameter_file: operation_parameter | operation_parameter_file + +opt_separator_deriving_conversion_end: + | wkt_separator operation_parameter opt_separator_deriving_conversion_end + | wkt_separator operation_parameter_file opt_separator_deriving_conversion_end + | wkt_separator identifier opt_separator_identifier + +deriving_conversion_keyword: T_DERIVINGCONVERSION + +deriving_conversion_name: quoted_latin_text + +// Derived CRS conversion method + +operation_method: operation_method_keyword left_delimiter + operation_method_name + opt_separator_identifier + right_delimiter + +operation_method_keyword: T_METHOD + +operation_method_name: quoted_latin_text + +// Derived CRS conversion parameter +operation_parameter: parameter_keyword left_delimiter parameter_name + wkt_separator parameter_value wkt_separator parameter_unit + opt_separator_identifier + right_delimiter + +parameter_unit: length_or_angle_or_scale_or_time_or_parametric_unit + +// Approximate definition: conversion_factor should be optional only for a timeunit (but not easy to detect if UNIT keyword is used!) +length_or_angle_or_scale_or_time_or_parametric_unit: + length_or_angle_or_scale_or_time_or_parametric_unit_keyword + left_delimiter unit_name + opt_separator_conversion_factor_identifier_list + right_delimiter + +length_or_angle_or_scale_or_time_or_parametric_unit_keyword: + T_LENGTHUNIT | T_ANGLEUNIT | T_SCALEUNIT | T_TIMEUNIT | T_PARAMETRICUNIT | T_UNIT + +// Derived CRS conversion parameter file + +operation_parameter_file: parameter_file_keyword left_delimiter parameter_name + wkt_separator parameter_file_name + opt_separator_identifier + right_delimiter + +parameter_file_keyword: T_PARAMETERFILE + +parameter_file_name: quoted_latin_text + + +// Derived geodetic CRS and derived geographic CRS + +// Note: derived_geodetic_crs and derived_geographic_crs separated to avoid Bison shift/reduce conflicts +derived_geodetic_crs: geodetic_crs_keyword + left_delimiter crs_name + wkt_separator base_geodetic_crs + wkt_separator deriving_conversion + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +derived_geographic_crs: geographic_crs_keyword + left_delimiter crs_name + wkt_separator base_geodetic_crs + wkt_separator deriving_conversion + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + + +// Derived projected CRS + +derived_projected_crs: derived_projected_crs_keyword left_delimiter + derived_crs_name wkt_separator base_projected_crs + wkt_separator deriving_conversion + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +derived_projected_crs_keyword: T_DERIVEDPROJCRS + +derived_crs_name: quoted_latin_text + +base_projected_crs: base_projected_crs_keyword left_delimiter base_crs_name + wkt_separator base_geodetic_crs + wkt_separator map_projection + right_delimiter + +base_projected_crs_keyword: T_BASEPROJCRS + + +// Derived vertical CRS + +derived_vertical_crs: vertical_crs_keyword left_delimiter crs_name + wkt_separator base_vertical_crs + wkt_separator deriving_conversion + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +base_vertical_crs: base_static_vertical_crs | base_dynamic_vertical_crs + +base_static_vertical_crs: base_vertical_crs_keyword left_delimiter base_crs_name + wkt_separator vertical_reference_frame right_delimiter + +base_dynamic_vertical_crs: base_vertical_crs_keyword left_delimiter base_crs_name + wkt_separator dynamic_crs + wkt_separator vertical_reference_frame right_delimiter + +base_vertical_crs_keyword: T_BASEVERTCRS + + +// Derived engineering CRS + +derived_engineering_crs: engineering_crs_keyword left_delimiter crs_name + wkt_separator base_engineering_crs + wkt_separator deriving_conversion + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +base_engineering_crs: base_engineering_crs_keyword left_delimiter base_crs_name + wkt_separator engineering_datum right_delimiter + +base_engineering_crs_keyword: T_BASEENGCRS + + +// Derived parametric CRS + +derived_parametric_crs: parametric_crs_keyword left_delimiter crs_name + wkt_separator base_parametric_crs + wkt_separator deriving_conversion + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +base_parametric_crs: base_parametric_crs_keyword left_delimiter base_crs_name + wkt_separator parametric_datum right_delimiter + +base_parametric_crs_keyword: T_BASEPARAMCRS + + +// Derived temporal CRS + +derived_temporal_crs: temporal_crs_keyword left_delimiter crs_name + wkt_separator base_temporal_crs + wkt_separator deriving_conversion + wkt_separator coordinate_system_scope_extent_identifier_remark + right_delimiter + +base_temporal_crs: base_temporal_crs_keyword left_delimiter base_crs_name + wkt_separator temporal_datum right_delimiter + +base_temporal_crs_keyword: T_BASETIMECRS + + +// Compound CRS + +compound_crs: compound_crs_keyword left_delimiter compound_crs_name + wkt_separator horizontal_crs wkt_separator + compound_crs_other_components + right_delimiter + +compound_crs_other_components: + vertical_crs opt_separator_scope_extent_identifier_remark + | parametric_crs opt_separator_scope_extent_identifier_remark + | temporal_crs opt_separator_scope_extent_identifier_remark + | vertical_crs wkt_separator temporal_crs opt_separator_scope_extent_identifier_remark + | parametric_crs wkt_separator temporal_crs opt_separator_scope_extent_identifier_remark + +compound_crs_keyword: T_COMPOUNDCRS + +compound_crs_name: quoted_latin_text + +horizontal_crs: geographic2D_crs | projected_crs | engineering_crs + +geographic2D_crs: static_geographic_crs | dynamic_geographic_crs + + +// coordinate epoch and coordinate metadata + +metadata_coordinate_epoch: coordinate_epoch_keyword left_delimiter + coordinate_epoch right_delimiter + +coordinate_epoch_keyword: T_EPOCH | T_COORDEPOCH + +coordinate_epoch: + unsigned_integer + | unsigned_integer period + | unsigned_integer period unsigned_integer + +coordinate_metadata: coordinate_metadata_keyword left_delimiter + coordinate_metadata_crs right_delimiter + +coordinate_metadata_crs: + static_crs + | dynamic_crs_coordinate_metadata wkt_separator metadata_coordinate_epoch + +coordinate_metadata_keyword: T_COORDINATEMETADATA + +static_crs: static_geodetic_crs | static_geographic_crs | + projected_crs | static_vertical_crs | + engineering_crs | parametric_crs | temporal_crs | + derived_geodetic_crs | derived_geographic_crs | + derived_projected_crs | derived_vertical_crs | + derived_engineering_crs | derived_parametric_crs | + derived_temporal_crs | compound_crs + +dynamic_crs_coordinate_metadata: dynamic_geodetic_crs | dynamic_geographic_crs | + projected_crs | dynamic_vertical_crs | + derived_geodetic_crs | derived_geographic_crs | + derived_projected_crs | derived_vertical_crs + +// Coordinate operations + +coordinate_operation: operation_keyword left_delimiter operation_name + wkt_separator source_crs wkt_separator target_crs + wkt_separator operation_method + wkt_separator parameter_or_parameter_file + opt_coordinate_operation_end + right_delimiter + +opt_coordinate_operation_end: + | wkt_separator operation_parameter opt_coordinate_operation_end + | wkt_separator operation_parameter_file opt_coordinate_operation_end + | wkt_separator interpolation_crs opt_separator_scope_extent_identifier_remark + | wkt_separator interpolation_crs wkt_separator operation_accuracy opt_separator_scope_extent_identifier_remark + | wkt_separator operation_accuracy opt_separator_scope_extent_identifier_remark + | wkt_separator no_opt_separator_scope_extent_identifier_remark + +operation_keyword: T_COORDINATEOPERATION + +operation_name: quoted_latin_text + +source_crs: source_crs_keyword left_delimiter crs right_delimiter + +source_crs_keyword: T_SOURCECRS + +target_crs: target_crs_keyword left_delimiter crs right_delimiter + +target_crs_keyword: T_TARGETCRS + +interpolation_crs: interpolation_crs_keyword left_delimiter crs right_delimiter + +interpolation_crs_keyword: T_INTERPOLATIONCRS + +operation_accuracy: operation_accuracy_keyword left_delimiter accuracy right_delimiter + +operation_accuracy_keyword: T_OPERATIONACCURACY + + +// Point motion operation + +point_motion_operation: point_motion_keyword left_delimiter operation_name + wkt_separator source_crs + wkt_separator operation_method + wkt_separator parameter_or_parameter_file + opt_point_motion_operation_end + right_delimiter + +opt_point_motion_operation_end: + | wkt_separator operation_parameter opt_point_motion_operation_end + | wkt_separator operation_parameter_file opt_point_motion_operation_end + | wkt_separator operation_accuracy opt_separator_scope_extent_identifier_remark + | wkt_separator no_opt_separator_scope_extent_identifier_remark + +point_motion_keyword: T_POINTMOTIONOPERATION + + +// Concatenated operation + +concatenated_operation: concatenated_operation_keyword left_delimiter + operation_name + wkt_separator source_crs wkt_separator target_crs + wkt_separator step_keyword left_delimiter step right_delimiter + wkt_separator step_keyword left_delimiter step right_delimiter + opt_concatenated_operation_end + right_delimiter + +step: coordinate_operation | point_motion_keyword | deriving_conversion + +opt_concatenated_operation_end: + | wkt_separator step_keyword left_delimiter step right_delimiter opt_concatenated_operation_end + | wkt_separator operation_accuracy opt_separator_scope_extent_identifier_remark + | wkt_separator no_opt_separator_scope_extent_identifier_remark + +concatenated_operation_keyword: T_CONCATENATEDOPERATION + +step_keyword: T_STEP + + +// Bound CRS + +bound_crs: bound_crs_keyword left_delimiter + source_crs wkt_separator target_crs + wkt_separator abridged_coordinate_transformation + opt_separator_scope_extent_identifier_remark + right_delimiter + +bound_crs_keyword: T_BOUNDCRS + +abridged_coordinate_transformation: abridged_transformation_keyword left_delimiter + operation_name wkt_separator + operation_method wkt_separator + abridged_parameter_or_parameter_file + opt_end_abridged_coordinate_transformation + right_delimiter + +abridged_parameter_or_parameter_file: abridged_transformation_parameter | operation_parameter_file + +opt_end_abridged_coordinate_transformation: + | wkt_separator abridged_transformation_parameter opt_end_abridged_coordinate_transformation + | wkt_separator operation_parameter_file opt_end_abridged_coordinate_transformation + | wkt_separator no_opt_separator_scope_extent_identifier_remark + +abridged_transformation_keyword: T_ABRIDGEDTRANSFORMATION + +abridged_transformation_parameter: parameter_keyword left_delimiter + parameter_name wkt_separator parameter_value + opt_separator_identifier_list + right_delimiter diff --git a/src/wkt2_parser.cpp b/src/wkt2_parser.cpp new file mode 100644 index 00000000..f77c7ceb --- /dev/null +++ b/src/wkt2_parser.cpp @@ -0,0 +1,221 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: WKT2 parser grammar + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2018 Even Rouault, + * + * 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. + ****************************************************************************/ + +#ifndef FROM_PROJ_CPP +#define FROM_PROJ_CPP +#endif + +#include "proj/internal/internal.hpp" + +#include +#include +#include +#include + +#include "wkt2_parser.h" +#include "wkt_parser.hpp" + +using namespace NS_PROJ::internal; + +//! @cond Doxygen_Suppress + +// --------------------------------------------------------------------------- + +struct pj_wkt2_parse_context : public pj_wkt_parse_context {}; + +// --------------------------------------------------------------------------- + +void pj_wkt2_error(pj_wkt2_parse_context *context, const char *msg) { + pj_wkt_error(context, msg); +} + +// --------------------------------------------------------------------------- + +std::string pj_wkt2_parse(const std::string &wkt) { + pj_wkt2_parse_context context; + context.pszInput = wkt.c_str(); + context.pszLastSuccess = wkt.c_str(); + context.pszNext = wkt.c_str(); + if (pj_wkt2_parse(&context) != 0) { + return context.errorMsg; + } + return std::string(); +} + +// --------------------------------------------------------------------------- + +typedef struct { + const char *pszToken; + int nTokenVal; +} wkt2_tokens; + +#define PAIR(X) \ + { #X, T_##X } + +static const wkt2_tokens tokens[] = { + PAIR(PARAMETER), PAIR(PROJECTION), PAIR(DATUM), PAIR(SPHEROID), + PAIR(PRIMEM), PAIR(UNIT), PAIR(AXIS), + + PAIR(GEODCRS), PAIR(LENGTHUNIT), PAIR(ANGLEUNIT), PAIR(SCALEUNIT), + PAIR(TIMEUNIT), PAIR(ELLIPSOID), PAIR(CS), PAIR(ID), PAIR(PROJCRS), + PAIR(BASEGEODCRS), PAIR(MERIDIAN), PAIR(BEARING), PAIR(ORDER), PAIR(ANCHOR), + PAIR(CONVERSION), PAIR(METHOD), PAIR(REMARK), PAIR(GEOGCRS), + PAIR(BASEGEOGCRS), PAIR(SCOPE), PAIR(AREA), PAIR(BBOX), PAIR(CITATION), + PAIR(URI), PAIR(VERTCRS), PAIR(VDATUM), PAIR(GEOIDMODEL), PAIR(COMPOUNDCRS), + PAIR(PARAMETERFILE), PAIR(COORDINATEOPERATION), PAIR(SOURCECRS), + PAIR(TARGETCRS), PAIR(INTERPOLATIONCRS), PAIR(OPERATIONACCURACY), + PAIR(CONCATENATEDOPERATION), PAIR(STEP), PAIR(BOUNDCRS), + PAIR(ABRIDGEDTRANSFORMATION), PAIR(DERIVINGCONVERSION), PAIR(TDATUM), + PAIR(CALENDAR), PAIR(TIMEORIGIN), PAIR(TIMECRS), PAIR(VERTICALEXTENT), + PAIR(TIMEEXTENT), PAIR(USAGE), PAIR(DYNAMIC), PAIR(FRAMEEPOCH), PAIR(MODEL), + PAIR(VELOCITYGRID), PAIR(ENSEMBLE), PAIR(MEMBER), PAIR(ENSEMBLEACCURACY), + PAIR(DERIVEDPROJCRS), PAIR(BASEPROJCRS), PAIR(EDATUM), PAIR(ENGCRS), + PAIR(PDATUM), PAIR(PARAMETRICCRS), PAIR(PARAMETRICUNIT), PAIR(BASEVERTCRS), + PAIR(BASEENGCRS), PAIR(BASEPARAMCRS), PAIR(BASETIMECRS), PAIR(GEODETICCRS), + PAIR(GEODETICDATUM), PAIR(PROJECTEDCRS), PAIR(PRIMEMERIDIAN), + PAIR(GEOGRAPHICCRS), PAIR(TRF), PAIR(VERTICALCRS), PAIR(VERTICALDATUM), + PAIR(VRF), PAIR(TIMEDATUM), PAIR(TEMPORALQUANTITY), PAIR(ENGINEERINGDATUM), + PAIR(ENGINEERINGCRS), PAIR(PARAMETRICDATUM), PAIR(EPOCH), PAIR(COORDEPOCH), + PAIR(COORDINATEMETADATA), PAIR(POINTMOTIONOPERATION), + + // CS types + PAIR(AFFINE), PAIR(CARTESIAN), PAIR(CYLINDRICAL), PAIR(ELLIPSOIDAL), + PAIR(LINEAR), PAIR(PARAMETRIC), PAIR(POLAR), PAIR(SPHERICAL), + PAIR(VERTICAL), PAIR(TEMPORAL), PAIR(TEMPORALCOUNT), PAIR(TEMPORALMEASURE), + PAIR(ORDINAL), PAIR(TEMPORALDATETIME), + + // Axis directions + PAIR(NORTH), PAIR(NORTHNORTHEAST), PAIR(NORTHEAST), PAIR(EASTNORTHEAST), + PAIR(EAST), PAIR(EASTSOUTHEAST), PAIR(SOUTHEAST), PAIR(SOUTHSOUTHEAST), + PAIR(SOUTH), PAIR(SOUTHSOUTHWEST), PAIR(SOUTHWEST), PAIR(WESTSOUTHWEST), + PAIR(WEST), PAIR(WESTNORTHWEST), PAIR(NORTHWEST), PAIR(NORTHNORTHWEST), + PAIR(UP), PAIR(DOWN), PAIR(GEOCENTRICX), PAIR(GEOCENTRICY), + PAIR(GEOCENTRICZ), PAIR(COLUMNPOSITIVE), PAIR(COLUMNNEGATIVE), + PAIR(ROWPOSITIVE), PAIR(ROWNEGATIVE), PAIR(DISPLAYRIGHT), PAIR(DISPLAYLEFT), + PAIR(DISPLAYUP), PAIR(DISPLAYDOWN), PAIR(FORWARD), PAIR(AFT), PAIR(PORT), + PAIR(STARBOARD), PAIR(CLOCKWISE), PAIR(COUNTERCLOCKWISE), PAIR(TOWARDS), + PAIR(AWAYFROM), PAIR(FUTURE), PAIR(PAST), PAIR(UNSPECIFIED), +}; + +// --------------------------------------------------------------------------- + +int pj_wkt2_lex(YYSTYPE * /*pNode */, pj_wkt2_parse_context *context) { + size_t i; + const char *pszInput = context->pszNext; + + /* -------------------------------------------------------------------- */ + /* Skip white space. */ + /* -------------------------------------------------------------------- */ + while (*pszInput == ' ' || *pszInput == '\t' || *pszInput == 10 || + *pszInput == 13) + pszInput++; + + context->pszLastSuccess = pszInput; + + if (*pszInput == '\0') { + context->pszNext = pszInput; + return EOF; + } + + /* -------------------------------------------------------------------- */ + /* Recognize node names. */ + /* -------------------------------------------------------------------- */ + if (isalpha(*pszInput)) { + for (i = 0; i < sizeof(tokens) / sizeof(tokens[0]); i++) { + if (ci_starts_with(pszInput, tokens[i].pszToken) && + !isalpha(pszInput[strlen(tokens[i].pszToken)])) { + context->pszNext = pszInput + strlen(tokens[i].pszToken); + return tokens[i].nTokenVal; + } + } + } + + /* -------------------------------------------------------------------- */ + /* Recognize unsigned integer */ + /* -------------------------------------------------------------------- */ + + if (*pszInput >= '0' && *pszInput <= '9') { + + // Special case for 1, 2, 3 + if ((*pszInput == '1' || *pszInput == '2' || *pszInput == '3') && + !(pszInput[1] >= '0' && pszInput[1] <= '9')) { + context->pszNext = pszInput + 1; + return *pszInput; + } + + pszInput++; + while (*pszInput >= '0' && *pszInput <= '9') + pszInput++; + + context->pszNext = pszInput; + + return T_UNSIGNED_INTEGER_DIFFERENT_ONE_TWO_THREE; + } + + /* -------------------------------------------------------------------- */ + /* Recognize double quoted strings. */ + /* -------------------------------------------------------------------- */ + if (*pszInput == '"') { + pszInput++; + while (*pszInput != '\0') { + if (*pszInput == '"') { + if (pszInput[1] == '"') + pszInput++; + else + break; + } + pszInput++; + } + if (*pszInput == '\0') { + context->pszNext = pszInput; + return EOF; + } + context->pszNext = pszInput + 1; + return T_STRING; + } + + // As used in examples of OGC 12-063r5 + const char *startPrintedQuote = "\xE2\x80\x9C"; + const char *endPrintedQuote = "\xE2\x80\x9D"; + if (strncmp(pszInput, startPrintedQuote, 3) == 0) { + context->pszNext = strstr(pszInput, endPrintedQuote); + if (context->pszNext == nullptr) { + context->pszNext = pszInput + strlen(pszInput); + return EOF; + } + context->pszNext += 3; + return T_STRING; + } + + /* -------------------------------------------------------------------- */ + /* Handle special tokens. */ + /* -------------------------------------------------------------------- */ + context->pszNext = pszInput + 1; + return *pszInput; +} + +//! @endcond diff --git a/src/wkt2_parser.h b/src/wkt2_parser.h new file mode 100644 index 00000000..1eaadab6 --- /dev/null +++ b/src/wkt2_parser.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: WKT2 parser grammar + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2018 Even Rouault, + * + * 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. + ****************************************************************************/ + +#ifndef PJ_WKT2_PARSER_H_INCLUDED +#define PJ_WKT2_PARSER_H_INCLUDED + +#ifndef DOXYGEN_SKIP + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct pj_wkt2_parse_context pj_wkt2_parse_context; + +#include "wkt2_generated_parser.h" + +void pj_wkt2_error( pj_wkt2_parse_context *context, const char *msg ); +int pj_wkt2_lex(YYSTYPE* pNode, pj_wkt2_parse_context *context); +int pj_wkt2_parse(pj_wkt2_parse_context *context); + +#ifdef __cplusplus +} + +std::string pj_wkt2_parse(const std::string& wkt); + +#endif + +#endif /* #ifndef DOXYGEN_SKIP */ + +#endif /* PJ_WKT2_PARSER_H_INCLUDED */ diff --git a/src/wkt_parser.cpp b/src/wkt_parser.cpp new file mode 100644 index 00000000..32fc4e34 --- /dev/null +++ b/src/wkt_parser.cpp @@ -0,0 +1,60 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: WKT parser common routines + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2018 Even Rouault, + * + * 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. + ****************************************************************************/ + +#include "wkt_parser.hpp" + +#include +#include + +// --------------------------------------------------------------------------- + +void pj_wkt_error(pj_wkt_parse_context *context, const char *msg) { + context->errorMsg = "Parsing error : "; + context->errorMsg += msg; + context->errorMsg += ". Error occurred around:\n"; + + std::string ctxtMsg; + const int n = static_cast(context->pszLastSuccess - context->pszInput); + int start_i = std::max(0, n - 40); + for (int i = start_i; i < n + 40 && context->pszInput[i]; i++) { + if (context->pszInput[i] == '\r' || context->pszInput[i] == '\n') { + if (i > n) { + break; + } else { + ctxtMsg.clear(); + start_i = i + 1; + } + } else { + ctxtMsg += context->pszInput[i]; + } + } + context->errorMsg += ctxtMsg; + context->errorMsg += '\n'; + for (int i = start_i; i < n; i++) + context->errorMsg += ' '; + context->errorMsg += '^'; +} diff --git a/src/wkt_parser.hpp b/src/wkt_parser.hpp new file mode 100644 index 00000000..0e7e9e8b --- /dev/null +++ b/src/wkt_parser.hpp @@ -0,0 +1,50 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: WKT parser common routines + * Author: Even Rouault, + * + ****************************************************************************** + * Copyright (c) 2018 Even Rouault, + * + * 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. + ****************************************************************************/ + +#ifndef PJ_WKT_PARSER_H_INCLUDED +#define PJ_WKT_PARSER_H_INCLUDED + +//! @cond Doxygen_Suppress + +#include + +struct pj_wkt_parse_context { + const char *pszInput = nullptr; + const char *pszLastSuccess = nullptr; + const char *pszNext = nullptr; + std::string errorMsg{}; + + pj_wkt_parse_context() = default; + pj_wkt_parse_context(const pj_wkt_parse_context &) = delete; + pj_wkt_parse_context &operator=(const pj_wkt_parse_context &) = delete; +}; + +void pj_wkt_error(pj_wkt_parse_context *context, const char *msg); + +//! @endcond + +#endif // PJ_WKT_PARSER_H_INCLUDED diff --git a/src/zpoly1.cpp b/src/zpoly1.cpp new file mode 100644 index 00000000..bacb62ce --- /dev/null +++ b/src/zpoly1.cpp @@ -0,0 +1,46 @@ +/* evaluate complex polynomial */ +#include "projects.h" +/* note: coefficients are always from C_1 to C_n +** i.e. C_0 == (0., 0) +** n should always be >= 1 though no checks are made +*/ + COMPLEX +pj_zpoly1(COMPLEX z, const COMPLEX *C, int n) { + COMPLEX a; + double t; + + a = *(C += n); + while (n-- > 0) { + a.r = (--C)->r + z.r * (t = a.r) - z.i * a.i; + a.i = C->i + z.r * a.i + z.i * t; + } + a.r = z.r * (t = a.r) - z.i * a.i; + a.i = z.r * a.i + z.i * t; + return a; +} +/* evaluate complex polynomial and derivative */ + COMPLEX +pj_zpolyd1(COMPLEX z, const COMPLEX *C, int n, COMPLEX *der) { + COMPLEX a, b; + double t; + int first = 1; + + a = *(C += n); + b = a; + while (n-- > 0) { + if (first) { + first = 0; + } else { + b.r = a.r + z.r * (t = b.r) - z.i * b.i; + b.i = a.i + z.r * b.i + z.i * t; + } + a.r = (--C)->r + z.r * (t = a.r) - z.i * a.i; + a.i = C->i + z.r * a.i + z.i * t; + } + b.r = a.r + z.r * (t = b.r) - z.i * b.i; + b.i = a.i + z.r * b.i + z.i * t; + a.r = z.r * (t = a.r) - z.i * a.i; + a.i = z.r * a.i + z.i * t; + *der = b; + return a; +} -- cgit v1.2.3