diff options
| author | Kristian Evers <kristianevers@gmail.com> | 2019-11-28 14:58:14 +0100 |
|---|---|---|
| committer | Kristian Evers <kristianevers@gmail.com> | 2019-11-28 14:58:14 +0100 |
| commit | ac2762b581918dd3fcecf2a4d0dd72f92ca87011 (patch) | |
| tree | d0158eb03d39b9d2249a30ea88f333c8e560f351 | |
| parent | 2bc1e2e1a9d0a7abe410ee99d39236570474cfde (diff) | |
| parent | bce4b158ab5f7d146de8e8fc98df4612dc8c2c9e (diff) | |
| download | PROJ-ac2762b581918dd3fcecf2a4d0dd72f92ca87011.tar.gz PROJ-ac2762b581918dd3fcecf2a4d0dd72f92ca87011.zip | |
Merge branch '6.2' of https://github.com/OSGeo/proj.4 into 6.2
54 files changed, 2269 insertions, 163 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f654b0ea..97cc521d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,9 +95,9 @@ colormsg(_HIBLUE_ "Configuring PROJ:") #PROJ version information ################################################################################ include(ProjVersion) -proj_version(MAJOR 6 MINOR 2 PATCH 0) +proj_version(MAJOR 6 MINOR 2 PATCH 1) set(PROJ_API_VERSION "17") -set(PROJ_BUILD_VERSION "17.0.2") +set(PROJ_BUILD_VERSION "17.1.2") ################################################################################ # Build features and variants diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..5ee42e5b --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,77 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [kristianevers@gmail.com](mailto:kristianevers@gmail.com). All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq + diff --git a/HOWTO-RELEASE b/HOWTO-RELEASE index 865dbcf2..0911486e 100644 --- a/HOWTO-RELEASE +++ b/HOWTO-RELEASE @@ -243,3 +243,6 @@ If the previous active version was, let's say, 6.1 and the new version is, let's then checkout 6.1 branch, and in travis/after_success.sh, remove the code that causes commits to 6.1 to cause a website refresh, that is remove the code under `if test "$TRAVIS_SECURE_ENV_VARS" = "true" -a "$TRAVIS_BRANCH" = "6.1"; then`. + +Also edit docs/source/conf.py to change the active branch for documentation +in the `github_version` variable. @@ -1,3 +1,83 @@ +6.2.1 Release Notes +------------------- + + Updates + ------- + + o Update the EPSG database to version 9.8.2 + + Bug fixes + ------- + + o Fixed erroneous spelling of "Potsdam" (#1573) + + o Calculate y-coordinate correctly in bertin1953 in all cases (#1579) + + o proj_create_crs_to_crs_from_pj(): make the PJ* arguments const PJ* (#1583) + + o PROJStringParser::createFromPROJString(): avoid potential infinite + recursion (#1574) + + o Avoid core dump when setting ctx==NULL in functions + proj_coordoperation_is_instantiable and + proj_coordoperation_has_ballpark_transformation (#1590) + + o createOperations(): fix conversion from/to PROJ.4 CRS strings with + non-ISO-kosher options and +towgs84/+nadgrids (#1602) + + o proj_trans_generic(): properly set coordinate time to HUGE_VAL when no + value is passed to the function (#1604) + + o Fix support for +proj=ob_tran +o_proj=lonlat/latlong/latlon instead of only + only allowing +o_proj=longlat (#1601) + + o Improve backwards compatibility of vertical transforms (#1613) + + o Improve emulation of deprecated +init style initialization (#1614) + + o cs2cs: autopromote CRS to 3D when there's a mix of 2D and 3D (#1563) + + o Avoid divisions by zero in odd situations (#1620) + + o Avoid compile error on Solaris (#1639) + + o proj_create_crs_to_crs(): fix when there are only transformations with + ballpark steps (#1643) + + o PROJ string CRS ingester: recognize more unit-less parameters, and general + handling of +key=string_value parameters (#1645) + + o Only call pkg-config in configure when necessary (#1652) + + o aeqd: for spherical forward path, go to higher precision ellipsoidal + case when the point coordinates are super close to the origin (#1654) + + o proj_create_crs_to_crs(): remove elimination of Ballpark operations + that caused transformation failures in some cases (#1665) + + o createOperations(): allow transforming from a compoundCRS of a bound + verticalCRS to a 2D CRS (#1667) + + o Avoid segfaults in case of out-of-memory situations (#1679) + + o createOperations(): fix double vertical unit conversion from CompoundCRS + to other CRS when the horizontal part of the projected CRS uses non-metre + unit (#1683) + + o importFromWkt(): fix axis orientation for non-standard ESRI WKT (#1690) + + + THANKS TO + --------- + + R. Schmunk + Jakob Egger + Alan D. Snow + Stephan Hügel + Kai Pastor + Kristian Evers + Even Rouault + 6.2.0 Release Notes ------------------- @@ -1,10 +1,11 @@ # PROJ -[](https://travis-ci.com/OSGeo/PROJ) -[](https://ci.appveyor.com/project/OSGeo/PROJ) -[](https://coveralls.io/github/OSGeo/PROJ?branch=master) +[](https://travis-ci.com/OSGeo/PROJ) +[](https://ci.appveyor.com/project/OSGeo/PROJ?branch=6.2) +[](https://coveralls.io/github/OSGeo/PROJ?branch=6.2) [](https://gitter.im/OSGeo/proj.4) [](http://lists.osgeo.org/mailman/listinfo/proj) +[](code-of-conduct.md) PROJ is a generic coordinate transformation software, that transforms coordinates from one coordinate reference system (CRS) to another. diff --git a/configure.ac b/configure.ac index fc1b0ead..788175e2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT([PROJ], [6.2.0], +AC_INIT([PROJ], [6.2.1], [https://github.com/OSGeo/PROJ/issues], proj, [https://proj.org]) AC_CONFIG_MACRO_DIR([m4]) AC_LANG(C) diff --git a/data/ITRF2014 b/data/ITRF2014 index 557ce60a..26c2ceff 100644 --- a/data/ITRF2014 +++ b/data/ITRF2014 @@ -32,24 +32,24 @@ # Z. Altamimi et al, 2017, ITRF2014 plate motion model, # doi: 10.1093/gji/ggx136 -<ANTA> +proj=helmert +drx=−0.000248 +dry=−0.000324 +drz=0.000675 +convention=position_vector +<ANTA> +proj=helmert +drx=-0.000248 +dry=-0.000324 +drz=0.000675 +convention=position_vector -<ARAB> +proj=helmert +drx=0.001154 +dry=−0.000136 +drz=0.001444 +convention=position_vector +<ARAB> +proj=helmert +drx=0.001154 +dry=-0.000136 +drz=0.001444 +convention=position_vector <AUST> +proj=helmert +drx=0.001510 +dry=0.001182 +drz=0.001215 +convention=position_vector -<EURA> +proj=helmert +drx=−0.000085 +dry=−0.000531 +drz=0.000770 +convention=position_vector +<EURA> +proj=helmert +drx=-0.000085 +dry=-0.000531 +drz=0.000770 +convention=position_vector -<INDI> +proj=helmert +drx=0.001154 +dry=−0.000005 +drz=0.001454 +convention=position_vector +<INDI> +proj=helmert +drx=0.001154 +dry=-0.000005 +drz=0.001454 +convention=position_vector -<NAZC> +proj=helmert +drx=−0.000333 +dry=−0.001544 +drz=0.001623 +convention=position_vector +<NAZC> +proj=helmert +drx=-0.000333 +dry=-0.001544 +drz=0.001623 +convention=position_vector <NOAM> +proj=helmert +drx=0.000024 +dry=-0.000694 +drz=-0.000063 +convention=position_vector -<NUBI> +proj=helmert +drx=0.000099 +dry=−0.000614 +drz=0.000733 +convention=position_vector +<NUBI> +proj=helmert +drx=0.000099 +dry=-0.000614 +drz=0.000733 +convention=position_vector -<PCFC> +proj=helmert +drx=−0.000409 +dry=0.001047 +drz=-0.002169 +convention=position_vector +<PCFC> +proj=helmert +drx=-0.000409 +dry=0.001047 +drz=-0.002169 +convention=position_vector -<SOAM> +proj=helmert +drx=−0.000270 +dry=−0.000301 +drz=−0.000140 +convention=position_vector +<SOAM> +proj=helmert +drx=-0.000270 +dry=-0.000301 +drz=-0.000140 +convention=position_vector -<SOMA> +proj=helmert +drx=−0.000121 +dry=−0.000794 +drz=0.000884 +convention=position_vector +<SOMA> +proj=helmert +drx=-0.000121 +dry=-0.000794 +drz=0.000884 +convention=position_vector diff --git a/docs/images/logo.png b/docs/images/logo.png Binary files differnew file mode 100644 index 00000000..b7ef2b57 --- /dev/null +++ b/docs/images/logo.png diff --git a/docs/source/_extensions/redirects.py b/docs/source/_extensions/redirects.py new file mode 100644 index 00000000..6a59b622 --- /dev/null +++ b/docs/source/_extensions/redirects.py @@ -0,0 +1,39 @@ +import os + +# https://tech.signavio.com/2017/managing-sphinx-redirects + + +template="""<html> + <head> + <meta http-equiv="refresh" content="1; url=%s" /> + <script> + window.location.href = "%s" + </script> + </head> +</html>""" + + +def gather_redirects(): + output = {} + + output.update({ 'projjson.html' : 'usage/projjson.html' }) + return output + +from shutil import copyfile +# copy legacy redirects +def copy_legacy_redirects(app, docname): # Sphinx expects two arguments + if app.builder.name == 'html': + for key in app.config.redirect_files: + src = key + tgt = app.config.redirect_files[key] + html = template % (tgt, tgt) + with open(os.path.join(app.outdir, src), 'wb') as f: + f.write(html.encode('utf-8')) + f.close() + + + +def setup(app): + app.add_config_value('redirect_files', {}, 'html') + app.connect('build-finished', copy_legacy_redirects) + return { 'parallel_read_safe': False, 'parallel_write_safe': True } diff --git a/docs/source/about.rst b/docs/source/about.rst index f78de532..6ecbb1bc 100644 --- a/docs/source/about.rst +++ b/docs/source/about.rst @@ -2,27 +2,11 @@ About ############################################################################### -PROJ is a generic coordinate transformation software that transforms geospatial -coordinates from one coordinate reference system (CRS) to another. This -includes cartographic projections as well as geodetic transformations. - -PROJ includes :ref:`command line applications<apps>` for easy conversion of -coordinates from text files or directly from user input. In addition to the -command line utilities PROJ also exposes an -:ref:`application programming interface<reference>`, or API in short. The API -lets developers use the functionality of PROJ in their own software without having -to implement similar functionality themselves. - -PROJ started purely as a cartography application letting users convert geodetic -coordinates into projected coordinates using a number of different cartographic -projections. Over the years, as the need has become apparent, support for datum -shifts has slowly worked its way into PROJ as well. Today PROJ supports more -than a hundred different map projections and can transform coordinates between -datums using all but the most obscure geodetic techniques. - - .. image:: ../images/OSGeo_community.png - :scale: 30 % - :alt: OSGeo Community +.. include:: about_core.rst + +.. image:: ../images/OSGeo_community.png + :scale: 30 % + :alt: OSGeo Community Citation ------------------------------------------------------------------------------- @@ -31,6 +15,8 @@ Citation .. include:: ../../CITATION +.. _license: + License ------------------------------------------------------------------------------- diff --git a/docs/source/about_core.rst b/docs/source/about_core.rst new file mode 100644 index 00000000..5f4238bc --- /dev/null +++ b/docs/source/about_core.rst @@ -0,0 +1,18 @@ +PROJ is a generic coordinate transformation software that transforms geospatial +coordinates from one coordinate reference system (CRS) to another. This +includes cartographic projections as well as geodetic transformations. PROJ +is released under the :ref:`X/MIT open source license <license>` + +PROJ includes :ref:`command line applications<apps>` for easy conversion of +coordinates from text files or directly from user input. In addition to the +command line utilities PROJ also exposes an +:ref:`application programming interface<reference>`, or API in short. The API +lets developers use the functionality of PROJ in their own software without having +to implement similar functionality themselves. + +PROJ started purely as a cartography application letting users convert geodetic +coordinates into projected coordinates using a number of different cartographic +projections. Over the years, as the need has become apparent, support for datum +shifts has slowly worked its way into PROJ as well. Today PROJ supports more +than a hundred different map projections and can transform coordinates between +datums using all but the most obscure geodetic techniques.
\ No newline at end of file diff --git a/docs/source/community/code_of_conduct.rst b/docs/source/community/code_of_conduct.rst new file mode 100644 index 00000000..175b184a --- /dev/null +++ b/docs/source/community/code_of_conduct.rst @@ -0,0 +1,92 @@ +.. _code_of_conduct: + +=========================== +Code of Conduct +=========================== + +The PROJ project has adopted the +`Contributor Covenant Code of Conduct <https://www.contributor-covenant.org/>`_. +Everyone who participates in the PROJ community is expected to follow the +code of conduct as written below. + + +Our Pledge +---------- + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +Our Standards +------------- + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +Our Responsibilities +-------------------- + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +Scope +----- + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +Enforcement +----------- + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at `kristianevers@gmail.com <mailto:kristianevers@gmail.com>`_. +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +Attribution +----------- + +This Code of Conduct is adapted from the +`Contributor Covenant <https://www.contributor-covenant.org>`_, version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq + diff --git a/docs/source/community/index.rst b/docs/source/community/index.rst index ccdbceca..b0d1ce3a 100644 --- a/docs/source/community/index.rst +++ b/docs/source/community/index.rst @@ -14,4 +14,5 @@ contributor the community is always very welcoming. channels contributing code_contributions + code_of_conduct rfc/index diff --git a/docs/source/community/rfc/rfc-2.rst b/docs/source/community/rfc/rfc-2.rst index e6f013a3..df6f742d 100644 --- a/docs/source/community/rfc/rfc-2.rst +++ b/docs/source/community/rfc/rfc-2.rst @@ -6,7 +6,7 @@ PROJ RFC 2: Initial integration of "GDAL SRS barn" work :Author: Even Rouault :Contact: even.rouault at spatialys.com -:Status: Adopted (not yet merged into master) +:Status: Adopted, implemented in PROJ 6.0 :Initial version: 2018-10-09 :Last Updated: 2018-10-31 diff --git a/docs/source/conf.py b/docs/source/conf.py index dd7adc2d..1008b79e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,6 +20,7 @@ import datetime # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('_extensions')) import bibstyle @@ -35,6 +36,7 @@ extensions = [ 'sphinx.ext.mathjax', 'sphinxcontrib.bibtex', 'breathe', + 'redirects', ] # Add any paths that contain templates here, relative to this directory. @@ -66,7 +68,7 @@ copyright = u'1983-{0}'.format(now.year) # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. -version = '6.2.0' +version = '6.2.1' # use same |release| as |version| release = version @@ -130,8 +132,20 @@ html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -html_theme_options = {} - +html_theme_options = { + 'canonical_url': 'https://proj.org', + 'logo_only': True, + 'display_version': True, + 'prev_next_buttons_location': 'both', + 'style_external_links': False, + 'style_nav_header_background': '#353130', + # Toc options + 'collapse_navigation': True, + 'sticky_navigation': True, + #'navigation_depth': 4, + 'includehidden': True, + 'titles_only': False +} # Add any paths that contain custom themes here, relative to this directory. @@ -144,7 +158,7 @@ html_theme_options = {} # The name of an image file (relative to this directory) to place at the top # of the sidebar. -#html_logo = None +html_logo = '../images/logo.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 @@ -157,6 +171,12 @@ html_theme_options = {} html_static_path = ['_static'] html_context = { + 'display_github': True, + 'theme_vcs_pageview_mode': 'edit', + 'github_user': 'OSGeo', + 'github_repo': 'PROJ', + # TODO: edit when switching active branch + 'github_version': '/6.2/docs/source/', 'css_files': [ '_static/theme_overrides.css', # override wide tables in RTD theme ], @@ -358,3 +378,6 @@ texinfo_documents = [ breathe_projects = { "cpp_stuff":"../build/xml/", } + +import redirects +redirect_files = redirects.gather_redirects() diff --git a/docs/source/download.rst b/docs/source/download.rst index 9ec03368..36e2a897 100644 --- a/docs/source/download.rst +++ b/docs/source/download.rst @@ -13,7 +13,7 @@ distribution of the source code and various resource file archives. See Current Release -------------------------------------------------------------------------------- -* **2019-09-01** `proj-6.2.0.tar.gz`_ (`md5`_) +* **2019-11-01** `proj-6.2.1.tar.gz`_ (`md5`_) * **2018-09-15** `proj-datumgrid-1.8.zip`_ * **2019-09-01** `proj-datumgrid-europe-1.4.zip`_ * **2019-03-01** `proj-datumgrid-north-america-1.2.zip`_ @@ -24,6 +24,7 @@ Current Release Past Releases -------------------------------------------------------------------------------- +* **2019-09-01** `proj-6.2.0.tar.gz`_ * **2019-07-01** `proj-6.1.1.tar.gz`_ * **2019-05-15** `proj-6.1.0.tar.gz`_ * **2019-03-01** `proj-6.0.0.tar.gz`_ @@ -44,6 +45,7 @@ Past Releases * **2018-03-01** `proj-datumgrid-europe-1.0.zip`_ * **2018-03-01** `proj-datumgrid-north-america-1.0.zip`_ +.. _`proj-6.2.1.tar.gz`: https://download.osgeo.org/proj/proj-6.2.1.tar.gz .. _`proj-6.2.0.tar.gz`: https://download.osgeo.org/proj/proj-6.2.0.tar.gz .. _`proj-6.1.1.tar.gz`: https://download.osgeo.org/proj/proj-6.1.1.tar.gz .. _`proj-6.1.0.tar.gz`: https://download.osgeo.org/proj/proj-6.1.0.tar.gz @@ -68,5 +70,5 @@ Past Releases .. _`proj-datumgrid-north-america-1.2.zip`: https://download.osgeo.org/proj/proj-datumgrid-north-america-1.2.zip .. _`proj-datumgrid-oceania-1.0.zip`: https://download.osgeo.org/proj/proj-datumgrid-oceania-1.0.zip .. _`proj-datumgrid-world-1.0.zip`: https://download.osgeo.org/proj/proj-datumgrid-world-1.0.zip -.. _`md5`: https://download.osgeo.org/proj/proj-6.2.0.tar.gz.md5 +.. _`md5`: https://download.osgeo.org/proj/proj-6.2.1.tar.gz.md5 .. _`proj.pdf`: https://raw.githubusercontent.com/OSGeo/PROJ/gh-pages/proj.pdf diff --git a/docs/source/faq.rst b/docs/source/faq.rst index e7265d48..0096accb 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -115,7 +115,7 @@ There are however exceptions, especially when dealing with coordinate systems th don't align with the cardinal directions of a compass. For example it is not obvious which coordinate component aligns to which axis in a skewed coordinate system with a 45 degrees angle against the north direction. Similarly, a geocentric -cartesain coordinate system usually has the z-component aligned with the rotational +cartesian coordinate system usually has the z-component aligned with the rotational axis of the earth and hence the axis points towards north. Both cases are incompatible with the convention of always having the x-component be the east/west axis, the y-component the north/south axis and the z-component the up/down axis. diff --git a/docs/source/index.rst b/docs/source/index.rst index 69f483ce..e9590d99 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -24,23 +24,7 @@ PROJ .. only:: html - PROJ is a generic coordinate transformation software that transforms geospatial - coordinates from one coordinate reference system (CRS) to another. This - includes cartographic projections as well as geodetic transformations. - - PROJ includes :ref:`command line applications<apps>` for easy conversion of - coordinates from text files or directly from user input. In addition to the - command line utilities PROJ also exposes an - :ref:`application programming interface<reference>`, or API in short. The API - lets developers use the functionality of PROJ in their own software without having - to implement similar functionality themselves. - - PROJ started purely as a cartography application letting users convert geodetic - coordinates into projected coordinates using a number of different cartographic - projections. Over the years, as the need has become apparent, support for datum - shifts has slowly worked its way into PROJ as well. Today PROJ supports more - than a hundred different map projections and can transform coordinates between - datums using all but the most obscure geodetic techniques. + .. include:: about_core.rst You can download the source code for PROJ on the :ref:`download section<download>` and find links to prepackaged executables in the diff --git a/docs/source/install.rst b/docs/source/install.rst index d3c2fab6..fa13046b 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -42,8 +42,8 @@ files is available on `DockerHub`_. Get the package with:: docker pull osgeo/proj -.. _`Docker`: https://docker.org -.. _`DockerHub`: https://hub.docker.com/r/osgeo/proj.4/ +.. _`Docker`: https://www.docker.com/ +.. _`DockerHub`: https://hub.docker.com/r/osgeo/proj/ Windows -------------------------------------------------------------------------------- @@ -94,6 +94,13 @@ On Debian and similar systems (e.g. Ubuntu) the APT package manager is used:: sudo apt-get install proj-bin +Fedora +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +On Fedora the dnf package manager is used:: + + sudo dnf install proj + Red Hat ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/docs/source/news.rst b/docs/source/news.rst index 2a6e8e47..17e573a7 100644 --- a/docs/source/news.rst +++ b/docs/source/news.rst @@ -3,6 +3,77 @@ News ############################################################################### +6.2.1 Release Notes +++++++++++++++++++++++++++++++++++++++++ +*November 1st 2019* + +Updates +------- + +* Update the EPSG database to version 9.8.2 + +Bug fixes +---------- + +* Fixed erroneous spelling of "Potsdam" (`#1573 <https://github.com/OSGeo/PROJ/issues/1573>`_) + +* Calculate y-coordinate correctly in :ref:`bertin1953` in all cases (`#1579 <https://github.com/OSGeo/PROJ/issues/1579>`_) + +* :c:func:`proj_create_crs_to_crs_from_pj()`: make the PJ* arguments const PJ* (`#1583 <https://github.com/OSGeo/PROJ/issues/1583>`_) + +* :c:func:`PROJStringParser::createFromPROJString()`: avoid potential infinite + recursion (`#1574 <https://github.com/OSGeo/PROJ/issues/1574>`_) + +* Avoid core dump when setting ``ctx==NULL`` in functions + :c:func:`proj_coordoperation_is_instantiable` and + :c:func:`proj_coordoperation_has_ballpark_transformation` (`#1590 <https://github.com/OSGeo/PROJ/issues/1590>`_) + +* :c:func:`createOperations()`: fix conversion from/to PROJ.4 CRS strings with + non-ISO-kosher options and ``+towgs84``/``+nadgrids`` (`#1602 <https://github.com/OSGeo/PROJ/issues/1602>`_) + +* :c:func:`proj_trans_generic()`: properly set coordinate time to ``HUGE_VAL`` + when no value is passed to the function (`#1604 <https://github.com/OSGeo/PROJ/issues/1604>`_) + +* Fix support for ``+proj=ob_tran +o_proj=lonlat/latlong/latlon`` instead of only + only allowing ``+o_proj=longlat`` (`#1601 <https://github.com/OSGeo/PROJ/issues/1601>`_) + +* Improve backwards compatibility of vertical transforms (`#1613 <https://github.com/OSGeo/PROJ/issues/1613>`_) + +* Improve emulation of deprecated ``+init`` style initialization (`#1614 <https://github.com/OSGeo/PROJ/issues/1614>`_) + +* :program:`cs2cs`: autopromote CRS to 3D when there's a mix of 2D and 3D (`#1563 <https://github.com/OSGeo/PROJ/issues/1563>`_) + +* Avoid divisions by zero in odd situations (`#1620 <https://github.com/OSGeo/PROJ/issues/1620>`_) + +* Avoid compile error on Solaris (`#1639 <https://github.com/OSGeo/PROJ/issues/1639>`_) + +* :c:func:`proj_create_crs_to_crs()`: fix when there are only transformations with + ballpark steps (`#1643 <https://github.com/OSGeo/PROJ/issues/1643>`_) + +* PROJ string CRS ingester: recognize more unit-less parameters, and general + handling of ``+key=string_value`` parameters (`#1645 <https://github.com/OSGeo/PROJ/issues/1645>`_) + +* Only call pkg-config in configure when necessary (`#1652 <https://github.com/OSGeo/PROJ/issues/1652>`_) + +* :ref:`aeqd`: for spherical forward path, go to higher precision ellipsoidal + case when the point coordinates are super close to the origin (`#1654 <https://github.com/OSGeo/PROJ/issues/1654>`_) + +* :c:func:`proj_create_crs_to_crs()`: remove elimination of Ballpark operations + that caused transformation failures in some cases (`#1665 <https://github.com/OSGeo/PROJ/issues/1665>`_) + +* :c:func:`createOperations()`: allow transforming from a compoundCRS of a bound + verticalCRS to a 2D CRS (`#1667 <https://github.com/OSGeo/PROJ/issues/1667>`_) + +* Avoid segfaults in case of out-of-memory situations (`#1679 <https://github.com/OSGeo/PROJ/issues/1679>`_) + +* :c:func:`createOperations()`: fix double vertical unit conversion from CompoundCRS + to other CRS when the horizontal part of the projected CRS uses non-metre + unit (#1683)(`#1683 <https://github.com/OSGeo/PROJ/issues/1683>`_) + +* :c:func:`importFromWkt()`: fix axis orientation for non-standard ESRI WKT (`#1690 <https://github.com/OSGeo/PROJ/issues/1690>`_) + + + 6.2.0 Release Notes ++++++++++++++++++++++++++++++++++++++++ *September 1st 2019* @@ -10,7 +81,7 @@ News Updates ------- - * Introduced PROJJSON, a JSON encoding of WKT2 (`#1547 <https://github.com/OSGeo/PROJ/issues/15475>`_) + * Introduced :ref:`PROJJSON`, a JSON encoding of WKT2 (`#1547 <https://github.com/OSGeo/PROJ/issues/1547>`_) * Support CRS instantiation of OGC URN's (`#1505 <https://github.com/OSGeo/PROJ/issues/1505>`_) * Expose scope and remarks of database objects (`#1537 <https://github.com/OSGeo/PROJ/issues/1537>`_) diff --git a/docs/source/operations/projections/ob_tran.rst b/docs/source/operations/projections/ob_tran.rst index 378f1333..3a23259d 100644 --- a/docs/source/operations/projections/ob_tran.rst +++ b/docs/source/operations/projections/ob_tran.rst @@ -19,9 +19,10 @@ oblique projection by means of the General Oblique Transformation. The user performs the oblique transformation by selecting the oblique projection ``+proj=ob_tran``, specifying the translation factors, :option:`+o_lat_p`, and :option:`+o_lon_p`, and the projection to be used, :option:`+o_proj`. In the -example of the Fairgrieve projection the latitude and longitude of the pole of -the new coordinates, :math:`\alpha` and :math:`\beta` respectively, are to be placed -at 45°N and 90°W and use the :ref:`moll` projection. Because the central meridian +example of the Fairgrieve projection, the latitude and longitude of the North pole +of the unrotated geographic CRS, :math:`\alpha` and :math:`\beta` respectively, +expressed in the rotated geographic CRS, are to be placed +at 45°N and 90°W and the :ref:`moll` projection is used. Because the central meridian of the translated coordinates will follow the :math:`\beta` meridian it is necessary to translate the translated system so that the Greenwich meridian will pass through the center of the projection by offsetting the central meridian. @@ -50,11 +51,11 @@ New pole .. option:: +o_lat_p=<latitude> - Latitude of new pole for oblique projection. + Latitude of the North pole of the unrotated source CRS, expressed in the rotated geographic CRS. .. option:: +o_lon_p=<longitude> - Longitude of new pole for oblique projection. + Longitude of the North pole of the unrotated source CRS, expressed in the rotated geographic CRS. Rotate about point ................................................................................ diff --git a/docs/source/usage/index.rst b/docs/source/usage/index.rst index 823e8fe7..c31c6dce 100644 --- a/docs/source/usage/index.rst +++ b/docs/source/usage/index.rst @@ -17,3 +17,5 @@ command line applications or the C API that is a part of the software package. transformation environmentvars differences + projjson + diff --git a/docs/source/usage/projjson.rst b/docs/source/usage/projjson.rst new file mode 100644 index 00000000..79e87c15 --- /dev/null +++ b/docs/source/usage/projjson.rst @@ -0,0 +1,261 @@ +.. _projjson: + +================================================================================ +PROJJSON +================================================================================ + +PROJJSON is a JSON encoding of +`WKT2:2019 / ISO-19162:2019 <http://docs.opengeospatial.org/is/18-010r7/18-010r7.html>`_, +which itself implements the model of +`OGC Topic 2: Referencing by coordinates <http://docs.opengeospatial.org/as/18-005r4/18-005r4.html>`_. +Apart from the difference of encodings, the semantics is intended to be exactly +the same as WKT2:2019. + +PROJJSON is available as input and output of PROJ since PROJ 6.2. + +The current version is 0.1. + +Schema +------ + +A JSON schema of its grammar is available at +https://proj.org/schemas/v0.1/projjson.schema.json + +Content +------- + +The high level objects are: + +* Coordinate Reference Systems (CRS): + + - Common ones: + + + ``GeographicCRS`` + + ``GeodeticCRS`` + + ``ProjectedCRS`` + + ``CompoundCRS`` + + ``BoundCRS`` + + - More esoteric ones: + + + ``VerticalCRS`` + + ``EngineeringCRS`` + + ``TemporalCRS`` + + ``ParametricCRS`` + + ``DerivedGeographicCRS`` + + ``DerivedGeodeticCRS`` + + ``DerivedProjectedCRS`` + + ``DerivedVerticalCRS`` + + ``DerivedEngineeringCRS`` + + ``DerivedTemporalCRS`` + + ``DerivedParametricCRS`` + +* Coordinate operations: + + - ``Transformation`` + - ``Conversion`` + - ``ConcatenatedOperation`` + +* Others: + + - ``PrimeMeridian`` + - ``Ellipsoid`` + - ``Datum`` + - ``DatumEnsemble`` + +Examples +-------- + +GeographicCRS ++++++++++++++ + +The following invokation + +:: + + projinfo EPSG:4326 -o PROJJSON -q + +will output: + +.. code-block:: json + + { + "$schema": "https://proj.org/schemas/v0.1/projjson.schema.json", + "type": "GeographicCRS", + "name": "WGS 84", + "datum": { + "type": "GeodeticReferenceFrame", + "name": "World Geodetic System 1984", + "ellipsoid": { + "name": "WGS 84", + "semi_major_axis": 6378137, + "inverse_flattening": 298.257223563 + } + }, + "coordinate_system": { + "subtype": "ellipsoidal", + "axis": [ + { + "name": "Geodetic latitude", + "abbreviation": "Lat", + "direction": "north", + "unit": "degree" + }, + { + "name": "Geodetic longitude", + "abbreviation": "Lon", + "direction": "east", + "unit": "degree" + } + ] + }, + "area": "World", + "bbox": { + "south_latitude": -90, + "west_longitude": -180, + "north_latitude": 90, + "east_longitude": 180 + }, + "id": { + "authority": "EPSG", + "code": 4326 + } + } + + +ProjectedCRS +++++++++++++ + +The following invokation + +:: + + projinfo EPSG:32631 -o PROJJSON -q + +will output: + +.. code-block:: json + + { + "$schema": "https://proj.org/schemas/v0.1/projjson.schema.json", + "type": "ProjectedCRS", + "name": "WGS 84 / UTM zone 31N", + "base_crs": { + "name": "WGS 84", + "datum": { + "type": "GeodeticReferenceFrame", + "name": "World Geodetic System 1984", + "ellipsoid": { + "name": "WGS 84", + "semi_major_axis": 6378137, + "inverse_flattening": 298.257223563 + } + }, + "coordinate_system": { + "subtype": "ellipsoidal", + "axis": [ + { + "name": "Geodetic latitude", + "abbreviation": "Lat", + "direction": "north", + "unit": "degree" + }, + { + "name": "Geodetic longitude", + "abbreviation": "Lon", + "direction": "east", + "unit": "degree" + } + ] + }, + "id": { + "authority": "EPSG", + "code": 4326 + } + }, + "conversion": { + "name": "UTM zone 31N", + "method": { + "name": "Transverse Mercator", + "id": { + "authority": "EPSG", + "code": 9807 + } + }, + "parameters": [ + { + "name": "Latitude of natural origin", + "value": 0, + "unit": "degree", + "id": { + "authority": "EPSG", + "code": 8801 + } + }, + { + "name": "Longitude of natural origin", + "value": 3, + "unit": "degree", + "id": { + "authority": "EPSG", + "code": 8802 + } + }, + { + "name": "Scale factor at natural origin", + "value": 0.9996, + "unit": "unity", + "id": { + "authority": "EPSG", + "code": 8805 + } + }, + { + "name": "False easting", + "value": 500000, + "unit": "metre", + "id": { + "authority": "EPSG", + "code": 8806 + } + }, + { + "name": "False northing", + "value": 0, + "unit": "metre", + "id": { + "authority": "EPSG", + "code": 8807 + } + } + ] + }, + "coordinate_system": { + "subtype": "Cartesian", + "axis": [ + { + "name": "Easting", + "abbreviation": "E", + "direction": "east", + "unit": "metre" + }, + { + "name": "Northing", + "abbreviation": "N", + "direction": "north", + "unit": "metre" + } + ] + }, + "area": "World - N hemisphere - 0°E to 6°E - by country", + "bbox": { + "south_latitude": 0, + "west_longitude": 0, + "north_latitude": 84, + "east_longitude": 6 + }, + "id": { + "authority": "EPSG", + "code": 32631 + } + } diff --git a/docs/source/usage/transformation.rst b/docs/source/usage/transformation.rst index 861e1b4b..a11992cf 100644 --- a/docs/source/usage/transformation.rst +++ b/docs/source/usage/transformation.rst @@ -12,7 +12,8 @@ large scale cartographic projections as well as coordinate transformation at a geodetic high precision level. This chapter delves into the details of how geodetic transformations of varying complexity can be performed. -In PROJ, two frameworks for geodetic transformations exists, the *cs2cs* +In PROJ, two frameworks for geodetic transformations exists, the +*PROJ 4.x/5.x* / :program:`cs2cs` / :c:func:`pj_transform` framework and the *transformation pipelines* framework. The first is the original, and limited, framework for doing geodetic transforms in PROJ The latter is a newer addition that aims to be a more complete transformation framework. Both are @@ -133,7 +134,7 @@ coordinate timestamps back to GPS weeks. step proj=unitconvert t_in=decimalyear t_out=gps_week -cs2cs paradigm +PROJ 4.x/5.x paradigm +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. _cs2cs_specific_options: @@ -148,9 +149,19 @@ cs2cs paradigm +vto_meter Vertical conversion to meters ============ ============================================================== -The *cs2cs* framework delivers a subset of the geodetic transformations available +.. warning:: + This section documents the behaviour of PROJ 4.x and 5.x. In PROJ 6.x, + :program:`cs2cs` has been reworked to use :c:func:`proj_create_crs_to_crs` internally, + with *late binding* capabilities, and thus is no longer constrained to using + WGS84 as a pivot (also called as *early binding* method). + When :program:`cs2cs` of PROJ 6 is used with PROJ.4 expanded strings to describe the CRS, + including ``+towgs84``, ``+nadgrids`` and ``+geoidgrids``, it will generally give + the same results as earlier PROJ versions. When used with AUTHORITY:CODE + CRS descriptions, it may return different results. + +The *cs2cs* framework in PROJ 4 and 5 delivers a subset of the geodetic transformations available with the *pipeline* framework. Coordinate transformations done in this framework -are transformed in a two-step process with WGS84 as a pivot datum That is, the +were transformed in a two-step process with WGS84 as a pivot datum. That is, the input coordinates are transformed to WGS84 geodetic coordinates and then transformed from WGS84 coordinates to the specified output coordinate reference system, by utilizing either the Helmert transform, datum shift grids or a combination of both. @@ -173,7 +184,7 @@ Both grid correction methods allow inclusion of more than one grid in the same transformation In contrast to the *transformation pipeline* framework, transformations with the -*cs2cs* framework are expressed as two separate proj-strings. One proj-string *to* +*cs2cs* framework in PROJ 4 and 5 were expressed as two separate proj-strings. One proj-string *to* WGS84 and one *from* WGS84. Together they form the mapping from the source coordinate reference system to the destination coordinate reference system. When used with the ``cs2cs`` the source and destination CRS's are separated by the @@ -189,6 +200,21 @@ to WGS84 with the ``+towgs84`` parameter. 20 35 20d0'5.467"E 35d0'9.575"N 0.000 +With PROJ 6, you can simply use the following: + +.. note:: With PROJ 6, the order of coordinates for EPSG geographic coordinate + reference systems is latitude first, longitude second. + +:: + + cs2cs "GGRS87" "WGS 84" + 35 20 + 35d0'9.575"N 20d0'5.467"E 0.000 + + cs2cs EPSG:4121 EPSG:4326 + 35 20 + 35d0'9.575"N 20d0'5.467"E 0.000 + The EPSG database provides this example for transforming from WGS72 to WGS84 using an approximated 7 parameter transformation. @@ -199,6 +225,19 @@ using an approximated 7 parameter transformation. 4 55 4d0'0.554"E 55d0'0.09"N 0.000 +With PROJ 6, you can simply use the following (note the reversed order for +latitude and longitude) + +:: + + cs2cs "WGS 72" "WGS 84" + 55 4 + 55d0'0.09"N 4d0'0.554"E 0.000 + + cs2cs EPSG:4322 EPSG:4326 + 55 4 + 55d0'0.09"N 4d0'0.554"E 0.000 + Grid Based Datum Adjustments +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -266,8 +305,8 @@ fallback to using the ``ntv1_can.dat`` file. The null Grid ................................................................................ -A special ``null`` grid shift file is shift with releases after 4.4.6 (not -inclusive). This file provides a zero shift for the whole world. It may be +A special ``null`` grid shift file is distributed with PROJ. +This file provides a zero shift for the whole world. It may be listed at the end of a nadgrids file list if you want a zero shift to be applied to points outside the valid region of all the other grids. Normally if no grid is found that contains the point to be transformed an error will occur. @@ -301,13 +340,7 @@ Caveats Careful selection of files and file order is necessary. In some cases border spanning datasets may need to be pre-segmented into Canadian and American points so they can be properly grid shifted -* There are additional grids for shifting between NAD83 and various HPGN - versions of the NAD83 datum. Use of these haven't been tried recently so - you may encounter problems. The FL.lla, WO.lla, MD.lla, TN.lla and WI.lla - are examples of high precision grid shifts. Take care! * Additional detail on the grid shift being applied can be found by setting the PROJ_DEBUG environment variable to a value. This will result in output to stderr on what grid is used to shift points, the bounds of the various grids loaded and so forth -* The *cs2cs* framework always assumes that grids contain a shift **to** NAD83 (essentially - WGS84). Other types of grids can be used with the *pipeline* framework. diff --git a/include/proj/crs.hpp b/include/proj/crs.hpp index 18ac4d5d..a39d8571 100644 --- a/include/proj/crs.hpp +++ b/include/proj/crs.hpp @@ -507,6 +507,9 @@ class PROJ_GCC_DLL DerivedCRS : virtual public SingleCRS { PROJ_PRIVATE : //! @cond Doxygen_Suppress + + // Use this method with extreme care ! It should never be used + // to recreate a new Derived/ProjectedCRS ! PROJ_INTERNAL const operation::ConversionNNPtr & derivingConversionRef() PROJ_PURE_DECL; diff --git a/man/man1/cct.1 b/man/man1/cct.1 index 759a3b08..be5c22fb 100644 --- a/man/man1/cct.1 +++ b/man/man1/cct.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "CCT" "1" "Aug 26, 2019" "6.2.0" "PROJ" +.TH "CCT" "1" "Nov 1, 2019" "6.2.1" "PROJ" .SH NAME cct \- Coordinate Conversion and Transformation . diff --git a/man/man1/cs2cs.1 b/man/man1/cs2cs.1 index ec4de873..c775e075 100644 --- a/man/man1/cs2cs.1 +++ b/man/man1/cs2cs.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "CS2CS" "1" "Aug 26, 2019" "6.2.0" "PROJ" +.TH "CS2CS" "1" "Nov 01, 2019" "6.2.1" "PROJ" .SH NAME cs2cs \- Cartographic coordinate system filter . diff --git a/man/man1/geod.1 b/man/man1/geod.1 index f4c356ac..eda8a29b 100644 --- a/man/man1/geod.1 +++ b/man/man1/geod.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "GEOD" "1" "Aug 26, 2019" "6.2.0" "PROJ" +.TH "GEOD" "1" "Nov 1, 2019" "6.2.1" "PROJ" .SH NAME geod \- Geodesic computations . diff --git a/man/man1/gie.1 b/man/man1/gie.1 index 54db5362..7c4e45af 100644 --- a/man/man1/gie.1 +++ b/man/man1/gie.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "GIE" "1" "Aug 26, 2019" "6.2.0" "PROJ" +.TH "GIE" "1" "Nov 1, 2019" "6.2.1" "PROJ" .SH NAME gie \- The Geospatial Integrity Investigation Environment . diff --git a/man/man1/proj.1 b/man/man1/proj.1 index 8bd927ca..f787e82f 100644 --- a/man/man1/proj.1 +++ b/man/man1/proj.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "PROJ" "1" "Aug 26, 2019" "6.2.0" "PROJ" +.TH "PROJ" "1" "Nov 1, 2019" "6.2.1" "PROJ" .SH NAME proj \- Cartographic projection filter . diff --git a/man/man1/projinfo.1 b/man/man1/projinfo.1 index 506663b5..a7d89bcd 100644 --- a/man/man1/projinfo.1 +++ b/man/man1/projinfo.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "PROJINFO" "1" "Aug 26, 2019" "6.2.0" "PROJ" +.TH "PROJINFO" "1" "Nov 1, 2019" "6.2.1" "PROJ" .SH NAME projinfo \- Geodetic object and coordinate operation queries . diff --git a/man/man3/geodesic.3 b/man/man3/geodesic.3 index c2d3d9df..4abf93be 100644 --- a/man/man3/geodesic.3 +++ b/man/man3/geodesic.3 @@ -1,6 +1,6 @@ .\" @(#)geodesic.3 .\" -.TH GEODESIC 3 "2019/09/01 Rel. 6.2.0" +.TH GEODESIC 3 "2019/11/01 Rel. 6.2.1" .ad b .hy 1 .SH NAME diff --git a/schemas/v0.2/projjson.schema.json b/schemas/v0.2/projjson.schema.json new file mode 100644 index 00000000..0a4015ce --- /dev/null +++ b/schemas/v0.2/projjson.schema.json @@ -0,0 +1,982 @@ +{ + "$id": "https://proj.org/schemas/v0.2/projjson.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Schema for PROJJSON", + "$comment": "This file exists both in data/ and in schemas/vXXX/. Keep both in sync. And if changing the value of $id, change PROJJSON_CURRENT_VERSION accordingly in io.cpp", + + "oneOf": [ + { "$ref": "#/definitions/crs" }, + { "$ref": "#/definitions/datum" }, + { "$ref": "#/definitions/datum_ensemble" }, + { "$ref": "#/definitions/ellipsoid" }, + { "$ref": "#/definitions/prime_meridian" }, + { "$ref": "#/definitions/single_operation" }, + { "$ref": "#/definitions/concatenated_operation" } + ], + + "definitions": { + + "abridged_transformation": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["AbridgedTransformation"] }, + "name": { "type": "string" }, + "method": { "$ref": "#/definitions/method" }, + "parameters": { + "type": "array", + "items": { "$ref": "#/definitions/parameter_value" } + }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name", "method", "parameters" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + }, + + "axis": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["Axis"] }, + "name": { "type": "string" }, + "abbreviation": { "type": "string" }, + "direction": { "type": "string", + "enum": [ "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", + "past", + "unspecified" ] }, + "unit": { "$ref": "#/definitions/unit" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name", "abbreviation", "direction" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + }, + + "bbox": { + "type": "object", + "properties": { + "east_longitude": { "type": "number" }, + "west_longitude": { "type": "number" }, + "south_latitude": { "type": "number" }, + "north_latitude": { "type": "number" } + }, + "required" : [ "east_longitude", "west_longitude", + "south_latitude", "north_latitude" ], + "additionalProperties": false + }, + + "bound_crs": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["BoundCRS"] }, + "source_crs": { "$ref": "#/definitions/crs" }, + "target_crs": { "$ref": "#/definitions/crs" }, + "transformation": { "$ref": "#/definitions/abridged_transformation" } + }, + "required" : [ "source_crs", "target_crs", "transformation" ], + "additionalProperties": false + }, + + "compound_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["CompoundCRS"] }, + "name": { "type": "string" }, + "components": { + "type": "array", + "items": { "$ref": "#/definitions/crs" } + }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "components" ], + "additionalProperties": false + }, + + "concatenated_operation": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["ConcatenatedOperation"] }, + "name": { "type": "string" }, + "source_crs": { "$ref": "#/definitions/crs" }, + "target_crs": { "$ref": "#/definitions/crs" }, + "steps": { + "type": "array", + "items": { "$ref": "#/definitions/single_operation" } + }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "source_crs", "target_crs", "steps" ], + "additionalProperties": false + }, + + "conversion": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["Conversion"] }, + "name": { "type": "string" }, + "method": { "$ref": "#/definitions/method" }, + "parameters": { + "type": "array", + "items": { "$ref": "#/definitions/parameter_value" } + }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name", "method" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + }, + + "coordinate_system": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["CoordinateSystem"] }, + "name": { "type": "string" }, + "subtype": { "type": "string", + "enum": ["Cartesian", + "spherical", + "ellipsoidal", + "vertical", + "ordinal", + "parametric", + "TemporalDateTime", + "TemporalCount", + "TemporalMeasure"] }, + "axis": { + "type": "array", + "items": { "$ref": "#/definitions/axis" } + }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "subtype", "axis" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + }, + + "crs": { + "oneOf": [ + { "$ref": "#/definitions/bound_crs" }, + { "$ref": "#/definitions/compound_crs" }, + { "$ref": "#/definitions/derived_engineering_crs" }, + { "$ref": "#/definitions/derived_geodetic_crs" }, + { "$ref": "#/definitions/derived_parametric_crs" }, + { "$ref": "#/definitions/derived_projected_crs" }, + { "$ref": "#/definitions/derived_temporal_crs" }, + { "$ref": "#/definitions/derived_vertical_crs" }, + { "$ref": "#/definitions/engineering_crs" }, + { "$ref": "#/definitions/geodetic_crs" }, + { "$ref": "#/definitions/parametric_crs" }, + { "$ref": "#/definitions/projected_crs" }, + { "$ref": "#/definitions/temporal_crs" }, + { "$ref": "#/definitions/vertical_crs" } + ] + }, + + "datum": { + "oneOf": [ + { "$ref": "#/definitions/geodetic_reference_frame" }, + { "$ref": "#/definitions/vertical_reference_frame" }, + { "$ref": "#/definitions/dynamic_geodetic_reference_frame" }, + { "$ref": "#/definitions/dynamic_vertical_reference_frame" }, + { "$ref": "#/definitions/temporal_datum" }, + { "$ref": "#/definitions/parametric_datum" }, + { "$ref": "#/definitions/engineering_datum" } + ] + }, + + "datum_ensemble": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["DatumEnsemble"] }, + "name": { "type": "string" }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + } + }, + "ellipsoid": { "$ref": "#/definitions/ellipsoid" }, + "accuracy": { "type": "string" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name", "members", "accuracy" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + }, + + "derived_engineering_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", + "enum": ["DerivedEngineeringCRS"] }, + "name": { "type": "string" }, + "base_crs": { "$ref": "#/definitions/engineering_crs" }, + "conversion": { "$ref": "#/definitions/conversion" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "base_crs", "conversion", "coordinate_system" ], + "additionalProperties": false + }, + + "derived_geodetic_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", + "enum": ["DerivedGeodeticCRS", + "DerivedGeographicCRS"] }, + "name": { "type": "string" }, + "base_crs": { "$ref": "#/definitions/geodetic_crs" }, + "conversion": { "$ref": "#/definitions/conversion" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "base_crs", "conversion", "coordinate_system" ], + "additionalProperties": false + }, + + "derived_parametric_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", + "enum": ["DerivedParametricCRS"] }, + "name": { "type": "string" }, + "base_crs": { "$ref": "#/definitions/parametric_crs" }, + "conversion": { "$ref": "#/definitions/conversion" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "base_crs", "conversion", "coordinate_system" ], + "additionalProperties": false + }, + + "derived_projected_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", + "enum": ["DerivedProjectedCRS"] }, + "name": { "type": "string" }, + "base_crs": { "$ref": "#/definitions/projected_crs" }, + "conversion": { "$ref": "#/definitions/conversion" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "base_crs", "conversion", "coordinate_system" ], + "additionalProperties": false + }, + + "derived_temporal_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", + "enum": ["DerivedTemporalCRS"] }, + "name": { "type": "string" }, + "base_crs": { "$ref": "#/definitions/temporal_crs" }, + "conversion": { "$ref": "#/definitions/conversion" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "base_crs", "conversion", "coordinate_system" ], + "additionalProperties": false + }, + + "derived_vertical_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", + "enum": ["DerivedVerticalCRS"] }, + "name": { "type": "string" }, + "base_crs": { "$ref": "#/definitions/vertical_crs" }, + "conversion": { "$ref": "#/definitions/conversion" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "base_crs", "conversion", "coordinate_system" ], + "additionalProperties": false + }, + + "dynamic_geodetic_reference_frame": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/geodetic_reference_frame" }], + "properties": { + "type": { "type": "string", "enum": ["DynamicGeodeticReferenceFrame"] }, + "name": {}, + "anchor": {}, + "ellipsoid": {}, + "prime_meridian": {}, + "frame_reference_epoch": { "type": "number" }, + "deformation_model": { "type": "string" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "ellipsoid", "frame_reference_epoch" ], + "additionalProperties": false + }, + + "dynamic_vertical_reference_frame": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/vertical_reference_frame" }], + "properties": { + "type": { "type": "string", "enum": ["DynamicVerticalReferenceFrame"] }, + "name": {}, + "anchor": {}, + "frame_reference_epoch": { "type": "number" }, + "deformation_model": { "type": "string" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "frame_reference_epoch" ], + "additionalProperties": false + }, + + "ellipsoid": { + "type": "object", + "oneOf":[ + { + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["Ellipsoid"] }, + "name": { "type": "string" }, + "semi_major_axis": { "$ref": "#/definitions/value_in_metre_or_value_and_unit" }, + "semi_minor_axis": { "$ref": "#/definitions/value_in_metre_or_value_and_unit" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name", "semi_major_axis", "semi_minor_axis" ], + "additionalProperties": false + }, + { + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["Ellipsoid"] }, + "name": { "type": "string" }, + "semi_major_axis": { "$ref": "#/definitions/value_in_metre_or_value_and_unit" }, + "inverse_flattening": { "type": "number" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name", "semi_major_axis", "inverse_flattening" ], + "additionalProperties": false + }, + { + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["Ellipsoid"] }, + "name": { "type": "string" }, + "radius": { "$ref": "#/definitions/value_in_metre_or_value_and_unit" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name", "radius" ], + "additionalProperties": false + } + ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ] + }, + + "engineering_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["EngineeringCRS"] }, + "name": { "type": "string" }, + "datum": { "$ref": "#/definitions/engineering_datum" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "datum" ], + "additionalProperties": false + }, + + "engineering_datum": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["EngineeringDatum"] }, + "name": { "type": "string" }, + "anchor": { "type": "string" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name" ], + "additionalProperties": false + }, + + "geodetic_crs": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["GeodeticCRS", "GeographicCRS"] }, + "name": { "type": "string" }, + "datum": { + "oneOf": [ + { "$ref": "#/definitions/geodetic_reference_frame" }, + { "$ref": "#/definitions/dynamic_geodetic_reference_frame" } + ] + }, + "datum_ensemble": { "$ref": "#/definitions/datum_ensemble" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name" ], + "description": "One and only one of datum and datum_ensemble must be provided", + "allOf": [ + { "$ref": "#/definitions/object_usage" }, + { "$ref": "#/definitions/one_and_only_one_of_datum_or_datum_ensemble" } + ], + "additionalProperties": false + }, + + "geodetic_reference_frame": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["GeodeticReferenceFrame"] }, + "name": { "type": "string" }, + "anchor": { "type": "string" }, + "ellipsoid": { "$ref": "#/definitions/ellipsoid" }, + "prime_meridian": { "$ref": "#/definitions/prime_meridian" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "ellipsoid" ], + "additionalProperties": false + }, + + "id": { + "type": "object", + "properties": { + "authority": { "type": "string" }, + "code": { + "oneOf": [ { "type": "string" }, { "type": "integer" } ] + } + }, + "required" : [ "authority", "code" ], + "additionalProperties": false + }, + + "ids": { + "type": "array", + "items": { "$ref": "#/definitions/id" } + }, + + "method": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["OperationMethod"]}, + "name": { "type": "string" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + }, + + "id_ids_mutually_exclusive": { + "not": { + "type": "object", + "required": [ "id", "ids" ] + } + }, + + "one_and_only_one_of_datum_or_datum_ensemble": { + "allOf": [ + { + "not": { + "type": "object", + "required": [ "datum", "datum_ensemble" ] + } + }, + { + "oneOf": [ + { "type": "object", "required": ["datum"] }, + { "type": "object", "required": ["datum_ensemble"] } + ] + } + ] + }, + + "object_usage": { + "anyOf": [ + { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "scope": { "type": "string" }, + "area": { "type": "string" }, + "bbox": { "$ref": "#/definitions/bbox" }, + "remarks": { "type": "string" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ] + }, + { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "usages": { "$ref": "#/definitions/usages" }, + "remarks": { "type": "string" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ] + } + ] + }, + + "parameter_value": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["ParameterValue"] }, + "name": { "type": "string" }, + "value": { + "oneOf": [ + { "type": "string" }, + { "type": "number" } + ] + }, + "unit": { "$ref": "#/definitions/unit" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name", "value" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + }, + + "parametric_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["ParametricCRS"] }, + "name": { "type": "string" }, + "datum": { "$ref": "#/definitions/parametric_datum" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "datum" ], + "additionalProperties": false + }, + + "parametric_datum": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["ParametricDatum"] }, + "name": { "type": "string" }, + "anchor": { "type": "string" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name" ], + "additionalProperties": false + }, + + "prime_meridian": { + "type": "object", + "properties": { + "$schema" : { "type": "string" }, + "type": { "type": "string", "enum": ["PrimeMeridian"] }, + "name": { "type": "string" }, + "longitude": { "$ref": "#/definitions/value_and_unit" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "name" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + }, + + "single_operation": { + "oneOf": [ + { "$ref": "#/definitions/conversion" }, + { "$ref": "#/definitions/transformation" } + ] + }, + + "projected_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", + "enum": ["ProjectedCRS"] }, + "name": { "type": "string" }, + "base_crs": { "$ref": "#/definitions/geodetic_crs" }, + "conversion": { "$ref": "#/definitions/conversion" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "base_crs", "conversion", "coordinate_system" ], + "additionalProperties": false + }, + + "temporal_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["TemporalCRS"] }, + "name": { "type": "string" }, + "datum": { "$ref": "#/definitions/temporal_datum" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "datum" ], + "additionalProperties": false + }, + + "temporal_datum": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["TemporalDatum"] }, + "name": { "type": "string" }, + "calendar": { "type": "string" }, + "time_origin": { "type": "string" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "calendar" ], + "additionalProperties": false + }, + + "transformation": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["Transformation"] }, + "name": { "type": "string" }, + "source_crs": { "$ref": "#/definitions/crs" }, + "target_crs": { "$ref": "#/definitions/crs" }, + "interpolation_crs": { "$ref": "#/definitions/crs" }, + "method": { "$ref": "#/definitions/method" }, + "parameters": { + "type": "array", + "items": { "$ref": "#/definitions/parameter_value" } + }, + "accuracy": { "type": "string" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name", "source_crs", "target_crs", "method", "parameters" ], + "additionalProperties": false + }, + + "unit": { + "oneOf": [ + { + "type": "string", + "enum": ["metre", "degree", "unity"] + }, + { + "type": "object", + "properties": { + "type": { "type": "string", + "enum": ["LinearUnit", "AngularUnit", "ScaleUnit", + "TimeUnit", "ParametricUnit", "Unit"] }, + "name": { "type": "string" }, + "conversion_factor": { "type": "number" }, + "id": { "$ref": "#/definitions/id" }, + "ids": { "$ref": "#/definitions/ids" } + }, + "required" : [ "type", "name" ], + "allOf": [ + { "$ref": "#/definitions/id_ids_mutually_exclusive" } + ], + "additionalProperties": false + } + ] + }, + + "usages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "scope": { "type": "string" }, + "area": { "type": "string" }, + "bbox": { "$ref": "#/definitions/bbox" } + }, + "additionalProperties": false + } + }, + + "value_and_unit": { + "type": "object", + "properties": { + "value": { "type": "number" }, + "unit": { "$ref": "#/definitions/unit" } + }, + "required" : [ "value", "unit" ], + "additionalProperties": false + }, + + "value_in_metre_or_value_and_unit": { + "oneOf": [ + { "type": "number" }, + { "$ref": "#/definitions/value_and_unit" } + ] + }, + + "vertical_crs": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["VerticalCRS"] }, + "name": { "type": "string" }, + "datum": { + "oneOf": [ + { "$ref": "#/definitions/vertical_reference_frame" }, + { "$ref": "#/definitions/dynamic_vertical_reference_frame" } + ] + }, + "datum_ensemble": { "$ref": "#/definitions/datum_ensemble" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "geoid_model": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "interpolation_crs": { "$ref": "#/definitions/crs" }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name" ], + "additionalProperties": false + }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name"], + "description": "One and only one of datum and datum_ensemble must be provided", + "allOf": [ + { "$ref": "#/definitions/object_usage" }, + { "$ref": "#/definitions/one_and_only_one_of_datum_or_datum_ensemble" } + ], + "additionalProperties": false + }, + + "vertical_reference_frame": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["VerticalReferenceFrame"] }, + "name": { "type": "string" }, + "anchor": { "type": "string" }, + "$schema" : {}, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {}, "ids": {} + }, + "required" : [ "name" ], + "additionalProperties": false + } + + } +} diff --git a/src/Makefile.am b/src/Makefile.am index fe7f2572..0a868412 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,7 +42,7 @@ geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la -libproj_la_LDFLAGS = -no-undefined -version-info 17:0:2 +libproj_la_LDFLAGS = -no-undefined -version-info 17:1:2 libproj_la_LIBADD = @SQLITE3_LIBS@ libproj_la_SOURCES = \ diff --git a/src/ctx.cpp b/src/ctx.cpp index 622a814d..bcb6e1cc 100644 --- a/src/ctx.cpp +++ b/src/ctx.cpp @@ -60,6 +60,14 @@ void pj_set_ctx( projPJ pj, projCtx ctx ) if (pj==nullptr) return; pj->ctx = ctx; + if( pj->is_pipeline ) + { + pj_pipeline_assign_context_to_steps(pj, ctx); + } + for( const auto &alt: pj->alternativeCoordinateOperations ) + { + pj_set_ctx(alt.pj, ctx); + } } /************************************************************************/ diff --git a/src/datum_set.cpp b/src/datum_set.cpp index c1cb4cb9..873d7be5 100644 --- a/src/datum_set.cpp +++ b/src/datum_set.cpp @@ -85,10 +85,22 @@ int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef) entry[ sizeof(entry) - 1 ] = '\0'; curr = curr->next = pj_mkparam(entry); + if (nullptr == curr) + { + pj_ctx_set_errno(ctx, ENOMEM); + return 1; + } } if( pj_datums[i].defn && strlen(pj_datums[i].defn) > 0 ) + { curr = curr->next = pj_mkparam(pj_datums[i].defn); + if (nullptr == curr) + { + pj_ctx_set_errno(ctx, ENOMEM); + return 1; + } + } (void)curr; /* make clang static analyzer happy */ } diff --git a/src/ell_set.cpp b/src/ell_set.cpp index d2930ca4..bb46b3a4 100644 --- a/src/ell_set.cpp +++ b/src/ell_set.cpp @@ -1,5 +1,6 @@ /* set ellipsoid parameters a and es */ +#include <errno.h> #include <math.h> #include <stddef.h> #include <string.h> @@ -156,7 +157,14 @@ static int ellps_ellps (PJ *P) { err = proj_errno_reset (P); paralist* new_params = pj_mkparam (ellps->major); + if (nullptr == new_params) + return proj_errno_set (P, ENOMEM); new_params->next = pj_mkparam (ellps->ell); + if (nullptr == new_params->next) + { + pj_dealloc(new_params); + return proj_errno_set (P, ENOMEM); + } paralist* old_params = P->params; P->params = new_params; diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index 1e5c106a..fb3b7f40 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -498,7 +498,7 @@ template <class T> static PROJ_STRING_LIST to_string_list(T &&set) { * proj_string_list_destroy(). * @param out_grammar_errors Pointer to a PROJ_STRING_LIST object, or NULL. * If provided, *out_grammar_errors will contain a list of errors regarding the - * WKT grammaer. It must be freed with proj_string_list_destroy(). + * WKT grammar. It must be freed with proj_string_list_destroy(). * @return Object that must be unreferenced with proj_destroy(), or NULL in * case of error. */ @@ -522,6 +522,7 @@ PJ *proj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt, if (dbContext) { parser.attachDatabaseContext(NN_NO_CHECK(dbContext)); } + parser.setStrict(false); for (auto iter = options; iter && iter[0]; ++iter) { const char *value; if ((value = getOptionValue(*iter, "STRICT="))) { @@ -536,10 +537,19 @@ PJ *proj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt, auto obj = nn_dynamic_pointer_cast<IdentifiedObject>( parser.createFromWKT(wkt)); + std::vector<std::string> warningsFromParsing; if (out_grammar_errors) { - auto warnings = parser.warningList(); - if (!warnings.empty()) { - *out_grammar_errors = to_string_list(warnings); + auto rawWarnings = parser.warningList(); + std::vector<std::string> grammarWarnings; + for (const auto &msg : rawWarnings) { + if (msg.find("Default it to") != std::string::npos) { + warningsFromParsing.push_back(msg); + } else { + grammarWarnings.push_back(msg); + } + } + if (!grammarWarnings.empty()) { + *out_grammar_errors = to_string_list(grammarWarnings); } } @@ -548,6 +558,8 @@ PJ *proj_create_from_wkt(PJ_CONTEXT *ctx, const char *wkt, if (derivedCRS) { auto warnings = derivedCRS->derivingConversionRef()->validateParameters(); + warnings.insert(warnings.end(), warningsFromParsing.begin(), + warningsFromParsing.end()); if (!warnings.empty()) { *out_warnings = to_string_list(warnings); } @@ -2089,14 +2101,26 @@ PJ *proj_get_target_crs(PJ_CONTEXT *ctx, const PJ *obj) { * The method returns a list of matching reference CRS, and the percentage * (0-100) of confidence in the match. The list is sorted by decreasing * confidence. - * - * 100% means that the name of the reference entry + * <ul> + * <li>100% means that the name of the reference entry * perfectly matches the CRS name, and both are equivalent. In which case a * single result is returned. - * 90% means that CRS are equivalent, but the names are not exactly the same. - * 70% means that CRS are equivalent), but the names do not match at all. - * 25% means that the CRS are not equivalent, but there is some similarity in - * the names. + * Note: in the case of a GeographicCRS whose axis + * order is implicit in the input definition (for example ESRI WKT), then axis + * order is ignored for the purpose of identification. That is the CRS built + * from + * GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]], + * PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] + * will be identified to EPSG:4326, but will not pass a + * isEquivalentTo(EPSG_4326, util::IComparable::Criterion::EQUIVALENT) test, + * but rather isEquivalentTo(EPSG_4326, + * util::IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS) + * </li> + * <li>90% means that CRS are equivalent, but the names are not exactly the same.</li> + * <li>70% means that CRS are equivalent), but the names do not match at all.</li> + * <li>25% means that the CRS are not equivalent, but there is some similarity in + * the names.</li> + * </ul> * Other confidence values may be returned by some specialized implementations. * * This is implemented for GeodeticCRS, ProjectedCRS, VerticalCRS and diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 3ba5a5a2..0eaba883 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -5927,24 +5927,31 @@ void Conversion::_exportToPROJString( if (!param->proj_name) { continue; } - auto value = + const auto value = parameterValueMeasure(param->wkt2_name, param->epsg_code); + double valueConverted = 0; + if (value == nullMeasure) { + // Deal with missing values. In an ideal world, this would + // not happen + if (param->epsg_code == + EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN) { + valueConverted = 1.0; + } + } else if (param->unit_type == + common::UnitOfMeasure::Type::ANGULAR) { + valueConverted = + value.convertToUnit(common::UnitOfMeasure::DEGREE); + } else { + valueConverted = value.getSIValue(); + } + if (mapping->epsg_code == EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP && strcmp(param->proj_name, "lat_1") == 0) { - formatter->addParam( - param->proj_name, - value.convertToUnit(common::UnitOfMeasure::DEGREE)); - formatter->addParam( - "lat_0", - value.convertToUnit(common::UnitOfMeasure::DEGREE)); - } else if (param->unit_type == - common::UnitOfMeasure::Type::ANGULAR) { - formatter->addParam( - param->proj_name, - value.convertToUnit(common::UnitOfMeasure::DEGREE)); + formatter->addParam(param->proj_name, valueConverted); + formatter->addParam("lat_0", valueConverted); } else { - formatter->addParam(param->proj_name, value.getSIValue()); + formatter->addParam(param->proj_name, valueConverted); } } @@ -6506,6 +6513,24 @@ static void getTransformationType(const crs::CRSNNPtr &sourceCRSIn, isGeog2D = nSrcAxisCount == 2 && nTargetAxisCount == 2; isGeog3D = !isGeog2D && nSrcAxisCount >= 2 && nTargetAxisCount >= 2; } + +// --------------------------------------------------------------------------- + +static int +useOperationMethodEPSGCodeIfPresent(const util::PropertyMap &properties, + int nDefaultOperationMethodEPSGCode) { + const auto *operationMethodEPSGCode = + properties.get("OPERATION_METHOD_EPSG_CODE"); + if (operationMethodEPSGCode) { + const auto boxedValue = dynamic_cast<const util::BoxedValue *>( + (*operationMethodEPSGCode).get()); + if (boxedValue && + boxedValue->type() == util::BoxedValue::Type::INTEGER) { + return boxedValue->integerValue(); + } + } + return nDefaultOperationMethodEPSGCode; +} //! @endcond // --------------------------------------------------------------------------- @@ -6534,12 +6559,13 @@ TransformationNNPtr Transformation::createGeocentricTranslations( isGeog3D); return create( properties, sourceCRSIn, targetCRSIn, nullptr, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_GEOGRAPHIC_3D)), VectorOfParameters{ createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_X_AXIS_TRANSLATION), createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_Y_AXIS_TRANSLATION), @@ -6592,11 +6618,12 @@ TransformationNNPtr Transformation::createPositionVector( isGeog3D); return createSevenParamsTransform( properties, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_POSITION_VECTOR_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_POSITION_VECTOR_GEOGRAPHIC_3D)), sourceCRSIn, targetCRSIn, translationXMetre, translationYMetre, translationZMetre, rotationXArcSecond, rotationYArcSecond, rotationZArcSecond, scaleDifferencePPM, accuracies); @@ -6641,11 +6668,12 @@ TransformationNNPtr Transformation::createCoordinateFrameRotation( isGeog3D); return createSevenParamsTransform( properties, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_COORDINATE_FRAME_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_COORDINATE_FRAME_GEOGRAPHIC_3D)), sourceCRSIn, targetCRSIn, translationXMetre, translationYMetre, translationZMetre, rotationXArcSecond, rotationYArcSecond, rotationZArcSecond, scaleDifferencePPM, accuracies); @@ -6784,12 +6812,13 @@ TransformationNNPtr Transformation::createTimeDependentPositionVector( isGeog3D); return createFifteenParamsTransform( properties, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_TIME_DEPENDENT_POSITION_VECTOR_GEOGRAPHIC_3D)), sourceCRSIn, targetCRSIn, translationXMetre, translationYMetre, translationZMetre, rotationXArcSecond, rotationYArcSecond, rotationZArcSecond, scaleDifferencePPM, rateTranslationX, @@ -6861,12 +6890,13 @@ TransformationNNPtr Transformation::createTimeDependentCoordinateFrameRotation( isGeog3D); return createFifteenParamsTransform( properties, - createMethodMapNameEPSGCode( + createMethodMapNameEPSGCode(useOperationMethodEPSGCodeIfPresent( + properties, isGeocentric ? EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOCENTRIC : isGeog2D ? EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_2D - : EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D), + : EPSG_CODE_METHOD_TIME_DEPENDENT_COORDINATE_FRAME_GEOGRAPHIC_3D)), sourceCRSIn, targetCRSIn, translationXMetre, translationYMetre, translationZMetre, rotationXArcSecond, rotationYArcSecond, rotationZArcSecond, scaleDifferencePPM, rateTranslationX, @@ -7448,6 +7478,14 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom, addModifiedIdentifier(map, op, true, derivedFrom); + const auto so = dynamic_cast<const SingleOperation *>(op); + if (so) { + const int soMethodEPSGCode = so->method()->getEPSGCode(); + if (soMethodEPSGCode > 0) { + map.set("OPERATION_METHOD_EPSG_CODE", soMethodEPSGCode); + } + } + return map; } @@ -12619,9 +12657,7 @@ CoordinateOperationFactory::Private::createOperations( auto vertCRSOfBaseOfBoundSrc = dynamic_cast<const crs::VerticalCRS *>(boundSrc->baseCRS().get()); - if (vertCRSOfBaseOfBoundSrc && hubSrcGeog && - hubSrcGeog->coordinateSystem()->axisList().size() == 3 && - geogDst->coordinateSystem()->axisList().size() == 3) { + if (vertCRSOfBaseOfBoundSrc && hubSrcGeog) { auto opsFirst = createOperations(sourceCRS, hubSrc, context); if (context.skipHorizontalTransformation) { if (!opsFirst.empty()) diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index eea7cce8..e044c0c7 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -237,7 +237,7 @@ CRSNNPtr CRS::alterGeodeticCRS(const GeodeticCRSNNPtr &newGeodCRS) const { auto projCRS = dynamic_cast<const ProjectedCRS *>(this); if (projCRS) { return ProjectedCRS::create(createPropertyMap(this), newGeodCRS, - projCRS->derivingConversionRef(), + projCRS->derivingConversion(), projCRS->coordinateSystem()); } @@ -264,7 +264,7 @@ CRSNNPtr CRS::alterCSLinearUnit(const common::UnitOfMeasure &unit) const { if (projCRS) { return ProjectedCRS::create( createPropertyMap(this), projCRS->baseCRS(), - projCRS->derivingConversionRef(), + projCRS->derivingConversion(), projCRS->coordinateSystem()->alterUnit(unit)); } } @@ -675,9 +675,8 @@ CRSNNPtr CRS::normalizeForVisualization() const { axisList[0]) : cs::CartesianCS::create(util::PropertyMap(), axisList[1], axisList[0], axisList[2]); - return util::nn_static_pointer_cast<CRS>( - ProjectedCRS::create(props, projCRS->baseCRS(), - projCRS->derivingConversionRef(), cs)); + return util::nn_static_pointer_cast<CRS>(ProjectedCRS::create( + props, projCRS->baseCRS(), projCRS->derivingConversion(), cs)); } } @@ -697,14 +696,26 @@ CRSNNPtr CRS::normalizeForVisualization() const { * The method returns a list of matching reference CRS, and the percentage * (0-100) of confidence in the match. The list is sorted by decreasing * confidence. - * - * 100% means that the name of the reference entry + * <ul> + * <li>100% means that the name of the reference entry * perfectly matches the CRS name, and both are equivalent. In which case a * single result is returned. - * 90% means that CRS are equivalent, but the names are not exactly the same. - * 70% means that CRS are equivalent), but the names do not match at all. - * 25% means that the CRS are not equivalent, but there is some similarity in - * the names. + * Note: in the case of a GeographicCRS whose axis + * order is implicit in the input definition (for example ESRI WKT), then axis + * order is ignored for the purpose of identification. That is the CRS built + * from + * GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]], + * PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] + * will be identified to EPSG:4326, but will not pass a + * isEquivalentTo(EPSG_4326, util::IComparable::Criterion::EQUIVALENT) test, + * but rather isEquivalentTo(EPSG_4326, + * util::IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS) + * </li> + * <li>90% means that CRS are equivalent, but the names are not exactly the same.</li> + * <li>70% means that CRS are equivalent), but the names do not match at all.</li> + * <li>25% means that the CRS are not equivalent, but there is some similarity in + * the names.</li> + * </ul> * Other confidence values may be returned by some specialized implementations. * * This is implemented for GeodeticCRS, ProjectedCRS, VerticalCRS and @@ -829,7 +840,7 @@ CRSNNPtr CRS::promoteTo3D(const std::string &newName, !newName.empty() ? newName : nameStr()), NN_NO_CHECK( util::nn_dynamic_pointer_cast<GeodeticCRS>(base3DCRS)), - projCRS->derivingConversionRef(), cs)); + projCRS->derivingConversion(), cs)); } } @@ -1554,17 +1565,30 @@ static bool hasCodeCompatibleOfAuthorityFactory( * authorityFactory is not null. * * The method returns a list of matching reference CRS, and the percentage - * (0-100) of confidence in the match. - * 100% means that the name of the reference entry + * (0-100) of confidence in the match: + * <ul> + * <li>100% means that the name of the reference entry * perfectly matches the CRS name, and both are equivalent. In which case a * single result is returned. - * 90% means that CRS are equivalent, but the names are not exactly the same. - * 70% means that CRS are equivalent (equivalent datum and coordinate system), - * but the names do not match at all. - * 60% means that ellipsoid, prime meridian and coordinate systems are - * equivalent, but the CRS and datum names do not match. - * 25% means that the CRS are not equivalent, but there is some similarity in - * the names. + * Note: in the case of a GeographicCRS whose axis + * order is implicit in the input definition (for example ESRI WKT), then axis + * order is ignored for the purpose of identification. That is the CRS built + * from + * GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]], + * PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] + * will be identified to EPSG:4326, but will not pass a + * isEquivalentTo(EPSG_4326, util::IComparable::Criterion::EQUIVALENT) test, + * but rather isEquivalentTo(EPSG_4326, + * util::IComparable::Criterion::EQUIVALENT_EXCEPT_AXIS_ORDER_GEOGCRS) + * </li> + * <li>90% means that CRS are equivalent, but the names are not exactly the same. + * <li>70% means that CRS are equivalent (equivalent datum and coordinate system), + * but the names do not match at all.</li> + * <li>60% means that ellipsoid, prime meridian and coordinate systems are + * equivalent, but the CRS and datum names do not match.</li> + * <li>25% means that the CRS are not equivalent, but there is some similarity in + * the names.</li> + * </ul> * * @param authorityFactory Authority factory (or null, but degraded * functionality) @@ -3218,10 +3242,10 @@ bool ProjectedCRS::_isEquivalentTo( ProjectedCRSNNPtr ProjectedCRS::alterParametersLinearUnit(const common::UnitOfMeasure &unit, bool convertToNewUnit) const { - return create(createPropertyMap(this), baseCRS(), - derivingConversionRef()->alterParametersLinearUnit( - unit, convertToNewUnit), - coordinateSystem()); + return create( + createPropertyMap(this), baseCRS(), + derivingConversion()->alterParametersLinearUnit(unit, convertToNewUnit), + coordinateSystem()); } //! @endcond @@ -3239,13 +3263,16 @@ void ProjectedCRS::addUnitConvertAndAxisSwap(io::PROJStringFormatter *formatter, if (!formatter->getCRSExport()) { formatter->addStep("unitconvert"); formatter->addParam("xy_in", "m"); - formatter->addParam("z_in", "m"); + if (!formatter->omitZUnitConversion()) + formatter->addParam("z_in", "m"); if (projUnit.empty()) { formatter->addParam("xy_out", toSI); - formatter->addParam("z_out", toSI); + if (!formatter->omitZUnitConversion()) + formatter->addParam("z_out", toSI); } else { formatter->addParam("xy_out", projUnit); - formatter->addParam("z_out", projUnit); + if (!formatter->omitZUnitConversion()) + formatter->addParam("z_out", projUnit); } } else { if (projUnit.empty()) { diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index a9607247..c0628270 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -3185,7 +3185,16 @@ ConversionNNPtr WKTParser::Private::buildProjectionFromESRI( } } - const auto *wkt2_mapping = getMapping(esriMapping->wkt2_name); + const char *projectionMethodWkt2Name = esriMapping->wkt2_name; + if (ci_equal(esriProjectionName, "Krovak")) { + const std::string projCRSName = + stripQuotes(projCRSNode->GP()->children()[0]); + if (projCRSName.find("_East_North") != std::string::npos) { + projectionMethodWkt2Name = EPSG_NAME_METHOD_KROVAK_NORTH_ORIENTED; + } + } + + const auto *wkt2_mapping = getMapping(projectionMethodWkt2Name); if (ci_equal(esriProjectionName, "Stereographic")) { try { if (std::fabs(io::asDouble( @@ -3467,6 +3476,14 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( } propertiesMethod.set(IdentifiedObject::NAME_KEY, projectionName); + std::vector<bool> foundParameters; + if (mapping) { + size_t countParams = 0; + while (mapping->params[countParams] != nullptr) { + ++countParams; + } + foundParameters.resize(countParams); + } for (const auto &childNode : projCRSNode->GP()->children()) { if (ci_equal(childNode->GP()->value(), WKTConstants::PARAMETER)) { const auto &childNodeChildren = childNode->GP()->children(); @@ -3487,11 +3504,18 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( continue; } } - const auto *paramMapping = + auto *paramMapping = mapping ? getMappingFromWKT1(mapping, parameterName) : nullptr; if (mapping && mapping->epsg_code == EPSG_CODE_METHOD_MERCATOR_VARIANT_B && ci_equal(parameterName, "latitude_of_origin")) { + for (size_t idx = 0; mapping->params[idx] != nullptr; ++idx) { + if (mapping->params[idx]->epsg_code == + EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN) { + foundParameters[idx] = true; + break; + } + } parameterName = EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN; propertiesParameter.set( Identifier::CODE_KEY, @@ -3499,6 +3523,12 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( propertiesParameter.set(Identifier::CODESPACE_KEY, Identifier::EPSG); } else if (paramMapping) { + for (size_t idx = 0; mapping->params[idx] != nullptr; ++idx) { + if (mapping->params[idx] == paramMapping) { + foundParameters[idx] = true; + break; + } + } parameterName = paramMapping->wkt2_name; if (paramMapping->epsg_code != 0) { propertiesParameter.set(Identifier::CODE_KEY, @@ -3522,6 +3552,38 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( } } + // Add back important parameters that should normally be present, but + // are sometimes missing. Currently we only deal with Scale factor at + // natural origin. This is to avoid a default value of 0 to slip in later. + // But such WKT should be considered invalid. + if (mapping) { + for (size_t idx = 0; mapping->params[idx] != nullptr; ++idx) { + if (!foundParameters[idx] && + mapping->params[idx]->epsg_code == + EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN) { + + emitRecoverableWarning( + "The WKT string lacks a value " + "for " EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN + ". Default it to 1."); + + PropertyMap propertiesParameter; + propertiesParameter.set( + Identifier::CODE_KEY, + EPSG_CODE_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN); + propertiesParameter.set(Identifier::CODESPACE_KEY, + Identifier::EPSG); + propertiesParameter.set( + IdentifiedObject::NAME_KEY, + EPSG_NAME_PARAMETER_SCALE_FACTOR_AT_NATURAL_ORIGIN); + parameters.push_back( + OperationParameter::create(propertiesParameter)); + values.push_back(ParameterValue::create( + Measure(1.0, UnitOfMeasure::SCALE_UNITY))); + } + } + } + return Conversion::create( PropertyMap().set(IdentifiedObject::NAME_KEY, "unnamed"), propertiesMethod, parameters, values) diff --git a/src/pipeline.cpp b/src/pipeline.cpp index afa3b19a..76ffc98e 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -105,6 +105,7 @@ Thomas Knudsen, thokn@sdfe.dk, 2016-05-20 #include "geodesic.h" #include "proj.h" #include "proj_internal.h" +#include "proj_experimental.h" PROJ_HEAD(pipeline, "Transformation pipeline manager"); PROJ_HEAD(pop, "Retrieve coordinate value from pipeline stack"); @@ -136,7 +137,11 @@ static PJ_LPZ pipeline_reverse_3d (PJ_XYZ xyz, PJ *P); static PJ_XY pipeline_forward (PJ_LP lp, PJ *P); static PJ_LP pipeline_reverse (PJ_XY xy, PJ *P); - +void pj_pipeline_assign_context_to_steps( PJ* P, PJ_CONTEXT* ctx ) +{ + for (int i = 1; i <= static_cast<struct pj_opaque*>(P->opaque)->steps; i++) + proj_assign_context(static_cast<struct pj_opaque*>(P->opaque)->pipeline[i], ctx); +} static PJ_COORD pipeline_forward_4d (PJ_COORD point, PJ *P) { @@ -154,7 +154,7 @@ extern "C" { /* The version numbers should be updated with every release! **/ #define PROJ_VERSION_MAJOR 6 #define PROJ_VERSION_MINOR 2 -#define PROJ_VERSION_PATCH 0 +#define PROJ_VERSION_PATCH 1 extern char const PROJ_DLL pj_release[]; /* global release id string */ diff --git a/src/proj_api.h b/src/proj_api.h index b933fc6b..23eecfa7 100644 --- a/src/proj_api.h +++ b/src/proj_api.h @@ -38,7 +38,7 @@ #endif #ifndef PJ_VERSION -#define PJ_VERSION 620 +#define PJ_VERSION 621 #endif #ifdef PROJ_RENAME_SYMBOLS diff --git a/src/proj_internal.h b/src/proj_internal.h index 4a126e98..77c4ba17 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -926,6 +926,8 @@ std::string pj_double_quote_string_param_if_needed(const std::string& str); PJ *pj_create_internal (PJ_CONTEXT *ctx, const char *definition); PJ *pj_create_argv_internal (PJ_CONTEXT *ctx, int argc, char **argv); +void pj_pipeline_assign_context_to_steps( PJ* P, PJ_CONTEXT* ctx ); + /* classic public API */ #include "proj_api.h" diff --git a/src/projections/ob_tran.cpp b/src/projections/ob_tran.cpp index 4ae8dbe7..badc6dd8 100644 --- a/src/projections/ob_tran.cpp +++ b/src/projections/ob_tran.cpp @@ -31,8 +31,10 @@ static PJ_XY o_forward(PJ_LP lp, PJ *P) { /* spheroid */ coslam = cos(lp.lam); sinphi = sin(lp.phi); cosphi = cos(lp.phi); + /* Formula (5-8b) of Snyder's "Map projections: a working manual" */ lp.lam = adjlon(aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam + Q->cphip * sinphi) + Q->lamp); + /* Formula (5-7) */ lp.phi = aasin(P->ctx,Q->sphip * sinphi - Q->cphip * cosphi * coslam); return Q->link->fwd(lp, Q->link); @@ -62,7 +64,9 @@ static PJ_LP o_inverse(PJ_XY xy, PJ *P) { /* spheroid */ coslam = cos(lp.lam -= Q->lamp); sinphi = sin(lp.phi); cosphi = cos(lp.phi); + /* Formula (5-9) */ lp.phi = aasin(P->ctx,Q->sphip * sinphi + Q->cphip * cosphi * coslam); + /* Formula (5-10b) */ lp.lam = aatan2(cosphi * sin(lp.lam), Q->sphip * cosphi * coslam - Q->cphip * sinphi); } diff --git a/src/release.cpp b/src/release.cpp index 13ed45f0..7f62da3f 100644 --- a/src/release.cpp +++ b/src/release.cpp @@ -11,7 +11,7 @@ char const pj_release[] = STR(PROJ_VERSION_MAJOR)"." STR(PROJ_VERSION_MINOR)"." STR(PROJ_VERSION_PATCH)", " - "September 1st, 2019"; + "November 1st, 2019"; const char *pj_get_release() { return pj_release; diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo index d8569a76..3c09a814 100755 --- a/test/cli/testprojinfo +++ b/test/cli/testprojinfo @@ -115,6 +115,10 @@ echo "Testing NGF IGN69 height to RGF93: projinfo -s EPSG:5720 -t EPSG:4965 -o P $EXE -s EPSG:5720 -t EPSG:4965 -o PROJ >>${OUT} 2>&1 echo "" >>${OUT} +echo "Testing -s "+proj=longlat +datum=WGS84 +geoidgrids=@foo.gtx +type=crs" -t EPSG:4326 -o PROJ -q" >> ${OUT} +$EXE -s "+proj=longlat +datum=WGS84 +geoidgrids=@foo.gtx +type=crs" -t EPSG:4326 -o PROJ -q >>${OUT} 2>&1 +echo "" >>${OUT} + # do 'diff' with distribution results echo "diff ${OUT} with testprojinfo_out.dist" diff -u ${OUT} ${TEST_CLI_DIR}/testprojinfo_out.dist diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist index 2c0a5c05..09e68ca6 100644 --- a/test/cli/testprojinfo_out.dist +++ b/test/cli/testprojinfo_out.dist @@ -876,3 +876,6 @@ INVERSE(EPSG):10000, Inverse of RGF93 to NGF IGN69 height (1), 0.5 m, France - m PROJ string: +proj=pipeline +step +inv +proj=vgridshift +grids=ggf97a.txt +multiplier=1 +Testing -s +proj=longlat +datum=WGS84 +geoidgrids=@foo.gtx +type=crs -t EPSG:4326 -o PROJ -q ++proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1 + diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index 7fd0e742..0a860d1f 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -231,7 +231,8 @@ TEST_F(CApi, proj_create_from_wkt) { " PRIMEM[\"Greenwich\",0],\n" " UNIT[\"degree\",0.0174532925199433]]", nullptr, nullptr, nullptr); - EXPECT_EQ(obj, nullptr); + ObjectKeeper keeper(obj); + EXPECT_NE(obj, nullptr); } { PROJ_STRING_LIST warningList = nullptr; @@ -244,7 +245,8 @@ TEST_F(CApi, proj_create_from_wkt) { " PRIMEM[\"Greenwich\",0],\n" " UNIT[\"degree\",0.0174532925199433]]", nullptr, &warningList, &errorList); - EXPECT_EQ(obj, nullptr); + ObjectKeeper keeper(obj); + EXPECT_NE(obj, nullptr); EXPECT_EQ(warningList, nullptr); proj_string_list_destroy(warningList); EXPECT_NE(errorList, nullptr); diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 0df128e6..faa1ace4 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -5281,3 +5281,70 @@ TEST(crs, promoteTo3D) { EXPECT_EQ(baseCRS->coordinateSystem()->axisList().size(), 3U); } } + +// --------------------------------------------------------------------------- + +TEST(crs, projected_normalizeForVisualization_do_not_mess_deriving_conversion) { + + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + // Something with non standard order + auto projCRS = authFactory->createProjectedCRS("3035"); + { + auto src = GeographicCRS::EPSG_4326; + auto op = + CoordinateOperationFactory::create()->createOperation(src, projCRS); + ASSERT_TRUE(op != nullptr); + // Make sure to run that in a scope, so that the object get destroyed + op->normalizeForVisualization(); + } + EXPECT_EQ(projCRS->derivingConversion()->targetCRS().get(), projCRS.get()); +} + +// --------------------------------------------------------------------------- + +TEST(crs, projected_promoteTo3D_do_not_mess_deriving_conversion) { + + auto projCRS = createProjected(); + { + // Make sure to run that in a scope, so that the object get destroyed + projCRS->promoteTo3D(std::string(), nullptr); + } + EXPECT_EQ(projCRS->derivingConversion()->targetCRS().get(), projCRS.get()); +} + +// --------------------------------------------------------------------------- + +TEST(crs, projected_alterGeodeticCRS_do_not_mess_deriving_conversion) { + + auto projCRS = createProjected(); + { + // Make sure to run that in a scope, so that the object get destroyed + projCRS->alterGeodeticCRS(NN_NO_CHECK(projCRS->extractGeographicCRS())); + } + EXPECT_EQ(projCRS->derivingConversion()->targetCRS().get(), projCRS.get()); +} + +// --------------------------------------------------------------------------- + +TEST(crs, projected_alterCSLinearUnit_do_not_mess_deriving_conversion) { + + auto projCRS = createProjected(); + { + // Make sure to run that in a scope, so that the object get destroyed + projCRS->alterCSLinearUnit(UnitOfMeasure("my unit", 2)); + } + EXPECT_EQ(projCRS->derivingConversion()->targetCRS().get(), projCRS.get()); +} + +// --------------------------------------------------------------------------- + +TEST(crs, projected_alterParametersLinearUnit_do_not_mess_deriving_conversion) { + + auto projCRS = createProjected(); + { + // Make sure to run that in a scope, so that the object get destroyed + projCRS->alterParametersLinearUnit(UnitOfMeasure::METRE, false); + } + EXPECT_EQ(projCRS->derivingConversion()->targetCRS().get(), projCRS.get()); +} diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 0eed2d15..8b6b315f 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -1174,6 +1174,40 @@ TEST(wkt_parse, wkt1_Mercator_1SP_with_latitude_origin_0) { // --------------------------------------------------------------------------- +TEST(wkt_parse, wkt1_Mercator_1SP_without_scale_factor) { + // See https://github.com/OSGeo/PROJ/issues/1700 + auto wkt = "PROJCS[\"unnamed\",\n" + " GEOGCS[\"WGS 84\",\n" + " DATUM[\"unknown\",\n" + " SPHEROID[\"WGS84\",6378137,298.257223563]],\n" + " PRIMEM[\"Greenwich\",0],\n" + " UNIT[\"degree\",0.0174532925199433]],\n" + " PROJECTION[\"Mercator_1SP\"],\n" + " PARAMETER[\"central_meridian\",0],\n" + " PARAMETER[\"false_easting\",0],\n" + " PARAMETER[\"false_northing\",0],\n" + " UNIT[\"Meter\",1],\n" + " AXIS[\"Easting\",EAST],\n" + " AXIS[\"Northing\",NORTH]]"; + WKTParser parser; + parser.setStrict(false).attachDatabaseContext(DatabaseContext::create()); + auto obj = parser.createFromWKT(wkt); + EXPECT_TRUE(!parser.warningList().empty()); + + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + auto got_wkt = crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL).get()); + EXPECT_TRUE(got_wkt.find("PARAMETER[\"scale_factor\",1]") != + std::string::npos) + << got_wkt; + EXPECT_EQ(crs->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +units=m " + "+no_defs +type=crs"); +} + +// --------------------------------------------------------------------------- + TEST(wkt_parse, wkt1_krovak_south_west) { auto wkt = "PROJCS[\"S-JTSK / Krovak\"," @@ -5096,6 +5130,79 @@ TEST(wkt_parse, wkt1_esri_krovak_south_west) { // --------------------------------------------------------------------------- +TEST(wkt_parse, + wkt1_esri_krovak_east_north_non_standard_likely_from_GDAL_wkt1) { + auto wkt = "PROJCS[\"S_JTSK_Krovak_East_North\",GEOGCS[\"GCS_S-JTSK\"," + "DATUM[\"D_S_JTSK\",SPHEROID[\"Bessel_1841\"," + "6377397.155,299.1528128]],PRIMEM[\"Greenwich\",0]," + "UNIT[\"Degree\",0.017453292519943295]],PROJECTION[\"Krovak\"]," + "PARAMETER[\"latitude_of_center\",49.5]," + "PARAMETER[\"longitude_of_center\",24.83333333333333]," + "PARAMETER[\"azimuth\",30.28813972222222]," + "PARAMETER[\"pseudo_standard_parallel_1\",78.5]," + "PARAMETER[\"scale_factor\",0.9999]," + "PARAMETER[\"false_easting\",0]," + "PARAMETER[\"false_northing\",0],UNIT[\"Meter\",1]]"; + + auto obj = WKTParser() + .attachDatabaseContext(DatabaseContext::create()) + .createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + + EXPECT_EQ(crs->derivingConversion()->method()->nameStr(), + "Krovak (North Orientated)"); + + auto expected_wkt2 = + "PROJCRS[\"S_JTSK_Krovak_East_North\",\n" + " BASEGEODCRS[\"GCS_S-JTSK\",\n" + " DATUM[\"System of the Unified Trigonometrical Cadastral " + "Network\",\n" + " ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128,\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"EPSG\",6156]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"Degree\",0.0174532925199433]]],\n" + " CONVERSION[\"unnamed\",\n" + " METHOD[\"Krovak (North Orientated)\",\n" + " ID[\"EPSG\",1041]],\n" + " PARAMETER[\"Latitude of projection centre\",49.5,\n" + " ANGLEUNIT[\"Degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8811]],\n" + " PARAMETER[\"Longitude of origin\",24.8333333333333,\n" + " ANGLEUNIT[\"Degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8833]],\n" + " PARAMETER[\"Co-latitude of cone axis\",30.2881397222222,\n" + " ANGLEUNIT[\"Degree\",0.0174532925199433],\n" + " ID[\"EPSG\",1036]],\n" + " PARAMETER[\"Latitude of pseudo standard parallel\",78.5,\n" + " ANGLEUNIT[\"Degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8818]],\n" + " PARAMETER[\"Scale factor on pseudo standard " + "parallel\",0.9999,\n" + " SCALEUNIT[\"unity\",1],\n" + " ID[\"EPSG\",8819]],\n" + " PARAMETER[\"False easting\",0,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8806]],\n" + " PARAMETER[\"False northing\",0,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8807]]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east,\n" + " ORDER[1],\n" + " LENGTHUNIT[\"metre\",1,\n" + " ID[\"EPSG\",9001]]],\n" + " AXIS[\"(N)\",north,\n" + " ORDER[2],\n" + " LENGTHUNIT[\"metre\",1,\n" + " ID[\"EPSG\",9001]]]]"; + + EXPECT_EQ(crs->exportToWKT(WKTFormatter::create().get()), expected_wkt2); +} + +// --------------------------------------------------------------------------- + TEST(wkt_parse, wkt1_esri_normalize_unit) { auto wkt = "PROJCS[\"Accra_Ghana_Grid\",GEOGCS[\"GCS_Accra\"," "DATUM[\"D_Accra\",SPHEROID[\"War_Office\",6378300.0,296.0]]," diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp index 3e538f33..7e63f921 100644 --- a/test/unit/test_operation.cpp +++ b/test/unit/test_operation.cpp @@ -5388,6 +5388,49 @@ TEST(operation, projCRS_no_id_to_geogCRS_context) { // --------------------------------------------------------------------------- +TEST(operation, geogCRS_3D_to_projCRS_with_2D_geocentric_translation) { + + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto src = + authFactory->createCoordinateReferenceSystem("4979"); // WGS 84 3D + + // Azores Central 1948 / UTM zone 26N + auto dst = authFactory->createCoordinateReferenceSystem("2189"); + + auto list = + CoordinateOperationFactory::create()->createOperations(src, dst, ctxt); + ASSERT_GE(list.size(), 1U); + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=axisswap +order=2,1 " + "+step +proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m " + "+step +proj=push +v_3 " // this is what we check + "+step +proj=cart +ellps=WGS84 " + "+step +proj=helmert +x=104 +y=-167 +z=38 " + "+step +inv +proj=cart +ellps=intl " + "+step +proj=pop +v_3 " // this is what we check + "+step +proj=utm +zone=26 +ellps=intl"); + + auto listReverse = + CoordinateOperationFactory::create()->createOperations(dst, src, ctxt); + ASSERT_GE(listReverse.size(), 1U); + EXPECT_EQ( + listReverse[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +inv +proj=utm +zone=26 +ellps=intl " + "+step +proj=push +v_3 " // this is what we check + "+step +proj=cart +ellps=intl " + "+step +proj=helmert +x=-104 +y=167 +z=-38 " + "+step +inv +proj=cart +ellps=WGS84 " + "+step +proj=pop +v_3 " // this is what we check + "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m " + "+step +proj=axisswap +order=2,1"); +} + +// --------------------------------------------------------------------------- + TEST(operation, projCRS_to_projCRS) { auto op = CoordinateOperationFactory::create()->createOperation( @@ -6955,6 +6998,30 @@ TEST(operation, compoundCRS_from_WKT2_no_id_to_geogCRS_3D_context) { // --------------------------------------------------------------------------- +TEST(operation, compoundCRS_with_non_meter_horiz_and_vertical_to_geog) { + auto objSrc = PROJStringParser().createFromPROJString( + "+proj=utm +zone=31 +datum=WGS84 +units=us-ft +vunits=us-ft +type=crs"); + auto src = nn_dynamic_pointer_cast<CRS>(objSrc); + ASSERT_TRUE(src != nullptr); + auto authFactory = + AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0); + auto list = CoordinateOperationFactory::create()->createOperations( + NN_NO_CHECK(src), authFactory->createCoordinateReferenceSystem("4326"), + ctxt); + ASSERT_EQ(list.size(), 1U); + // Check that vertical unit conversion is done just once + EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=unitconvert +xy_in=us-ft +xy_out=m " + "+step +inv +proj=utm +zone=31 +ellps=WGS84 " + "+step +proj=unitconvert +xy_in=rad +z_in=us-ft " + "+xy_out=deg +z_out=m " + "+step +proj=axisswap +order=2,1"); +} + +// --------------------------------------------------------------------------- + TEST(operation, boundCRS_to_compoundCRS) { auto objSrc = PROJStringParser().createFromPROJString( "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +type=crs"); diff --git a/travis/osx/before_install.sh b/travis/osx/before_install.sh index 55c0667a..c85c460b 100755 --- a/travis/osx/before_install.sh +++ b/travis/osx/before_install.sh @@ -2,7 +2,7 @@ set -e -export PATH=$HOME/Library/Python/3.6/bin:$PATH +export PATH=$HOME/Library/Python/3.7/bin:$PATH ./travis/before_install.sh @@ -11,6 +11,8 @@ brew install ccache brew install sqlite3 brew install doxygen brew install md5sha1sum +brew reinstall python +brew reinstall wget pip3 install --user sphinx sphinx-rtd-theme sphinxcontrib-bibtex breathe which sphinx-build |
