Compare commits

...
82 Commits
Author SHA1 Message Date
Even Rouault a539150fe8 Update projsync.rst 2022-10-30 10:06:05 +01:00
Even Rouault cfa19520db Merge pull request #3414 from OSGeo/backport-3413-to-9.1
[Backport 9.1] C++ API: add methods to build Geographic/Vertical Offset conversions
2022-10-25 20:54:12 +02:00
Even Rouault d1955db87d Merge pull request #3413 from rouault/add_conversion_geogoffsets
C++ API: add methods to build Geographic/Vertical Offset conversions
2022-10-24 18:13:34 +00:00
Even Rouault 9e1b8ac692 Merge pull request #3412 from OSGeo/backport-3411-to-9.1
[Backport 9.1] createOperations(): fix issues when transforming between Geog3D and DerivedGeog3D CRS with Geographic3D offsets method
2022-10-23 12:23:03 +02:00
Even Rouault 5d388a28f1 Merge pull request #3411 from rouault/fix_derived_geogCRS_3D_issues
createOperations(): fix issues when transforming between Geog3D and DerivedGeog3D CRS with Geographic3D offsets method
2022-10-23 10:00:21 +00:00
Even Rouault 159655ecad Merge pull request #3409 from OSGeo/backport-3408-to-9.1
[Backport 9.1] VerticalCRS::_isEquivalentTo(): do not consider VerticalCRS and DerivedVerticalCRS as equivalent
2022-10-21 21:45:16 +02:00
Even Rouault ea292b0aa3 Merge pull request #3408 from rouault/fix_3407
VerticalCRS::_isEquivalentTo(): do not consider VerticalCRS and DerivedVerticalCRS as equivalent
2022-10-21 19:25:46 +00:00
Even Rouault 0544964369 Merge pull request #3405 from OSGeo/backport-3395-to-9.1
[Backport 9.1] cct and cs2cs: make them robust against UTF-8 BOM at beginning of input files (fixes #3287)
2022-10-19 12:48:35 +02:00
Even Rouault 6cfca76d1b Merge pull request #3395 from rouault/fix_3287
cct and cs2cs: make them robust against UTF-8 BOM at beginning of input files (fixes #3287)
2022-10-18 23:21:22 +00:00
Even Rouault d0323a7616 Merge pull request #3401 from OSGeo/backport-3398-to-9.1
[Backport 9.1] add startup + OSS to users docs
2022-10-14 18:53:41 +02:00
Even Rouault 642b671254 Merge pull request #3398 from BuntingLabs/add-users
add startup + OSS to users docs
2022-10-14 16:30:33 +00:00
Even Rouault 895bca5864 Merge pull request #3393 from OSGeo/rouault-patch-1
bindings.rst: mention PROJ-JNI
2022-10-13 16:59:27 +02:00
Even Rouault 3b898c1e1a bindings.rst: mention PROJ-JNI 2022-10-13 15:08:56 +02:00
jbeilin 7ade8ef296 users.rst: add ENSG-géomatique (#3391) 2022-10-13 14:02:44 +02:00
Even Rouault 747f0d5323 cs2cs: fix incorrect use of proj_cs_get_axis_count() introduced in 4abde1b9f8 (not in a release) 2022-10-12 17:47:40 +02:00
Even Rouault 8bfb760b64 defmodel.rst: add link to deformation_model.schema.json 2022-10-12 11:57:40 +02:00
Even Rouault f3d79c378c Merge pull request #3388 from AndrewAtAvenza/patch-1
Added Avenza Maps to list of proprietary software that uses PROJ
2022-10-11 16:08:17 +02:00
Andrew Patterson 3b8377e8b4 Added Avenza Maps
Added Avenza Maps to the list of Proprietary licensed software
2022-10-11 10:04:54 -04:00
Even Rouault 3e6c789e7d Doc: users.rst: fix 2022-10-11 14:50:51 +02:00
Even Rouault e638272843 Merge pull request #3387 from OSGeo/backport-3382-to-9.1
[Backport 9.1] Doc: users.rst: link to bindings.rst
2022-10-11 12:03:07 +02:00
Even Rouault c5170615ab Merge pull request #3382 from rouault/doc_user_bindings
Doc: users.rst: link to bindings.rst
2022-10-11 09:57:11 +00:00
Even Rouault aaa90e311d Merge pull request #3385 from afrigeri/patch-1
added gislab at INAF
2022-10-11 11:39:43 +02:00
Even Rouault becff6864a Update users.rst 2022-10-11 11:39:26 +02:00
Alessandro Frigeri ba700d0248 added gislab at INAF 2022-10-11 09:33:25 +02:00
Even Rouault 215e6d19b2 users.rst: formatting fix 2022-10-10 22:01:30 +02:00
Even Rouault 0fa8862dc0 Merge pull request #3383 from OSGeo/m-kuhn-patch-1
Add qfield to users list
2022-10-10 20:48:54 +02:00
Matthias Kuhn 56a39eaf44 Add qfield to users list 2022-10-10 20:40:43 +02:00
Even Rouault 922185bc9b Merge pull request #3380 from Jochem-L/patch-1
Update users.rst
2022-10-10 20:17:54 +02:00
Jochem-L 11b63ff6a2 Update users.rst 2022-10-10 20:00:44 +02:00
Even Rouault 1231c55f78 Merge pull request #3376 from OSGeo/rouault-patch-1
faq.rst: remove trailing character
2022-10-10 19:02:55 +02:00
Even Rouault cd41b56f99 faq.rst: remove trailing character 2022-10-10 19:02:29 +02:00
Even Rouault 401ca42eeb Merge pull request #3375 from OSGeo/backport-3369-to-9.1
[Backport 9.1] Doc: add a page about users of PROJ
2022-10-10 18:00:14 +02:00
Even Rouault fdeb558166 Merge pull request #3369 from rouault/doc_users
Doc: add a page about users of PROJ
2022-10-10 15:59:21 +00:00
Even Rouault 5ed73e514c Merge pull request #3373 from OSGeo/backport-3371-to-9.1
[Backport 9.1] createFromUserInput(): make it work better when approximate name is provided
2022-10-09 13:16:28 +02:00
Even Rouault cc6693af26 Merge pull request #3372 from OSGeo/backport-3367-to-9.1
[Backport 9.1] projinfo / cs2cs : auto promotion to 3D of CRS specified by name
2022-10-09 13:16:15 +02:00
Even Rouault 36ff062b83 Merge pull request #3371 from rouault/createFromUserInput_improvement
createFromUserInput(): make it work better when approximate name is provided
2022-10-08 13:18:05 +00:00
Even Rouault cba8c78a0a Merge pull request #3367 from rouault/longitude_rotation_fix
projinfo / cs2cs : auto promotion to 3D of CRS specified by name
2022-10-08 13:17:55 +00:00
Even Rouault ced426c8d5 Merge pull request #3368 from OSGeo/rouault-patch-1
Doc: community: disable for now FOSS4G section
2022-10-07 19:46:42 +02:00
Even Rouault 037971a375 Doc: community: disable for now FOSS4G section 2022-10-07 19:05:08 +02:00
Even Rouault 36e3df9b15 Merge pull request #3366 from OSGeo/backport-3365-to-9.1
[Backport 9.1] findsOpsInRegistryWithIntermediate(): make it work when source/target geodetic CRS has no known id
2022-10-07 16:09:46 +02:00
Even Rouault 428e8150be Merge pull request #3365 from rouault/fix_findsOpsInRegistryWithIntermediate
findsOpsInRegistryWithIntermediate(): make it work when source/target geodetic CRS has no known id
2022-10-07 11:38:05 +00:00
Kristian Evers 08bcb4f928 Merge pull request #3364 from OSGeo/backport-3351-to-9.1
[Backport 9.1] Doc: document +over limitations (fixes #3348)
2022-10-07 09:18:54 +02:00
Even Rouault c314ef931c Merge pull request #3351 from rouault/fix_3348
Doc: document +over limitations (fixes #3348)
2022-10-06 19:18:36 +00:00
Even Rouault 252e3d1a56 Merge pull request #3363 from OSGeo/backport-3361-to-9.1
[Backport 9.1] createOperations(): emulate PROJ < 6 behavior when doing geocentric <--> geographic transformation between datum with unknown transformation (fixes #3360)
2022-10-06 20:28:48 +02:00
Even Rouault 1532683766 Merge pull request #3361 from rouault/fix_3360
createOperations(): emulate PROJ < 6 behavior when doing geocentric <--> geographic transformation between datum with unknown transformation (fixes #3360)
2022-10-06 09:42:14 +00:00
Even Rouault 879b677603 Merge pull request #3356 from OSGeo/backport-3355-to-9.1
[Backport 9.1] Fix issue when transforming from/into a WKT2 Bound VerticalCRS with a  'Geographic3D to GravityRelatedHeight' method (fixes #3354)
2022-09-30 19:25:12 +02:00
Even Rouault 0b74725ca6 Merge pull request #3355 from rouault/fix_3354
Fix issue when transforming from/into a WKT2 Bound VerticalCRS with a  'Geographic3D to GravityRelatedHeight' method (fixes #3354)
2022-09-30 09:54:43 +00:00
Even Rouault f1963e761b Merge pull request #3352 from OSGeo/backport-3350-to-9.1
[Backport 9.1] proj_normalize_for_visualization(): take into account FORCE_OVER property from source operation (fixes #3347)
2022-09-27 21:06:03 +02:00
Even Rouault 5dcd58f16e Merge pull request #3350 from rouault/fix_3347
proj_normalize_for_visualization(): take into account FORCE_OVER property from source operation (fixes #3347)
2022-09-27 13:01:14 +00:00
Even Rouault 2ade26a374 Merge pull request #3349 from OSGeo/backport-3346-to-9.1
[Backport 9.1] Add preliminary documentation of suffix based specification of units
2022-09-27 14:55:52 +02:00
Sebastian Val 620f7dcb82 Doc: add preliminary documentation of suffix based specification of units (#3346)
Fixes #3345
2022-09-27 09:44:45 +00:00
Even Rouault 258080d492 Merge pull request #3344 from OSGeo/backport-3342-to-9.1
[Backport 9.1] WKT import: 3D-promote base CRS of 3D DerivedProjectedCRS (fixes #3340)
2022-09-25 15:31:40 +02:00
Even Rouault a6897da6d9 Merge pull request #3342 from rouault/fix_3340
WKT import: 3D-promote base CRS of 3D DerivedProjectedCRS (fixes #3340)
2022-09-25 10:59:32 +00:00
Even Rouault dde3af1ef6 Merge pull request #3343 from OSGeo/backport-3341-to-9.1
[Backport 9.1] Build: link geodtest against libm when available (fixes #3311)
2022-09-24 13:59:28 +02:00
Even Rouault db126a6ba1 Merge pull request #3341 from rouault/fix_3311
Build: link geodtest against libm when available (fixes #3311)
2022-09-24 11:17:02 +00:00
Even Rouault 3ec6b92a39 Merge pull request #3339 from OSGeo/backport-3324-to-9.1
[Backport 9.1] CMake: add a INSTALL_LEGACY_CMAKE_FILES option (fixes OSGeo/gdal#5646)
2022-09-24 12:16:43 +02:00
Even Rouault 028c60f32d Merge pull request #3324 from rouault/fix_gdal_5646
CMake: add a INSTALL_LEGACY_CMAKE_FILES option (fixes OSGeo/gdal#5646)
2022-09-23 14:54:33 +00:00
Kristian Evers 8fc56a6220 Merge pull request #3336 from OSGeo/backport-3333-to-9.1
[Backport 9.1] Fix issue related to transforming to CGVD28 height (EPSG:5713)
2022-09-22 17:44:43 +02:00
Even Rouault d6c5522e9f Merge pull request #3333 from rouault/fix_3328
Fix issue related to transforming to CGVD28 height (EPSG:5713)
2022-09-22 12:14:40 +00:00
Kristian Evers 372e2fb062 Merge pull request #3332 from OSGeo/backport-3331-to-9.1
[Backport 9.1] Fix typos/formatting in tutorials
2022-09-20 15:31:18 +02:00
Kristian Evers 53d8bb5541 Merge pull request #3331 from AlexBass05/fix-tutorial-typos
Fix typos/formatting in tutorials
2022-09-20 12:25:10 +00:00
Kristian Evers 8de96ede73 Merge pull request #3329 from khurramkhalil/patch-1
Added missing punctuation mark
2022-09-20 08:58:50 +02:00
Khurram Khalil e291698c47 Added missing punctuation mark
Added missing punctuation mark in transformation.rst docs fie.
2022-09-20 11:19:41 +05:00
Even Rouault 800c06689f Merge pull request #3320 from OSGeo/backport-3319-to-9.1
[Backport 9.1] Implement alterCSLinearUnit for DerivedProjectedCRS
2022-09-15 08:46:22 +02:00
Kristian Evers d4fb7161d5 Merge pull request #3322 from OSGeo/backport-3304-to-9.1
[Backport 9.1] Tutorials for the docs
2022-09-14 19:50:25 +02:00
Kristian Evers 8f7f1c9f25 Merge pull request #3304 from kbevers/tutorials
Tutorials for the docs
2022-09-14 16:53:57 +00:00
Even Rouault f4eb93c1c4 Merge pull request #3319 from jjimenezshaw/alterCSLinearUnit-derivedProj
Implement alterCSLinearUnit for DerivedProjectedCRS
2022-09-13 12:34:09 +00:00
Even Rouault 9107ea23a3 Merge pull request #3318 from OSGeo/backport-3317-to-9.1
[Backport 9.1] Add method DerivedProjectedCRS::demoteTo2D and implement promoteTo3D
2022-09-13 14:12:54 +02:00
Javier Jimenez Shaw 16cec28e4c Add method DerivedProjectedCRS::demoteTo2D and implement promoteTo3D (#3317) 2022-09-11 20:40:24 +00:00
Even Rouault af0daa6787 Merge pull request #3315 from OSGeo/backport-3313-to-9.1
[Backport 9.1] GeoTIFF grids: support UNITTYPE=arc-seconds per year for temporal hgridshift
2022-09-11 12:21:43 +02:00
Even Rouault f74f8a0da6 Merge pull request #3314 from OSGeo/backport-3312-to-9.1
[Backport 9.1] Docs: update doc of grid-based methods to mention/advertize more GeoTIFF
2022-09-11 12:21:32 +02:00
Even Rouault 34b8b8fe6f Merge pull request #3313 from rouault/gtg_arcsecond_per_year
GeoTIFF grids: support UNITTYPE=arc-seconds per year for temporal hgridshift
2022-09-08 20:30:56 +00:00
Even Rouault 83def49fa8 Merge pull request #3312 from rouault/doc_grid_formats
Docs: update doc of grid-based methods to mention/advertize more GeoTIFF
2022-09-08 20:30:50 +00:00
Kristian Evers b4d1a777b0 docs: remove duplicate target name on download page 2022-09-01 20:43:03 +02:00
Even Rouault ae64b7f5f2 Merge pull request #3307 from rouault/epsg_10_076
Database: update to EPSG v10.076
2022-09-01 20:37:56 +02:00
Kristian Evers d700052a76 Update github_version in doc config 2022-09-01 17:09:35 +02:00
Kristian Evers 95545fb4f8 Update website for 9.1.0 release 2022-09-01 16:41:52 +02:00
Kristian EversandMike Taves 2f3dcce640 Avoid using upper case project name in doc install dir (#3299)
Closes #3296 

Co-authored-by: Mike Taves <mwtoews@gmail.com>
2022-08-28 12:35:24 +02:00
Even Rouault cc8970d96e Merge pull request #3305 from OSGeo/backport-3300-to-9.1
[Backport 9.1] JSON output: avoid rounding issues with integer values in a double on…
2022-08-27 18:12:16 +02:00
Even Rouault 6e791c10d5 Merge pull request #3300 from rouault/fix_3297
JSON output: avoid rounding issues with integer values in a double on…
2022-08-27 15:37:15 +00:00
Kristian Evers 7d3c2425cc Merge pull request #3303 from OSGeo/backport-3302-to-9.1
[Backport 9.1] CMake: fix symbol detection when CFLAGS includes -Werror=something (fixes #3295)
2022-08-27 15:45:34 +02:00
Even Rouault ea151cd98b Merge pull request #3302 from rouault/fix_3295
CMake: fix symbol detection when CFLAGS includes -Werror=something (fixes #3295)
2022-08-27 13:05:57 +00:00
84 changed files with 4204 additions and 253 deletions
+13
View File
@@ -291,7 +291,20 @@ link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
# Installation
################################################################################
include(ProjInstallPath)
# By default GNUInstallDirs will use the upper case project name
# for CMAKE_INSTALL_DOCDIR, resulting in something like share/doc/PROJ
# instead of share/doc/proj which historically have been the path used
# by the project.
# Here force the use of a lower case project name and reset after
# GNUInstallDirs has done its thing
set(PROJECT_NAME_ORIGINAL "${PROJECT_NAME}")
string(TOLOWER "${PROJECT_NAME}" PROJECT_NAME)
include(GNUInstallDirs)
set(PROJECT_NAME "${PROJECT_NAME_ORIGINAL}")
set(PROJ_DATA_PATH "${CMAKE_INSTALL_FULL_DATADIR}/proj")
################################################################################
+17 -5
View File
@@ -90,7 +90,17 @@ else ()
set (CMAKE_CROSSCOMPILING_STR "OFF")
endif ()
foreach (PROJECT_VARIANT_NAME ${PROJECT_NAME} ${PROJECT_LEGACY_NAME})
# If this is a regular build (PROJECT_SOURCE_DIR == CMAKE_SOURCE_DIR), export legacy files by default
# Otherwise, this is embedded in another project, only export PROJ target
# cf https://github.com/OSGeo/gdal/issues/5646
string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}" DEFAULT_VAL)
option(INSTALL_LEGACY_CMAKE_FILES "Install PROJ4 legacy target CMake files" ${DEFAULT_VAL})
set(PROJECT_LIST ${PROJECT_NAME})
if (INSTALL_LEGACY_CMAKE_FILES)
set(PROJECT_LIST "${PROJECT_LIST}" "${PROJECT_LEGACY_NAME}")
endif ()
foreach (PROJECT_VARIANT_NAME IN LISTS PROJECT_LIST)
string (TOLOWER "${PROJECT_VARIANT_NAME}" PROJECT_VARIANT_LOWER)
set (CMAKECONFIGSUBDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_VARIANT_LOWER}")
# proj-config.cmake for the install tree. It's installed in
@@ -117,9 +127,11 @@ foreach (PROJECT_VARIANT_NAME ${PROJECT_NAME} ${PROJECT_LEGACY_NAME})
NAMESPACE ${PROJECT_NAME}::
FILE ${PROJECT_NAME_LOWER}-targets.cmake
DESTINATION "${CMAKECONFIGSUBDIR}")
install(EXPORT targets
NAMESPACE ${PROJECT_LEGACY_NAME}::
FILE ${PROJECT_LEGACY_LOWER}-targets.cmake
DESTINATION "${CMAKECONFIGSUBDIR}")
if (INSTALL_LEGACY_CMAKE_FILES)
install(EXPORT targets
NAMESPACE ${PROJECT_LEGACY_NAME}::
FILE ${PROJECT_LEGACY_LOWER}-targets.cmake
DESTINATION "${CMAKECONFIGSUBDIR}")
endif()
endforeach ()
+3 -1
View File
@@ -13,7 +13,9 @@ include(CheckFunctionExists)
# if C flags have -Werror, temporarily remove these while running some checks
string(FIND "${CMAKE_C_FLAGS}" "-Werror" FIND_WERROR)
if(FIND_WERROR GREATER_EQUAL 0)
string(REPLACE "-Werror" "" _tmp_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
# we must be careful about not matching -Werror=something, so let's append
# a space at the end of CMAKE_C_FLAGS and match -Werror with a trailing space
string(REPLACE "-Werror " " " _tmp_CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ")
set(_prev_CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_C_FLAGS "${_tmp_CMAKE_C_FLAGS}")
endif()
+2
View File
@@ -7747,3 +7747,5 @@ INSERT INTO "alias_name" VALUES('geodetic_crs','EPSG','20040','SIRGAS-Chile real
INSERT INTO "alias_name" VALUES('geodetic_crs','EPSG','20040','SIRGAS-Chile epoch 2021.00','EPSG');
INSERT INTO "alias_name" VALUES('geodetic_crs','EPSG','20041','SIRGAS-Chile realización 5','EPSG');
INSERT INTO "alias_name" VALUES('geodetic_crs','EPSG','20041','SIRGAS-Chile epoch 2021.00','EPSG');
INSERT INTO "alias_name" VALUES('projected_crs','EPSG','20050','NAD83(2011) / Amtrak CS21 (ft)','EPSG');
INSERT INTO "alias_name" VALUES('projected_crs','EPSG','20050','ACS21 (ft)','EPSG');
+2 -2
View File
@@ -73,14 +73,14 @@ FOR EACH ROW BEGIN
AND g1.source_crs_code = g2.source_crs_code
AND g1.target_crs_auth_name = g2.target_crs_auth_name
AND g1.target_crs_code = g2.target_crs_code
WHERE g1.auth_name = 'PROJ' AND g1.code NOT LIKE '%_RESTRICTED_TO_VERTCRS%' AND g2.auth_name = 'EPSG')
WHERE g1.auth_name = 'PROJ' AND g1.code NOT LIKE '%_RESTRICTED_TO_VERTCRS%' AND g2.auth_name = 'EPSG' AND g2.deprecated = 0)
OR EXISTS (SELECT 1 FROM grid_transformation g1
JOIN grid_transformation g2
ON g1.source_crs_auth_name = g2.target_crs_auth_name
AND g1.source_crs_code = g2.target_crs_code
AND g1.target_crs_auth_name = g1.source_crs_auth_name
AND g1.target_crs_code = g1.source_crs_code
WHERE g1.auth_name = 'PROJ' AND g1.code NOT LIKE '%_RESTRICTED_TO_VERTCRS%' AND g2.auth_name = 'EPSG');
WHERE g1.auth_name = 'PROJ' AND g1.code NOT LIKE '%_RESTRICTED_TO_VERTCRS%' AND g2.auth_name = 'EPSG' AND g2.deprecated = 0);
SELECT RAISE(ABORT, 'Arg! there is now a EPSG:102100 object. Hack in createFromUserInput() will no longer work')
WHERE EXISTS(SELECT 1 FROM crs_view WHERE auth_name = 'EPSG' AND code = '102100');
+5 -1
View File
@@ -1836,6 +1836,10 @@ INSERT INTO "conversion" VALUES('EPSG','10131','SPCS83 Alabama East zone (meters
INSERT INTO "usage" VALUES('EPSG','11103','conversion','EPSG','10131','EPSG','2154','EPSG','1142');
INSERT INTO "conversion" VALUES('EPSG','10132','SPCS83 Alabama West zone (meters)','','EPSG','9807','Transverse Mercator','EPSG','8801','Latitude of natural origin',30.0,'EPSG','9110','EPSG','8802','Longitude of natural origin',-87.3,'EPSG','9110','EPSG','8805','Scale factor at natural origin',0.999933333,'EPSG','9201','EPSG','8806','False easting',600000.0,'EPSG','9001','EPSG','8807','False northing',0.0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
INSERT INTO "usage" VALUES('EPSG','11104','conversion','EPSG','10132','EPSG','2155','EPSG','1142');
INSERT INTO "conversion" VALUES('EPSG','10147','Brisbane City Survey Grid 2020','Replaces Brisbane City Survey Grid 02 (code 17363) from 2022-07-01.','EPSG','9807','Transverse Mercator','EPSG','8801','Latitude of natural origin',-28.0,'EPSG','9102','EPSG','8802','Longitude of natural origin',153.0,'EPSG','9102','EPSG','8805','Scale factor at natural origin',0.99999,'EPSG','9201','EPSG','8806','False easting',150000.0,'EPSG','9001','EPSG','8807','False northing',200000.0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
INSERT INTO "usage" VALUES('EPSG','18476','conversion','EPSG','10147','EPSG','2990','EPSG','1029');
INSERT INTO "conversion" VALUES('EPSG','10148','Amtrak North East Corridor Coordinate System 2021 (International feet)','If using Hotine Oblique Mercator (variant A) method (code 9812), FE = -16,589,516.268572...ft, FN = -9,803,584.307096...ft.','EPSG','9815','Hotine Oblique Mercator (variant B)','EPSG','8811','Latitude of projection centre',40.5,'EPSG','9110','EPSG','8812','Longitude of projection centre',-74.0,'EPSG','9110','EPSG','8813','Azimuth of initial line',58.0,'EPSG','9110','EPSG','8814','Angle from Rectified to Skew Grid',58.0,'EPSG','9110','EPSG','8815','Scale factor on initial line',0.99999,'EPSG','9201','EPSG','8816','Easting at projection centre',1500000.0,'EPSG','9002','EPSG','8817','Northing at projection centre',1500000.0,'EPSG','9002',0);
INSERT INTO "usage" VALUES('EPSG','18487','conversion','EPSG','10148','EPSG','4669','EPSG','1141');
INSERT INTO "conversion" VALUES('EPSG','10201','Arizona Coordinate System East zone','','EPSG','9807','Transverse Mercator','EPSG','8801','Latitude of natural origin',31.0,'EPSG','9110','EPSG','8802','Longitude of natural origin',-110.1,'EPSG','9110','EPSG','8805','Scale factor at natural origin',0.9999,'EPSG','9201','EPSG','8806','False easting',500000.0,'EPSG','9003','EPSG','8807','False northing',0.0,'EPSG','9003',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
INSERT INTO "usage" VALUES('EPSG','11105','conversion','EPSG','10201','EPSG','2167','EPSG','1142');
INSERT INTO "conversion" VALUES('EPSG','10202','Arizona Coordinate System Central zone','','EPSG','9807','Transverse Mercator','EPSG','8801','Latitude of natural origin',31.0,'EPSG','9110','EPSG','8802','Longitude of natural origin',-111.55,'EPSG','9110','EPSG','8805','Scale factor at natural origin',0.9999,'EPSG','9201','EPSG','8806','False easting',500000.0,'EPSG','9003','EPSG','8807','False northing',0.0,'EPSG','9003',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
@@ -4112,7 +4116,7 @@ INSERT INTO "conversion" VALUES('EPSG','17361','Vicgrid','May also be used to di
INSERT INTO "usage" VALUES('EPSG','12537','conversion','EPSG','17361','EPSG','2285','EPSG','1135');
INSERT INTO "conversion" VALUES('EPSG','17362','Geoscience Australia Standard National Scale Lambert Projection','Created by Australian Geological Survey Organisation prior to incorporation into Auslig. See also ACRESLC (proj code 4460).','EPSG','9802','Lambert Conic Conformal (2SP)','EPSG','8821','Latitude of false origin',0.0,'EPSG','9102','EPSG','8822','Longitude of false origin',134.0,'EPSG','9102','EPSG','8823','Latitude of 1st standard parallel',-18.0,'EPSG','9102','EPSG','8824','Latitude of 2nd standard parallel',-36.0,'EPSG','9102','EPSG','8826','Easting at false origin',0.0,'EPSG','9001','EPSG','8827','Northing at false origin',0.0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL,0);
INSERT INTO "usage" VALUES('EPSG','12538','conversion','EPSG','17362','EPSG','2575','EPSG','1236');
INSERT INTO "conversion" VALUES('EPSG','17363','Brisbane City Survey Grid 02','','EPSG','9807','Transverse Mercator','EPSG','8801','Latitude of natural origin',-28.0,'EPSG','9102','EPSG','8802','Longitude of natural origin',153.0,'EPSG','9102','EPSG','8805','Scale factor at natural origin',0.99999,'EPSG','9201','EPSG','8806','False easting',50000.0,'EPSG','9001','EPSG','8807','False northing',100000.0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
INSERT INTO "conversion" VALUES('EPSG','17363','Brisbane City Survey Grid 02','Replaced by BCGS2020 (code 10147) from 2022-07-01.','EPSG','9807','Transverse Mercator','EPSG','8801','Latitude of natural origin',-28.0,'EPSG','9102','EPSG','8802','Longitude of natural origin',153.0,'EPSG','9102','EPSG','8805','Scale factor at natural origin',0.99999,'EPSG','9201','EPSG','8806','False easting',50000.0,'EPSG','9001','EPSG','8807','False northing',100000.0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0);
INSERT INTO "usage" VALUES('EPSG','12539','conversion','EPSG','17363','EPSG','2990','EPSG','1029');
INSERT INTO "conversion" VALUES('EPSG','17364','New South Wales Lambert','','EPSG','9802','Lambert Conic Conformal (2SP)','EPSG','8821','Latitude of false origin',-33.25,'EPSG','9102','EPSG','8822','Longitude of false origin',147.0,'EPSG','9102','EPSG','8823','Latitude of 1st standard parallel',-30.75,'EPSG','9102','EPSG','8824','Latitude of 2nd standard parallel',-35.75,'EPSG','9102','EPSG','8826','Easting at false origin',9300000.0,'EPSG','9001','EPSG','8827','Northing at false origin',4500000.0,'EPSG','9001',NULL,NULL,NULL,NULL,NULL,NULL,0);
INSERT INTO "usage" VALUES('EPSG','12540','conversion','EPSG','17364','EPSG','3139','EPSG','1135');
+44
View File
@@ -144,6 +144,50 @@ UPDATE grid_transformation SET accuracy = 2.0 WHERE auth_name = 'EPSG' AND code
UPDATE grid_transformation SET accuracy = 2.0 WHERE auth_name = 'EPSG' AND code = '1462';
-- Create a PROJ copy of EPSG:9123 "NAD83(CSRS) to CGVD28 height (1)" by
-- removing the deprecation flag.
-- Having a transformation from/to CGVD28 using the "generic" NAD83(CSRS) is much
-- more convenient for low accuracy cases like https://github.com/OSGeo/PROJ/issues/3328
INSERT INTO grid_transformation SELECT
'PROJ' AS auth_name,
'EPSG_9123' AS code,
name,
description || ' Imported from EPSG:9123 with deprecation flag removed by PROJ' AS description,
method_auth_name,
method_code,
method_name,
source_crs_auth_name,
source_crs_code,
target_crs_auth_name,
target_crs_code,
accuracy,
grid_param_auth_name,
grid_param_code,
grid_param_name,
grid_name,
grid2_param_auth_name,
grid2_param_code,
grid2_param_name,
grid2_name,
interpolation_crs_auth_name,
interpolation_crs_code,
operation_version,
0 AS deprecated
FROM grid_transformation WHERE auth_name = 'EPSG' AND code = '9123';
INSERT INTO usage SELECT
'PROJ' AS auth_name,
'USAGE_PROJ_EPSG_9123' AS code,
object_table_name,
'PROJ' AS object_auth_name,
'EPSG_9123' AS object_code,
extent_auth_name,
extent_code,
scope_auth_name,
scope_code
FROM usage WHERE object_table_name = 'grid_transformation' AND object_auth_name = 'EPSG' AND object_code = '9123';
-- Define the allowed authorities, and their precedence, when researching a
-- coordinate operation
+23 -22
View File
@@ -213,7 +213,7 @@ INSERT INTO "extent" VALUES('EPSG','1233','Tokelau','Tokelau - onshore and offsh
INSERT INTO "extent" VALUES('EPSG','1234','Tonga','Tonga - onshore and offshore.',-25.68,-14.14,-179.08,-171.28,0);
INSERT INTO "extent" VALUES('EPSG','1235','Trinidad and Tobago','Trinidad and Tobago - onshore and offshore.',9.83,12.34,-62.09,-57.28,0);
INSERT INTO "extent" VALUES('EPSG','1236','Tunisia','Tunisia - onshore and offshore.',30.23,38.41,7.49,13.67,0);
INSERT INTO "extent" VALUES('EPSG','1237','Turkey','Turkey - onshore and offshore.',34.42,43.45,25.62,44.83,0);
INSERT INTO "extent" VALUES('EPSG','1237','Turkey','Türkiye (Turkey) - onshore and offshore.',34.42,43.45,25.62,44.83,0);
INSERT INTO "extent" VALUES('EPSG','1238','Turkmenistan','Turkmenistan - onshore and offshore.',35.14,42.8,51.3,66.68,0);
INSERT INTO "extent" VALUES('EPSG','1239','Turks and Caicos Islands','Turks and Caicos Islands - onshore and offshore.',20.54,25.07,-72.82,-67.66,0);
INSERT INTO "extent" VALUES('EPSG','1240','Tuvalu','Tuvalu - onshore and offshore. Funafuti, Nanumanga, Nui, Nanomea, Nurakita, Niutao, Nukufetau, Nukulaelae, and Vaitupu.',-13.24,-4.0,172.73,-176.71,0);
@@ -272,7 +272,7 @@ INSERT INTO "extent" VALUES('EPSG','1292','Argentina - Neuquen province','Argent
INSERT INTO "extent" VALUES('EPSG','1293','Brazil - Corrego Alegre 1970-1972','Brazil - onshore - west of 54°W and south of 18°S; also south of 15°S between 54°W and 42°W; also east of 42°W.',-33.78,-2.68,-58.16,-34.74,0);
INSERT INTO "extent" VALUES('EPSG','1294','Portugal - mainland - onshore','Portugal - mainland - onshore.',36.95,42.16,-9.56,-6.19,0);
INSERT INTO "extent" VALUES('EPSG','1295','Germany - DHDN','Germany - onshore - Baden-Wurtemberg, Bayern, Hessen, Niedersachsen, Nordrhein-Westfalen, Rheinland-Pfalz, Saarland, Schleswig-Holstein. Also former DDR states of Sachsen and Thuringen by transformation.',47.27,55.06,5.87,15.03,1);
INSERT INTO "extent" VALUES('EPSG','1296','Europe - ED50 by country','Europe - west: Andorra; Cyprus; Denmark - onshore and offshore; Faroe Islands - onshore; France - offshore; Germany - offshore North Sea; Gibraltar; Greece - offshore; Israel - offshore; Italy including San Marino and Vatican City State; Ireland offshore; Malta; Netherlands - offshore; North Sea; Norway including Svalbard - onshore and offshore; Portugal - mainland - offshore; Spain - onshore; Turkey - onshore and offshore; United Kingdom UKCS offshore east of 6°W including Channel Islands (Guernsey and Jersey). Egypt - Western Desert; Iraq - onshore; Jordan.',25.71,84.73,-16.1,48.61,0);
INSERT INTO "extent" VALUES('EPSG','1296','Europe - ED50 by country','Europe - west: Andorra; Cyprus; Denmark - onshore and offshore; Faroe Islands - onshore; France - offshore; Germany - offshore North Sea; Gibraltar; Greece - offshore; Israel - offshore; Italy including San Marino and Vatican City State; Ireland offshore; Malta; Netherlands - offshore; North Sea; Norway including Svalbard - onshore and offshore; Portugal - mainland - offshore; Spain - onshore; Türkiye (Turkey) - onshore and offshore; United Kingdom - UKCS offshore east of 6°W including Channel Islands (Guernsey and Jersey). Egypt - Western Desert; Iraq - onshore; Jordan.',25.71,84.73,-16.1,48.61,0);
INSERT INTO "extent" VALUES('EPSG','1297','Europe - west','Europe - west.',34.88,84.73,-10.56,38.01,0);
INSERT INTO "extent" VALUES('EPSG','1298','Europe - ETRF by country','Europe - onshore and offshore: Albania; Andorra; Austria; Belgium; Bosnia and Herzegovina; Bulgaria; Croatia; Cyprus; Czechia; Denmark; Estonia; Faroe Islands; Finland; France; Germany; Gibraltar; Greece; Hungary; Ireland; Italy; Kosovo; Latvia; Liechtenstein; Lithuania; Luxembourg; Malta; Moldova; Monaco; Montenegro; Netherlands; North Macedonia; Norway including Svalbard and Jan Mayen; Poland; Portugal; Romania; San Marino; Serbia; Slovakia; Slovenia; Spain; Sweden; Switzerland; United Kingdom (UK) including Channel Islands and Isle of Man; Vatican City State.',32.88,84.73,-16.1,40.18,0);
INSERT INTO "extent" VALUES('EPSG','1299','Europe - EVRF2000','Europe - onshore - Andorra; Austria; Belgium; Bosnia and Herzegovina; Croatia; Czechia; Denmark; Estonia; Finland; France - mainland; Germany; Gibraltar; Hungary; Italy - mainland and Sicily; Latvia; Liechtenstein; Lithuania; Luxembourg; Netherlands; Norway; Poland; Portugal - mainland; Romania; San Marino; Slovakia; Slovenia; Spain - mainland; Sweden; Switzerland; United Kingdom (UK) - Great Britain mainland; Vatican City State.',35.95,71.21,-9.56,31.59,0);
@@ -500,13 +500,13 @@ INSERT INTO "extent" VALUES('EPSG','1520','Poland - west of 16.5°E','Poland - o
INSERT INTO "extent" VALUES('EPSG','1521','Poland - 16.5°E to 19.5°E','Poland - onshore and offshore between 16°30''E and 19°30''E.',49.39,55.93,16.5,19.5,0);
INSERT INTO "extent" VALUES('EPSG','1522','Poland - 19.5°E to 22.5°E','Poland - onshore and offshore between 19°30''E and 22°30''E.',49.09,54.55,19.5,22.5,0);
INSERT INTO "extent" VALUES('EPSG','1523','Poland - east of 22.5°E','Poland - east of 22°30''E.',49.0,54.41,22.5,24.15,0);
INSERT INTO "extent" VALUES('EPSG','1524','Turkey - west of 28.5°E onshore','Turkey west of 28°30''E, onshore.',36.5,42.11,25.62,28.5,0);
INSERT INTO "extent" VALUES('EPSG','1525','Turkey - 28.5°E to 31.5°E onshore','Turkey between 28°30''E and 31°30''E, onshore.',36.06,41.46,28.5,31.5,0);
INSERT INTO "extent" VALUES('EPSG','1526','Turkey - 31.5°E to 34.5°E onshore','Turkey between 31°30''E and 34°30''E, onshore.',35.97,42.07,31.5,34.5,0);
INSERT INTO "extent" VALUES('EPSG','1527','Turkey - 34.5°E to 37.5°E onshore','Turkey between 34°30''E and 37°30''E, onshore.',35.81,42.15,34.5,37.5,0);
INSERT INTO "extent" VALUES('EPSG','1528','Turkey - 37.5°E to 40.5°E onshore','Turkey between 37°30''E and 40°30''E, onshore.',36.66,41.19,37.5,40.5,0);
INSERT INTO "extent" VALUES('EPSG','1529','Turkey - 40.5°E to 43.5°E onshore','Turkey between 40°30''E and 43°30''E, onshore.',37.02,41.6,40.5,43.5,0);
INSERT INTO "extent" VALUES('EPSG','1530','Turkey - east of 43.5°E','Turkey east of 43°30''E.',36.97,41.02,43.5,44.83,0);
INSERT INTO "extent" VALUES('EPSG','1524','Turkey - west of 28.5°E onshore','Türkiye (Turkey) - west of 28°30''E, onshore.',36.5,42.11,25.62,28.5,0);
INSERT INTO "extent" VALUES('EPSG','1525','Turkey - 28.5°E to 31.5°E onshore','Türkiye (Turkey) - between 28°30''E and 31°30''E, onshore.',36.06,41.46,28.5,31.5,0);
INSERT INTO "extent" VALUES('EPSG','1526','Turkey - 31.5°E to 34.5°E onshore','Türkiye (Turkey) - between 31°30''E and 34°30''E, onshore.',35.97,42.07,31.5,34.5,0);
INSERT INTO "extent" VALUES('EPSG','1527','Turkey - 34.5°E to 37.5°E onshore','Türkiye (Turkey) - between 34°30''E and 37°30''E, onshore.',35.81,42.15,34.5,37.5,0);
INSERT INTO "extent" VALUES('EPSG','1528','Turkey - 37.5°E to 40.5°E onshore','Türkiye (Turkey) - between 37°30''E and 40°30''E, onshore.',36.66,41.19,37.5,40.5,0);
INSERT INTO "extent" VALUES('EPSG','1529','Turkey - 40.5°E to 43.5°E onshore','Türkiye (Turkey) - between 40°30''E and 43°30''E, onshore.',37.02,41.6,40.5,43.5,0);
INSERT INTO "extent" VALUES('EPSG','1530','Turkey - east of 43.5°E','Türkiye (Turkey) - east of 43°30''E.',36.97,41.02,43.5,44.83,0);
INSERT INTO "extent" VALUES('EPSG','1531','Canada - Maritime Provinces - west of 66°W','Canada - New Brunswick and Nova Scotia - west of 66°W.',43.64,48.07,-69.0,-66.0,0);
INSERT INTO "extent" VALUES('EPSG','1532','Canada - Maritime Provinces - east of 66°W','Canada - New Brunswick and Nova Scotia east of 66°W; Prince Edward Island.',43.41,47.98,-66.0,-59.73,0);
INSERT INTO "extent" VALUES('EPSG','1533','Canada - Prince Edward Island','Canada - Prince Edward Island.',45.9,47.09,-64.49,-61.9,0);
@@ -614,10 +614,10 @@ INSERT INTO "extent" VALUES('EPSG','1634','Europe - 0°E to 6°E and ED50 by cou
INSERT INTO "extent" VALUES('EPSG','1635','Europe - 6°E to 12°E and ED50 by country','Europe - between 6°E and 12°E - Denmark - onshore and offshore; France - offshore; Germany offshore; Italy - onshore and offshore; Netherlands offshore; Norway including Svalbard - onshore and offshore.',36.53,84.33,5.99,12.01,0);
INSERT INTO "extent" VALUES('EPSG','1636','Europe - 12°E to 18°E and ED50 by country','Europe - between 12°E and 18°E onshore and offshore - Denmark (including Bornholm); Italy including San Marino and Vatican City State; Malta; Norway including Svalbard.',34.49,84.42,12.0,18.01,0);
INSERT INTO "extent" VALUES('EPSG','1637','Europe - 18°E to 24°E and ED50 by country','Europe - between 18°E and 24°E - Greece - offshore; Italy - onshore and offshore; Norway including Svalbard - onshore and offshore.',33.59,84.54,17.99,24.01,0);
INSERT INTO "extent" VALUES('EPSG','1638','Europe - 24°E to 30°E and ED50 by country','Europe - between 24°E and 30°E - Greece - offshore; Norway including Svalbard - onshore and offshore; Turkey - onshore and offshore. Egypt - Western Desert.',25.71,84.73,24.0,30.01,0);
INSERT INTO "extent" VALUES('EPSG','1639','Europe - 30°E to 36°E and ED50 by country','Europe - between 30°E and 36°E - Israel - offshore; Jordan; Norway including Svalbard - onshore and offshore; Turkey - onshore and offshore.',29.19,84.7,30.0,36.01,0);
INSERT INTO "extent" VALUES('EPSG','1640','Europe - 36°E to 42°E and ED50 by country','Europe - between 36°E and 42°E - Jordan; Norway including Svalbard - offshore; Turkey onshore and offshore.',29.18,79.07,36.0,42.0,0);
INSERT INTO "extent" VALUES('EPSG','1641','Europe - 42°E to 48°E and ED50 by country','Europe - between 42°E and 48°E - Turkey.',36.97,41.6,42.0,44.83,0);
INSERT INTO "extent" VALUES('EPSG','1638','Europe - 24°E to 30°E and ED50 by country','Europe - between 24°E and 30°E - Greece - offshore; Norway including Svalbard - onshore and offshore; Türkiye (Turkey) - onshore and offshore. Egypt - Western Desert.',25.71,84.73,24.0,30.01,0);
INSERT INTO "extent" VALUES('EPSG','1639','Europe - 30°E to 36°E and ED50 by country','Europe - between 30°E and 36°E - Israel - offshore; Jordan; Norway including Svalbard - onshore and offshore; Türkiye (Turkey) - onshore and offshore.',29.19,84.7,30.0,36.0,0);
INSERT INTO "extent" VALUES('EPSG','1640','Europe - 36°E to 42°E and ED50 by country','Europe - between 36°E and 42°E - Jordan; Norway including Svalbard - offshore; Türkiye (Turkey) - onshore and offshore.',29.18,79.07,36.0,42.0,0);
INSERT INTO "extent" VALUES('EPSG','1641','Europe - 42°E to 48°E and ED50 by country','Europe - between 42°E and 48°E - Türkiye (Turkey).',36.97,41.6,42.0,44.83,0);
INSERT INTO "extent" VALUES('EPSG','1642','Egypt - east of 33°E onshore','Egypt - east of 33°E - onshore plus offshore Gulf of Suez.',21.97,31.36,33.0,36.95,0);
INSERT INTO "extent" VALUES('EPSG','1643','Egypt - 29°E to 33°E','Egypt - onshore between 29°E and 33°E, offshore Mediterranean east of 29°E and offshore Gulf of Suez.',21.99,33.82,29.0,34.27,0);
INSERT INTO "extent" VALUES('EPSG','1644','Egypt - west of 29°E; north of 28°11''N','Egypt - onshore west of 29°E and north of approximately 28°11''N.',28.18,31.68,24.7,29.0,0);
@@ -1044,13 +1044,13 @@ INSERT INTO "extent" VALUES('EPSG','2064','World - N hemisphere - 12°E to 18°E
INSERT INTO "extent" VALUES('EPSG','2065','World - S hemisphere - 12°E to 18°E - by country','Between 12°E and 18°E, southern hemisphere between 80°S and equator, onshore and offshore. Angola. Congo. Democratic Republic of the Congo (Zaire). Gabon. Namibia. South Africa.',-80.0,0.0,12.0,18.0,0);
INSERT INTO "extent" VALUES('EPSG','2066','World - N hemisphere - 18°E to 24°E - by country','Between 18°E and 24°E, northern hemisphere between equator and 84°N, onshore and offshore. Albania. Belarus. Bosnia and Herzegovina. Bulgaria. Central African Republic. Chad. Croatia. Democratic Republic of the Congo (Zaire). Estonia. Finland. Greece. Hungary. Italy. Kosovo. Latvia. Libya. Lithuania. Montenegro. North Macedonia. Norway, including Svalbard and Bjornoys. Poland. Romania. Russian Federation. Serbia. Slovakia. Sudan. Sweden. Ukraine.',0.0,84.0,18.0,24.0,0);
INSERT INTO "extent" VALUES('EPSG','2067','World - S hemisphere - 18°E to 24°E - by country','Between 18°E and 24°E, southern hemisphere between 80°S and equator, onshore and offshore. Angola. Botswana. Democratic Republic of the Congo (Zaire). Namibia. South Africa. Zambia.',-80.0,0.0,18.0,24.0,0);
INSERT INTO "extent" VALUES('EPSG','2068','World - N hemisphere - 24°E to 30°E - by country','Between 24°E and 30°E, northern hemisphere between equator and 84°N, onshore and offshore. Belarus. Bulgaria. Central African Republic. Democratic Republic of the Congo (Zaire). Egypt. Estonia. Finland. Greece. Latvia. Lesotho. Libya. Lithuania. Moldova. Norway. Poland. Romania. Russian Federation. Sudan. Svalbard. Turkey. Uganda. Ukraine.',0.0,84.0,24.0,30.0,0);
INSERT INTO "extent" VALUES('EPSG','2068','World - N hemisphere - 24°E to 30°E - by country','Between 24°E and 30°E, northern hemisphere between equator and 84°N, onshore and offshore. Belarus. Bulgaria. Central African Republic. Democratic Republic of the Congo (Zaire). Egypt. Estonia. Finland. Greece. Latvia. Lesotho. Libya. Lithuania. Moldova. Norway. Poland. Romania. Russian Federation. Sudan. Svalbard. Türkiye (Turkey). Uganda. Ukraine.',0.0,84.0,24.0,30.0,0);
INSERT INTO "extent" VALUES('EPSG','2069','World - S hemisphere - 24°E to 30°E - by country','Between 24°E and 30°E, southern hemisphere between 80°S and equator, onshore and offshore. Botswana. Burundi. Democratic Republic of the Congo (Zaire). Rwanda. South Africa. Tanzania. Uganda. Zambia. Zimbabwe.',-80.0,0.0,24.0,30.0,0);
INSERT INTO "extent" VALUES('EPSG','2070','World - N hemisphere - 30°E to 36°E - by country','Between 30°E and 36°E, northern hemisphere between equator and 84°N, onshore and offshore. Belarus. Cyprus. Egypt. Ethiopia. Finland. Israel. Jordan. Kenya. Lebanon. Moldova. Norway. Russian Federation. Saudi Arabia. Sudan. Syria. Turkey. Uganda. Ukraine.',0.0,84.0,30.0,36.0,0);
INSERT INTO "extent" VALUES('EPSG','2070','World - N hemisphere - 30°E to 36°E - by country','Between 30°E and 36°E, northern hemisphere between equator and 84°N, onshore and offshore. Belarus. Cyprus. Egypt. Ethiopia. Finland. Israel. Jordan. Kenya. Lebanon. Moldova. Norway. Russian Federation. Saudi Arabia. Sudan. Syria. Türkiye (Turkey). Uganda. Ukraine.',0.0,84.0,30.0,36.0,0);
INSERT INTO "extent" VALUES('EPSG','2071','World - S hemisphere - 30°E to 36°E - by country','Between 30°E and 36°E, southern hemisphere between 80°S and equator, onshore and offshore. Burundi. Eswatini (Swaziland). Kenya. Malawi. Mozambique. Rwanda. South Africa. Tanzania. Uganda. Zambia. Zimbabwe.',-80.0,0.0,30.0,36.0,0);
INSERT INTO "extent" VALUES('EPSG','2072','World - N hemisphere - 36°E to 42°E - by country','Between 36°E and 42°E, northern hemisphere between equator and 84°N, onshore and offshore. Djibouti. Egypt. Eritrea. Ethiopia. Georgia. Iraq. Jordan. Kenya. Lebanon. Russian Federation. Saudi Arabia. Somalia. Sudan. Syria. Turkey. Ukraine.',0.0,84.0,36.0,42.0,0);
INSERT INTO "extent" VALUES('EPSG','2072','World - N hemisphere - 36°E to 42°E - by country','Between 36°E and 42°E, northern hemisphere between equator and 84°N, onshore and offshore. Djibouti. Egypt. Eritrea. Ethiopia. Georgia. Iraq. Jordan. Kenya. Lebanon. Russian Federation. Saudi Arabia. Somalia. Sudan. Syria. Türkiye (Turkey). Ukraine.',0.0,84.0,36.0,42.0,0);
INSERT INTO "extent" VALUES('EPSG','2073','World - S hemisphere - 36°E to 42°E - by country','Between 36°E and 42°E, southern hemisphere between 80°S and equator, onshore and offshore. Kenya. Mozambique. Tanzania.',-80.0,0.0,36.0,42.0,0);
INSERT INTO "extent" VALUES('EPSG','2074','World - N hemisphere - 42°E to 48°E - by country','Between 42°E and 48°E, northern hemisphere between equator and 84°N, onshore and offshore. Armenia. Azerbaijan. Djibouti. Eritrea. Ethiopia. Georgia. Islamic Republic of Iran. Iraq. kazakhstan. Kuwait. Russian Federation. Saudi Arabia. Somalia. Turkey. Yemen.',0.0,84.0,42.0,48.0,0);
INSERT INTO "extent" VALUES('EPSG','2074','World - N hemisphere - 42°E to 48°E - by country','Between 42°E and 48°E, northern hemisphere between equator and 84°N, onshore and offshore. Armenia. Azerbaijan. Djibouti. Eritrea. Ethiopia. Georgia. Islamic Republic of Iran. Iraq. kazakhstan. Kuwait. Russian Federation. Saudi Arabia. Somalia. Türkiye (Turkey). Yemen.',0.0,84.0,42.0,48.0,0);
INSERT INTO "extent" VALUES('EPSG','2075','World - S hemisphere - 42°E to 48°E - by country','Between 42°E and 48°E, southern hemisphere between 80°S and equator, onshore and offshore. Madagascar.',-80.0,0.0,42.0,48.0,0);
INSERT INTO "extent" VALUES('EPSG','2076','World - N hemisphere - 48°E to 54°E - by country','Between 48°E and 54°E, northern hemisphere between equator and 84°N, onshore and offshore. Azerbaijan. Bahrain. Islamic Republic of Iran. Iraq. Kazakhstan. Kuwait. Oman. Qatar. Russian Federation. Saudi Arabia. Somalia. Turkmenistan. United Arab Emirates. Yemen.',0.0,84.0,48.0,54.0,0);
INSERT INTO "extent" VALUES('EPSG','2077','World - S hemisphere - 48°E to 54°E - by country','Between 48°E and 54°E, southern hemisphere between 80°S and equator, onshore and offshore. Madagascar.',-80.0,0.0,48.0,54.0,0);
@@ -1806,7 +1806,7 @@ INSERT INTO "extent" VALUES('EPSG','2826','Africa - South Sudan and Sudan - west
INSERT INTO "extent" VALUES('EPSG','2827','Africa - South Sudan and Sudan - 24°E to 30°E','South Sudan and Sudan - between 24°E and 30°E.',4.21,22.01,23.99,30.01,0);
INSERT INTO "extent" VALUES('EPSG','2828','Guadeloupe - St Martin and St Barthelemy - onshore','Guadeloupe - onshore - St Martin and St Barthélemy islands.',17.82,18.17,-63.21,-62.73,0);
INSERT INTO "extent" VALUES('EPSG','2829','Guadeloupe - Grande-Terre and surrounding islands - onshore','Guadeloupe - onshore - Basse-Terre, Grande-Terre, La Desirade, Marie-Galante, Les Saintes.',15.8,16.55,-61.85,-60.97,0);
INSERT INTO "extent" VALUES('EPSG','2830','World (by country)','World: Afghanistan, Albania, Algeria, American Samoa, Andorra, Angola, Anguilla, Antarctica, Antigua and Barbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belgium, Belgium, Belize, Benin, Bermuda, Bhutan, Bolivia, Bonaire, Saint Eustasius and Saba, Bosnia and Herzegovina, Botswana, Bouvet Island, Brazil, British Indian Ocean Territory, British Virgin Islands, Brunei Darussalam, Bulgaria, Burkina Faso, Burundi, Cambodia, Cameroon, Canada, Cape Verde, Cayman Islands, Central African Republic, Chad, Chile, China, Christmas Island, Cocos (Keeling) Islands, Comoros, Congo, Cook Islands, Costa Rica, Côte d''Ivoire (Ivory Coast), Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, Dominican Republic, East Timor, Ecuador, Egypt, El Salvador, Equatorial Guinea, Eritrea, Estonia, Eswatini (Swaziland), Ethiopia, Falkland Islands (Malvinas), Faroe Islands, Fiji, Finland, France, French Guiana, French Polynesia, French Southern Territories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guinea, Guinea-Bissau, Guyana, Haiti, Heard Island and McDonald Islands, Holy See (Vatican City State), Honduras, China - Hong Kong, Hungary, Iceland, India, Indonesia, Islamic Republic of Iran, Iraq, Ireland, Israel, Italy, Jamaica, Japan, Jordan, Kazakhstan, Kenya, Kiribati, Democratic People''s Republic of Korea (North Korea), Republic of Korea (South Korea), Kosovo, Kuwait, Kyrgyzstan, Lao People''s Democratic Republic (Laos), Latvia, Lebanon, Lesotho, Liberia, Libyan Arab Jamahiriya, Liechtenstein, Lithuania, Luxembourg, China - Macao, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, Marshall Islands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, Federated States of Micronesia, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar (Burma), Namibia, Nauru, Nepal, Netherlands, New Caledonia, New Zealand, Nicaragua, Niger, Nigeria, Niue, Norfolk Island, North Macedonia, Northern Mariana Islands, Norway, Oman, Pakistan, Palau, Panama, Papua New Guinea (PNG), Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, Puerto Rico, Qatar, Reunion, Romania, Russian Federation, Rwanda, St Barthelemy, St Kitts and Nevis, St Helena, Ascension and Tristan da Cunha, St Lucia, St Martin, St Pierre and Miquelon, Saint Vincent and the Grenadines, Samoa, San Marino, Sao Tome and Principe, Saudi Arabia, Senegal, Serbia, Seychelles, Sierra Leone, Singapore, Slovakia (Slovak Republic), Slovenia, St Maarten, Solomon Islands, Somalia, South Africa, South Georgia and the South Sandwich Islands, South Sudan, Spain, Sri Lanka, Sudan, Suriname, Svalbard and Jan Mayen, Sweden, Switzerland, Syrian Arab Republic, Taiwan, Tajikistan, United Republic of Tanzania, Thailand, The Democratic Republic of the Congo (Zaire), Togo, Tokelau, Tonga, Trinidad and Tobago, Tunisia, Turkey, Turkmenistan, Turks and Caicos Islands, Tuvalu, Uganda, Ukraine, United Arab Emirates (UAE), United Kingdom (UK), United States (USA), United States Minor Outlying Islands, Uruguay, Uzbekistan, Vanuatu, Venezuela, Vietnam, US Virgin Islands, Wallis and Futuna, Western Sahara, Yemen, Zambia, Zimbabwe.',-90.0,90.0,-180.0,180.0,0);
INSERT INTO "extent" VALUES('EPSG','2830','World (by country)','World: Afghanistan, Albania, Algeria, American Samoa, Andorra, Angola, Anguilla, Antarctica, Antigua and Barbuda, Argentina, Armenia, Aruba, Australia, Austria, Azerbaijan, Bahamas, Bahrain, Bangladesh, Barbados, Belgium, Belgium, Belize, Benin, Bermuda, Bhutan, Bolivia, Bonaire, Saint Eustasius and Saba, Bosnia and Herzegovina, Botswana, Bouvet Island, Brazil, British Indian Ocean Territory, British Virgin Islands, Brunei Darussalam, Bulgaria, Burkina Faso, Burundi, Cambodia, Cameroon, Canada, Cape Verde, Cayman Islands, Central African Republic, Chad, Chile, China, Christmas Island, Cocos (Keeling) Islands, Comoros, Congo, Cook Islands, Costa Rica, Côte d''Ivoire (Ivory Coast), Croatia, Cuba, Curacao, Cyprus, Czechia, Denmark, Djibouti, Dominica, Dominican Republic, East Timor, Ecuador, Egypt, El Salvador, Equatorial Guinea, Eritrea, Estonia, Eswatini (Swaziland), Ethiopia, Falkland Islands (Malvinas), Faroe Islands, Fiji, Finland, France, French Guiana, French Polynesia, French Southern Territories, Gabon, Gambia, Georgia, Germany, Ghana, Gibraltar, Greece, Greenland, Grenada, Guadeloupe, Guam, Guatemala, Guinea, Guinea-Bissau, Guyana, Haiti, Heard Island and McDonald Islands, Holy See (Vatican City State), Honduras, China - Hong Kong, Hungary, Iceland, India, Indonesia, Islamic Republic of Iran, Iraq, Ireland, Israel, Italy, Jamaica, Japan, Jordan, Kazakhstan, Kenya, Kiribati, Democratic People''s Republic of Korea (North Korea), Republic of Korea (South Korea), Kosovo, Kuwait, Kyrgyzstan, Lao People''s Democratic Republic (Laos), Latvia, Lebanon, Lesotho, Liberia, Libyan Arab Jamahiriya, Liechtenstein, Lithuania, Luxembourg, China - Macao, Madagascar, Malawi, Malaysia, Maldives, Mali, Malta, Marshall Islands, Martinique, Mauritania, Mauritius, Mayotte, Mexico, Federated States of Micronesia, Monaco, Mongolia, Montenegro, Montserrat, Morocco, Mozambique, Myanmar (Burma), Namibia, Nauru, Nepal, Netherlands, New Caledonia, New Zealand, Nicaragua, Niger, Nigeria, Niue, Norfolk Island, North Macedonia, Northern Mariana Islands, Norway, Oman, Pakistan, Palau, Panama, Papua New Guinea (PNG), Paraguay, Peru, Philippines, Pitcairn, Poland, Portugal, Puerto Rico, Qatar, Reunion, Romania, Russian Federation, Rwanda, St Barthelemy, St Kitts and Nevis, St Helena, Ascension and Tristan da Cunha, St Lucia, St Martin, St Pierre and Miquelon, Saint Vincent and the Grenadines, Samoa, San Marino, Sao Tome and Principe, Saudi Arabia, Senegal, Serbia, Seychelles, Sierra Leone, Singapore, Slovakia (Slovak Republic), Slovenia, St Maarten, Solomon Islands, Somalia, South Africa, South Georgia and the South Sandwich Islands, South Sudan, Spain, Sri Lanka, Sudan, Suriname, Svalbard and Jan Mayen, Sweden, Switzerland, Syrian Arab Republic, Taiwan, Tajikistan, United Republic of Tanzania, Thailand, The Democratic Republic of the Congo (Zaire), Togo, Tokelau, Tonga, Trinidad and Tobago, Tunisia, Türkiye (Turkey), Turkmenistan, Turks and Caicos Islands, Tuvalu, Uganda, Ukraine, United Arab Emirates (UAE), United Kingdom (UK), United States (USA), United States Minor Outlying Islands, Uruguay, Uzbekistan, Vanuatu, Venezuela, Vietnam, US Virgin Islands, Wallis and Futuna, Western Sahara, Yemen, Zambia, Zimbabwe.',-90.0,90.0,-180.0,180.0,0);
INSERT INTO "extent" VALUES('EPSG','2831','Canada - Atlantic offshore','Canada - offshore Newfoundland and Labrador, New Brunswick and Nova Scotia - west of 44°W and north of 40°N.',40.0,64.21,-67.75,-43.99,0);
INSERT INTO "extent" VALUES('EPSG','2832','Canada - British Columbia','Canada - British Columbia.',48.25,60.01,-139.04,-114.08,0);
INSERT INTO "extent" VALUES('EPSG','2833','Sweden - 12 00','Sweden - communes west of approximately 12°45''E and south of approximately 60°N. See information source for map.',56.74,60.13,10.93,13.11,0);
@@ -1857,7 +1857,7 @@ INSERT INTO "extent" VALUES('EPSG','2877','Slovenia - Slovenska Bistrica','Slove
INSERT INTO "extent" VALUES('EPSG','2878','Slovenia - Slovenske Gorice','Slovenia - Slovenske Gorice (the Slovene Humpback) with the broad region of Ormoz.',46.29,46.76,15.9,16.3,0);
INSERT INTO "extent" VALUES('EPSG','2879','Germany - offshore North Sea','Germany - offshore North Sea.',53.6,55.92,3.34,8.88,0);
INSERT INTO "extent" VALUES('EPSG','2880','Antarctica - Australian sector north of 80°S','Antarctica - north of 80°S and between 45°E and 136°E and between 142°E and 160°E - Australian sector north of 80°S.',-80.0,-60.0,45.0,160.0,0);
INSERT INTO "extent" VALUES('EPSG','2881','Europe - LCC & LAEA','Europe - European Union (EU) countries and candidates. Europe - onshore and offshore: Albania; Andorra; Austria; Belgium; Bosnia and Herzegovina; Bulgaria; Croatia; Cyprus; Czechia; Denmark; Estonia; Faroe Islands; Finland; France; Germany; Gibraltar; Greece; Hungary; Iceland; Ireland; Italy; Kosovo; Latvia; Liechtenstein; Lithuania; Luxembourg; Malta; Monaco; Montenegro; Netherlands; North Macedonia; Norway including Svalbard and Jan Mayen; Poland; Portugal including Madeira and Azores; Romania; San Marino; Serbia; Slovakia; Slovenia; Spain including Canary Islands; Sweden; Switzerland; Turkey; United Kingdom (UK) including Channel Islands and Isle of Man; Vatican City State.',24.6,84.73,-35.58,44.83,0);
INSERT INTO "extent" VALUES('EPSG','2881','Europe - LCC & LAEA','Europe - European Union (EU) countries and candidates. Europe - onshore and offshore: Albania; Andorra; Austria; Belgium; Bosnia and Herzegovina; Bulgaria; Croatia; Cyprus; Czechia; Denmark; Estonia; Faroe Islands; Finland; France; Germany; Gibraltar; Greece; Hungary; Iceland; Ireland; Italy; Kosovo; Latvia; Liechtenstein; Lithuania; Luxembourg; Malta; Monaco; Montenegro; Netherlands; North Macedonia; Norway including Svalbard and Jan Mayen; Poland; Portugal including Madeira and Azores; Romania; San Marino; Serbia; Slovakia; Slovenia; Spain including Canary Islands; Sweden; Switzerland; Türkiye (Turkey); United Kingdom (UK) including Channel Islands and Isle of Man; Vatican City State.',24.6,84.73,-35.58,44.83,0);
INSERT INTO "extent" VALUES('EPSG','2882','Italy - Adriatic - North Ancona','Italy - offshore - Adriatic Sea - North Ancona.',43.62,45.73,12.22,13.96,0);
INSERT INTO "extent" VALUES('EPSG','2883','Italy - Adriatic - South Ancona / North Gargano','Italy - offshore - Adriatic Sea - South Ancona and North Gargano.',41.95,44.04,13.61,16.14,0);
INSERT INTO "extent" VALUES('EPSG','2884','Italy - Adriatic - South Gargano','Italy - offshore - Adriatic Sea - South Gargano.',40.72,42.28,15.95,18.63,0);
@@ -1872,7 +1872,7 @@ INSERT INTO "extent" VALUES('EPSG','2892','Guadeloupe - Grande-Terre and Basse-T
INSERT INTO "extent" VALUES('EPSG','2893','Guadeloupe - La Desirade - onshore','Guadeloupe - onshore - La Desirade.',16.26,16.38,-61.13,-60.97,0);
INSERT INTO "extent" VALUES('EPSG','2894','Guadeloupe - Marie-Galante - onshore','Guadeloupe - onshore - Marie-Galante.',15.8,16.05,-61.39,-61.13,0);
INSERT INTO "extent" VALUES('EPSG','2895','Guadeloupe - Les Saintes - onshore','Guadeloupe - onshore - Les Saintes.',15.8,15.94,-61.68,-61.52,0);
INSERT INTO "extent" VALUES('EPSG','2896','Asia - Middle East - Israel, Palestine Territory, Turkey - offshore','Israel and Palestine Territory - offshore Mediterranean Sea; Turkey - offshore Black Sea.',31.35,43.45,28.03,41.47,0);
INSERT INTO "extent" VALUES('EPSG','2896','Asia - Middle East - Israel, Palestine Territory, Turkey - offshore','Israel and Palestine Territory - offshore Mediterranean Sea; Türkiye (Turkey) - offshore Black Sea.',31.35,43.45,28.03,41.47,0);
INSERT INTO "extent" VALUES('EPSG','2897','Asia - Middle East - Israel and Palestine Territory offshore','Israel and Palestine Territory - offshore Mediterranean Sea.',31.33,33.1,33.5,35.1,1);
INSERT INTO "extent" VALUES('EPSG','2898','Germany - Berlin','Germany - Berlin.',52.33,52.65,13.09,13.76,0);
INSERT INTO "extent" VALUES('EPSG','2899','Australia - 126°E to 132°E, 8°S to 12°S (SC52) onshore','Australia - onshore mainland between 8°S and 12°S and 126°E and 132°E.',-12.0,-11.07,131.02,132.0,0);
@@ -1966,7 +1966,7 @@ INSERT INTO "extent" VALUES('EPSG','2986','Australia - SA','Australia - South Au
INSERT INTO "extent" VALUES('EPSG','2987','Libya - Amal','Libya - Amal field.',29.1,29.8,20.8,21.4,0);
INSERT INTO "extent" VALUES('EPSG','2988','Channel Islands - Jersey, Les Ecrehos and Les Minquiers','Channel Islands - Jersey, Les Ecrehos and Les Minquiers - onshore and offshore.',48.77,49.44,-2.72,-1.81,0);
INSERT INTO "extent" VALUES('EPSG','2989','Channel Islands - Guernsey, Alderney, Sark','Channel Islands - Guernsey, Alderney, Sark, Herm, Brecqhou, Jethou, Lihou - onshore and offshore.',49.11,50.16,-3.73,-2.02,0);
INSERT INTO "extent" VALUES('EPSG','2990','Australia - Brisbane','Australia - Brisbane area. Local authorities in south-east Queensland: Gold Coast, Logan, Beaudesert, Redcliffe, Redlands, Pine Rivers, Caboolture, Caloundra, Maroochy, Noosa, Maryborough; local authorities in north-east New South Wales: Tweed, Byron, Lismore, Ballina and Richmond Valley.',-29.88,-24.64,151.19,153.69,0);
INSERT INTO "extent" VALUES('EPSG','2990','Australia - Brisbane','Australia - Brisbane and surrounding area. Also applicable in other local authorities in south-east Queensland (Gold Coast, Logan, Ipswich, Scenic Rim, Redland, Moreton Bay, Sunshine Coast, Noosa, eastern part of Gympie, eastern part of Fraser Coast) and north-east New South Wales (Tweed, Byron, Lismore, Kyogle, Ballina and Richmond Valley).',-29.36,-24.64,152.37,153.69,0);
INSERT INTO "extent" VALUES('EPSG','2991','Antarctica - 60°S to 64°S, 72°W to 60°W (SP19-20)','Antarctica - 60°S to 64°S and 72°W to 60°W.',-64.0,-60.0,-72.0,-60.0,0);
INSERT INTO "extent" VALUES('EPSG','2992','Antarctica - 60°S to 64°S, 60°W to 48°W (SP21-22)','Antarctica - 60°S to 64°S and 60°W to 48°W.',-64.0,-60.0,-60.0,-48.0,0);
INSERT INTO "extent" VALUES('EPSG','2993','Antarctica - 60°S to 64°S, 48°W to 36°W (SP23-24)','Antarctica - 60°S to 64°S and 48°W to 36°W.',-64.0,-60.0,-48.0,-36.0,0);
@@ -2298,7 +2298,7 @@ INSERT INTO "extent" VALUES('EPSG','3318','East Timor - onshore','Timor-Leste (E
INSERT INTO "extent" VALUES('EPSG','3319','Togo - onshore','Togo - onshore.',6.05,11.14,-0.15,1.8,0);
INSERT INTO "extent" VALUES('EPSG','3320','Tokelau - onshore','Tokelau - onshore.',-9.27,-9.12,-171.92,-171.79,0);
INSERT INTO "extent" VALUES('EPSG','3321','Tonga - onshore','Tonga - onshore.',-21.32,-18.51,-175.42,-173.85,0);
INSERT INTO "extent" VALUES('EPSG','3322','Turkey - onshore','Turkey - onshore.',35.81,42.15,25.62,44.83,0);
INSERT INTO "extent" VALUES('EPSG','3322','Turkey - onshore','Türkiye (Turkey) - onshore.',35.81,42.15,25.62,44.83,0);
INSERT INTO "extent" VALUES('EPSG','3323','Turks and Caicos Islands - onshore','Turks and Caicos Islands - onshore.',21.38,22.01,-72.09,-71.07,0);
INSERT INTO "extent" VALUES('EPSG','3324','Ukraine - onshore','Ukraine - onshore.',44.32,52.38,22.15,40.18,0);
INSERT INTO "extent" VALUES('EPSG','3325','UAE - onshore','United Arab Emirates (UAE) - onshore. Abu Dhabi, Dubai, Sharjah, Umm al Qaywayn, Al Fujairah, Ras al Khaymah.',22.63,26.1,51.56,56.44,0);
@@ -3643,3 +3643,4 @@ INSERT INTO "extent" VALUES('EPSG','4664','UK - Inverness to Thurso','United Kin
INSERT INTO "extent" VALUES('EPSG','4665','UK - Motherwell to Inverness','United Kingdom (UK) - on or related to the Scottish central mainline rail route from Motherwell through Perth and Pitlochry to Inverness.',55.7,57.55,-4.4,-3.3,0);
INSERT INTO "extent" VALUES('EPSG','4666','UK - Manchester, Wigan and Chester','United Kingdom (UK) - on or related to the rail route from Manchester via Wigan and Liverpool to Chester.',53.09,53.65,-3.15,-2.1,0);
INSERT INTO "extent" VALUES('EPSG','4667','Chile - west of 108°W','Chile - Easter Island onshore and offshore - west of 108°W.',-30.54,-23.72,-113.21,-108.0,0);
INSERT INTO "extent" VALUES('EPSG','4669','USA - Amtrak NE corridor','United States (USA) - parts of Connecticut, Delaware, District of Columbia, Maryland, Massachusetts, New Jersey, New York, Pennsylvania, Rhode Island and Virginia on or related to the Amtrak northeast corridor rail route from Boston to Washington DC via New York and Philadelphia.',38.64,42.74,-78.51,-70.48,0);
+2 -2
View File
@@ -1597,7 +1597,7 @@ INSERT INTO "usage" VALUES('EPSG','5429','geodetic_crs','EPSG','7685','EPSG','11
INSERT INTO "geodetic_crs" VALUES('EPSG','7686','Kyrg-06',NULL,'geographic 2D','EPSG','6422','EPSG','1160',NULL,0);
INSERT INTO "usage" VALUES('EPSG','5430','geodetic_crs','EPSG','7686','EPSG','1137','EPSG','1183');
INSERT INTO "geodetic_crs" VALUES('EPSG','7789','ITRF2014',NULL,'geocentric','EPSG','6500','EPSG','1165',NULL,0);
INSERT INTO "usage" VALUES('EPSG','5473','geodetic_crs','EPSG','7789','EPSG','2830','EPSG','1027');
INSERT INTO "usage" VALUES('EPSG','5473','geodetic_crs','EPSG','7789','EPSG','1262','EPSG','1027');
INSERT INTO "geodetic_crs" VALUES('EPSG','7796','BGS2005',NULL,'geocentric','EPSG','6500','EPSG','1167',NULL,0);
INSERT INTO "usage" VALUES('EPSG','5479','geodetic_crs','EPSG','7796','EPSG','1056','EPSG','1027');
INSERT INTO "geodetic_crs" VALUES('EPSG','7797','BGS2005',NULL,'geographic 3D','EPSG','6423','EPSG','1167',NULL,0);
@@ -2131,7 +2131,7 @@ INSERT INTO "usage" VALUES('EPSG','15341','geodetic_crs','EPSG','9739','EPSG','4
INSERT INTO "geodetic_crs" VALUES('EPSG','9753','WGS 84 (G2139)',NULL,'geocentric','EPSG','6500','EPSG','1309',NULL,0);
INSERT INTO "usage" VALUES('EPSG','16657','geodetic_crs','EPSG','9753','EPSG','1262','EPSG','1176');
INSERT INTO "geodetic_crs" VALUES('EPSG','9754','WGS 84 (G2139)',NULL,'geographic 3D','EPSG','6423','EPSG','1309',NULL,0);
INSERT INTO "usage" VALUES('EPSG','16853','geodetic_crs','EPSG','9754','EPSG','1262','EPSG','1176');
INSERT INTO "usage" VALUES('EPSG','16853','geodetic_crs','EPSG','9754','EPSG','2830','EPSG','1176');
INSERT INTO "geodetic_crs" VALUES('EPSG','9755','WGS 84 (G2139)',NULL,'geographic 2D','EPSG','6422','EPSG','1309',NULL,0);
INSERT INTO "usage" VALUES('EPSG','16852','geodetic_crs','EPSG','9755','EPSG','1262','EPSG','1176');
INSERT INTO "geodetic_crs" VALUES('EPSG','9758','ECML14_NB-IRF',NULL,'geographic 2D','EPSG','6422','EPSG','1310',NULL,0);
+2 -1
View File
@@ -47,7 +47,8 @@ VALUES
('CGG2013an83.byn','ca_nrc_CGG2013an83.tif','CGG2013an83.gtx','GTiff','geoid_like',0,NULL,'https://cdn.proj.org/ca_nrc_CGG2013an83.tif',1,1,NULL),
('CGG2013i83.byn','ca_nrc_CGG2013i08.tif','CGG2013i08.gtx','GTiff','geoid_like',0,NULL,'https://cdn.proj.org/ca_nrc_CGG2013i08.tif',1,1,NULL),
('CGG2013n83.byn','ca_nrc_CGG2013n83.tif','CGG2013n83.gtx','GTiff','geoid_like',0,NULL,'https://cdn.proj.org/ca_nrc_CGG2013n83.tif',1,1,NULL),
('HT2_0.byn','ca_nrc_HT2_2010v70.tif','HT2_2010v70.gtx','GTiff','geoid_like',0,NULL,'https://cdn.proj.org/ca_nrc_HT2_2010v70.tif',1,1,NULL), -- deprecated name
('HT2_0.byn','ca_nrc_HT2_2010v70.tif','HT2_2010v70.gtx','GTiff','geoid_like',0,NULL,'https://cdn.proj.org/ca_nrc_HT2_2010v70.tif',1,1,NULL), -- deprecated name. dubious mapping !!!
('HT2_1997.byn','ca_nrc_HT2_2010v70.tif',NULL,'GTiff','geoid_like',0,NULL,'https://cdn.proj.org/ca_nrc_HT2_2010v70.tif',1,1,NULL), -- dubious mapping !!!
('HT2_2010v70.byn','ca_nrc_HT2_2010v70.tif','HT2_2010v70.gtx','GTiff','geoid_like',0,NULL,'https://cdn.proj.org/ca_nrc_HT2_2010v70.tif',1,1,NULL),
('HT2_2010v70_CGG2013a.byn','ca_nrc_HT2_2010v70_CGG2013a.tif',NULL,'GTiff','vgridshift',0,NULL,'https://cdn.proj.org/ca_nrc_HT2_2010v70_CGG2013a.tif',1,1,NULL),
-- the PROJ grid is the reverse way of the EPSG one
+2 -2
View File
@@ -9,8 +9,8 @@
INSERT INTO "metadata" VALUES('DATABASE.LAYOUT.VERSION.MAJOR', 1);
INSERT INTO "metadata" VALUES('DATABASE.LAYOUT.VERSION.MINOR', 2);
INSERT INTO "metadata" VALUES('EPSG.VERSION', 'v10.074');
INSERT INTO "metadata" VALUES('EPSG.DATE', '2022-08-01');
INSERT INTO "metadata" VALUES('EPSG.VERSION', 'v10.076');
INSERT INTO "metadata" VALUES('EPSG.DATE', '2022-08-31');
-- The value of ${PROJ_VERSION} is substituted at build time by the actual
-- value.
+4
View File
@@ -7510,10 +7510,14 @@ INSERT INTO "projected_crs" VALUES('EPSG','20032','Pulkovo 1995 / Gauss-Kruger z
INSERT INTO "usage" VALUES('EPSG','6205','projected_crs','EPSG','20032','EPSG','1791','EPSG','1211');
INSERT INTO "projected_crs" VALUES('EPSG','20042','SIRGAS-Chile 2021 / UTM zone 12S',NULL,'EPSG','4400','EPSG','20041','EPSG','16112',NULL,0);
INSERT INTO "usage" VALUES('EPSG','18383','projected_crs','EPSG','20042','EPSG','4667','EPSG','1142');
INSERT INTO "projected_crs" VALUES('EPSG','20047','GDA2020 / BCSG2020',NULL,'EPSG','4400','EPSG','7844','EPSG','10147',NULL,0);
INSERT INTO "usage" VALUES('EPSG','18477','projected_crs','EPSG','20047','EPSG','2990','EPSG','1029');
INSERT INTO "projected_crs" VALUES('EPSG','20048','SIRGAS-Chile 2021 / UTM zone 18S',NULL,'EPSG','4400','EPSG','20041','EPSG','16118',NULL,0);
INSERT INTO "usage" VALUES('EPSG','18384','projected_crs','EPSG','20048','EPSG','3829','EPSG','1142');
INSERT INTO "projected_crs" VALUES('EPSG','20049','SIRGAS-Chile 2021 / UTM zone 19S',NULL,'EPSG','4400','EPSG','20041','EPSG','16119',NULL,0);
INSERT INTO "usage" VALUES('EPSG','18385','projected_crs','EPSG','20049','EPSG','3811','EPSG','1142');
INSERT INTO "projected_crs" VALUES('EPSG','20050','NAD83(2011) / Amtrak NECCS21 (ft)',NULL,'EPSG','4495','EPSG','6318','EPSG','10148',NULL,0);
INSERT INTO "usage" VALUES('EPSG','18480','projected_crs','EPSG','20050','EPSG','4669','EPSG','1141');
INSERT INTO "projected_crs" VALUES('EPSG','20064','Pulkovo 1995 / Gauss-Kruger 4N',NULL,'EPSG','4530','EPSG','4200','EPSG','16304',NULL,1);
INSERT INTO "usage" VALUES('EPSG','6206','projected_crs','EPSG','20064','EPSG','1763','EPSG','1209');
INSERT INTO "projected_crs" VALUES('EPSG','20065','Pulkovo 1995 / Gauss-Kruger 5N',NULL,'EPSG','4530','EPSG','4200','EPSG','16305',NULL,1);
+1 -1
View File
@@ -149,7 +149,7 @@ Examples
projsync --all
2. Download resource files covering specified point and attributing to an agency
2. Download resource files covering specified point and attributed to an agency
.. code-block:: console
+13 -11
View File
@@ -17,16 +17,18 @@ contributor the community is always very welcoming.
code_of_conduct
rfc/index
Conference
----------
.. Below section commented. to be refreshed for FOSS4G 2023
.. image:: ../../images/foss4g2021.jpg
:alt: FOSS4G 2021
:target: https://2021.foss4g.org/
Conference
----------
`FOSS4G 2021 <https://2021.foss4g.org/>`_ is the leading annual conference for
free and open source geospatial software. It will include presentations related
to PROJ, and some of the PROJ development community will be attending. It is the
event for those interested in PROJ, other FOSS geospatial technologies and the
community around them. The conference will due to COVID-19 be held in a virtual
setting September 27th - October 2nd, 2021.
.. image:: ../../images/foss4g2021.jpg
:alt: FOSS4G 2021
:target: https://2021.foss4g.org/
`FOSS4G 2021 <https://2021.foss4g.org/>`_ is the leading annual conference for
free and open source geospatial software. It will include presentations related
to PROJ, and some of the PROJ development community will be attending. It is the
event for those interested in PROJ, other FOSS geospatial technologies and the
community around them. The conference will due to COVID-19 be held in a virtual
setting September 27th - October 2nd, 2021.
+1 -1
View File
@@ -206,7 +206,7 @@ html_context = {
'github_user': 'OSGeo',
'github_repo': 'PROJ',
# TODO: edit when switching active branch
'github_version': '9.0/docs/source/',
'github_version': '9.1/docs/source/',
}
# Add any extra paths that contain custom files (such as robots.txt or
+6
View File
@@ -11,6 +11,12 @@ Python
`pyproj <https://pypi.python.org/pypi/pyproj>`_:
Python interface (wrapper for PROJ)
Java
====
`PROJ-JNI <https://github.com/OSGeo/PROJ-JNI>`_:
Java Native Interface for PROJ
Ruby
=======
@@ -201,8 +201,8 @@ paragraph for more details.
- ALLOW_BALLPARK=YES/NO: can be set to NO to disallow the use of
:term:`Ballpark transformation` in the candidate coordinate operations.
- FORCE_OVER=YES/NO: can be set to YES to force the +over flag on the transformation
returned by this function.
- FORCE_OVER=YES/NO: can be set to YES to force the ``+over`` flag on the transformation
returned by this function. See :ref:`longitude_wrapping`
.. doxygenfunction:: proj_normalize_for_visualization
:project: doxygen_api
+7 -3
View File
@@ -13,8 +13,8 @@ distribution of the source code and various resource file archives. See
Current Release
--------------------------------------------------------------------------------
* **2022-06-15** `proj-9.0.1.tar.gz`_ (`md5`_)
* **2022-06-15** `proj-data-1.10.tar.gz`_
* **2022-09-01** `proj-9.1.0.tar.gz`_ (`md5`_)
* **2022-09-01** `proj-data-1.11.tar.gz`_
* **PDF Manual** `proj.pdf`_
.. note::
@@ -28,6 +28,7 @@ Current Release
Past Releases
--------------------------------------------------------------------------------
* **2022-06-15** `proj-9.0.1.tar.gz`_
* **2022-03-01** `proj-9.0.0.tar.gz`_
* **2022-01-01** `proj-8.2.1.tar.gz`_
* **2021-11-01** `proj-8.2.0.tar.gz`_
@@ -57,6 +58,7 @@ Past Releases
* **2015-09-13** `proj-4.9.2.tar.gz`_
* **2015-03-04** `proj-4.9.1.tar.gz`_
* **2022-06-15** `proj-data-1.10.tar.gz`_
* **2022-03-01** `proj-data-1.9.tar.gz`_
* **2021-11-01** `proj-data-1.8.tar.gz`_
* **2021-07-01** `proj-data-1.7.tar.gz`_
@@ -88,8 +90,9 @@ Past Releases
* **2018-03-01** `proj-datumgrid-oceania-1.1.zip`_
* **2018-03-01** `proj-datumgrid-oceania-1.0.zip`_
.. _`proj-9.1.0.tar.gz`: https://download.osgeo.org/proj/proj-9.1.0.tar.gz
.. _`md5`: https://download.osgeo.org/proj/proj-9.1.0.tar.gz.md5
.. _`proj-9.0.1.tar.gz`: https://download.osgeo.org/proj/proj-9.0.1.tar.gz
.. _`md5`: https://download.osgeo.org/proj/proj-9.0.1.tar.gz.md5
.. _`proj-9.0.0.tar.gz`: https://download.osgeo.org/proj/proj-9.0.0.tar.gz
.. _`proj-8.2.1.tar.gz`: https://download.osgeo.org/proj/proj-8.2.1.tar.gz
.. _`proj-8.2.0.tar.gz`: https://download.osgeo.org/proj/proj-8.2.0.tar.gz
@@ -120,6 +123,7 @@ Past Releases
.. _`proj-4.9.2.tar.gz`: https://download.osgeo.org/proj/proj-4.9.2.tar.gz
.. _`proj-4.9.3.tar.gz`: https://download.osgeo.org/proj/proj-4.9.3.tar.gz
.. _`proj-data-1.11.tar.gz`: https://download.osgeo.org/proj/proj-data-1.11.tar.gz
.. _`proj-data-1.10.tar.gz`: https://download.osgeo.org/proj/proj-data-1.10.tar.gz
.. _`proj-data-1.9.tar.gz`: https://download.osgeo.org/proj/proj-data-1.9.tar.gz
.. _`proj-data-1.8.tar.gz`: https://download.osgeo.org/proj/proj-data-1.8.tar.gz
+11
View File
@@ -194,3 +194,14 @@ call the software PROJ.
Use of name PROJ.4 is now strictly reserved for describing legacy behavior
of the software, e.g. "PROJ.4 strings" as seen in :program:`projinfo`
output.
Who uses PROJ ?
---------------
See :ref:`users`
.. toctree::
:hidden:
users
+1
View File
@@ -19,6 +19,7 @@ PROJ
development/index
specifications/index
community/index
tutorials/index
faq
glossary
zreferences
+93
View File
@@ -3,6 +3,99 @@
News
###############################################################################
9.1.0 Release Notes
+++++++++++++++++++
*September 1st 2022*
Updates
--------
* Database:
* Database: update to EPSG v10.074 (`#3273 <https://github.com/OSGeo/PROJ/issues/3273>`_)
* Update ESRI objects to version 3.0.0 (`#3257 <https://github.com/OSGeo/PROJ/issues/3257>`_)
* Generate null transformation between geodetic/vertical datum ensemble and its members (`#3266 <https://github.com/OSGeo/PROJ/issues/3266>`_)
* Add ``fk delete cascade`` to database tables for improved customizability of the database (`#3237 <https://github.com/OSGeo/PROJ/issues/3237>`_)
* Add Svalbard geoid grid ``no_kv_arcgp-2006-sk`` to grid alternatives (`#3292 <https://github.com/OSGeo/PROJ/issues/3292>`_)
* Added French grid ``fr_ign_RAF20`` to grid alternatives (`#3228 <https://github.com/OSGeo/PROJ/issues/3228>`_)
* WKT & PROJJSON:
* WKT2 parser: allow unit-less PARAMETER for coordinate operations (`#3271 <https://github.com/OSGeo/PROJ/issues/3271>`_)
* WKT and PROJJSON adjustments (`#3234 <https://github.com/OSGeo/PROJ/issues/3234>`_)
* Bump PROJJSON to v0.5 (`#3216 <https://github.com/OSGeo/PROJ/issues/3216>`_)
* Change order of horizontal and vertical operations when dealing with WKT1 / PROJ4 compound CRS (`#3127 <https://github.com/OSGeo/PROJ/issues/3127>`_)
* Coordinate Operations:
* Implement Vertical Offset and slope transformation method (`#3200 <https://github.com/OSGeo/PROJ/issues/3200>`_)
* Add Interrupted Mollweide (land and ocean view) projections (`#3139 <https://github.com/OSGeo/PROJ/issues/3139>`_)
* Add invertible Horner polynomials (`#3133 <https://github.com/OSGeo/PROJ/issues/3133>`_)
* Optimizations:
* NTv2 and GTX grid readers: add a cache of lines to speed-up (`#3241 <https://github.com/OSGeo/PROJ/issues/3241>`_)
* :cpp:func:`IComparable::isEquivalentTo()` optimizations (`#3233 <https://github.com/OSGeo/PROJ/issues/3233>`_)
+ Various Updates:
* :cpp:func:`createOperations()` / :c:func:`proj_trans()`: better take into account area of interest name / do not only keep first returned coordinate operation (`#3282 <https://github.com/OSGeo/PROJ/issues/3282>`_)
* :cpp:func:`createOperations()`: take into account axis unit and inversion of target DerivedProjectedCRS (`#3281 <https://github.com/OSGeo/PROJ/issues/3281>`_)
* Allow a Compound CRS with derived projected (`#3283 <https://github.com/OSGeo/PROJ/issues/3283>`_)
* Make "Vertical Offset and Slope" method usable as a deriving conversion of a DerivedVerticalCRS (`#3270 <https://github.com/OSGeo/PROJ/issues/3270>`_)
* PROJ pipeline generator: recognize opposite Helmert transformations using a different convention (`#3265 <https://github.com/OSGeo/PROJ/issues/3265>`_)
* :cpp:func:`createOperations()`: prefer simpler pipelines / affects WGS 84 to GDA94/GDA2020 (`#3248 <https://github.com/OSGeo/PROJ/issues/3248>`_)
* Make it possible to determine which grid files were actually used during a transformation (`#3180 <https://github.com/OSGeo/PROJ/issues/3180>`_)
* Transformation: no longer do vertical trasnformation when doing compound CRS to 2D CRS / add --3d to cs2cs (`#3119 <https://github.com/OSGeo/PROJ/issues/3119>`_)
* Deprecate PROJ4 CMake name (`#3094 <https://github.com/OSGeo/PROJ/issues/3094>`_)
* Use GNUInstallDirs for CMake install locations (`#3100 <https://github.com/OSGeo/PROJ/issues/3100>`_)
* Introduce ``PROJ_DATA``` environment variable to deprecate ``PROJ_LIB`` (`#3253 <https://github.com/OSGeo/PROJ/issues/3253>`_)
Bug fixes
----------
* :program:`projinfo`: fix crash on --list-crs when proj.db cannot be opened (`#3290 <https://github.com/OSGeo/PROJ/issues/3290>`_)
* :cpp:func:`getCRSInfoList()`: fix retrieval of projected_crs given by text_definition only (`#3289 <https://github.com/OSGeo/PROJ/issues/3289>`_)
* WKT parser: fix issue when parsing some WKT1 with Hotine_Oblique_Mercator_Azimuth_Center and ignoring rectified_grid_angle (`#3280 <https://github.com/OSGeo/PROJ/issues/3280>`_)
* WKT1 import: better deal when the angular unit of the GEOGCS[] of the PROJCS[] doesn't match the one from the database (`#3274 <https://github.com/OSGeo/PROJ/issues/3274>`_)
* :cpp:func:`createOperations()`: avoid potential infinite recursions (`#3264 <https://github.com/OSGeo/PROJ/issues/3264>`_)
* WKT ESRI: fix related to projected CRS export and add support for geographic 3D CRS with LINUNIT node (`#3256 <https://github.com/OSGeo/PROJ/issues/3256>`_)
* :c:func:`proj_grid_info()`: make it work again with remote grids (`#3239 <https://github.com/OSGeo/PROJ/issues/3239>`_)
* :cpp:func:`createOperations()`: fix projected CRS with non-metre horiz&vertical unit and towgs84 to gencentric CRS (`#3231 <https://github.com/OSGeo/PROJ/issues/3231>`_)
* :cpp:func:`createOperations()`: fix infinite recursion in a complex case (`#3226 <https://github.com/OSGeo/PROJ/issues/3226>`_)
9.0.1 Release Notes
+++++++++++++++++++
*June 15th 2022*
+8
View File
@@ -3,3 +3,11 @@
Latitude of projection center.
*Defaults to 0.0.*
.. note::
The default convention is to interpret this value as decimal degrees. To
specify radians instead, follow the value with the "r" character.
Example: `+lat_0=1.5708r`
See :ref:`Projection Units <projection_units>` for more information.
+8
View File
@@ -3,3 +3,11 @@
First standard parallel.
*Defaults to 0.0.*
.. note::
The default convention is to interpret this value as decimal degrees. To
specify radians instead, follow the value with the "r" character.
Example: `+lat_1=1.5708r`
See :ref:`Projection Units <projection_units>` for more information.
+8
View File
@@ -3,3 +3,11 @@
Second standard parallel.
*Defaults to 0.0.*
.. note::
The default convention is to interpret this value as decimal degrees. To
specify radians instead, follow the value with the "r" character.
Example: `+lat_2=1.5708r`
See :ref:`Projection Units <projection_units>` for more information.
@@ -4,3 +4,11 @@
Takes precedence over ``+k_0`` if both options are used together.
*Defaults to 0.0.*
.. note::
The default convention is to interpret this value as decimal degrees. To
specify radians instead, follow the value with the "r" character.
Example: `+lat_ts=1.5708r`
See :ref:`Projection Units <projection_units>` for more information.
+8
View File
@@ -3,3 +3,11 @@
Longitude of projection center.
*Defaults to 0.0.*
.. note::
The default convention is to interpret this value as decimal degrees. To
specify radians instead, follow the value with the "r" character.
Example: `+lon_0=1.5708r`
See :ref:`Projection Units <projection_units>` for more information.
@@ -50,7 +50,9 @@ Required
.. option:: +model=<filename>
Filename to the JSON master file for the deformation model.
Filename to the JSON master file for the deformation model. This file must validate
against the `deformation_model.schema.json <https://raw.githubusercontent.com/OSGeo/PROJ/master/data/deformation_model.schema.json>`__
JSON schema.
Example
@@ -32,13 +32,11 @@ deformations can be modelled and then applied to the coordinates so that
they represent the physical world better. In PROJ this is done with the deformation
operation.
The horizontal grid is stored in CTable2 format and the vertical grid is stored in the
GTX format. Both grids are expected to contain grid-values in units of
mm/year. GDAL both reads and writes both file formats. Using GDAL for
construction of new grids is recommended.
Starting with PROJ 7.0, use of a GeoTIFF format is recommended to store both
the horizontal and vertical velocities.
Starting with PROJ 7.0, it is recommended to store both the horizontal and vertical
velocities in a single GeoTIFF file (:ref:`geodetictiffgrids`).
Grid values are expected to be in units of mm/year. Using GDAL for construction of new grids is recommended.
Prior to PROJ 7.0, the horizontal grid used to be stored in CTable2 format and the
vertical grid in the GTX format. Both grids GDAL both reads and writes both file formats.
More complex deformations can be done with the :ref:`Multi-component time-based deformation model <defmodel>` transformation.
@@ -83,35 +81,11 @@ model. The first use of the deformation operation is::
Here we set the central epoch of the transformation, 2000.0. The observation epoch
is expected as part of the input coordinate tuple. The deformation model is
described by two grids, specified with :option:`+xy_grids` and :option:`+z_grids`.
The first is the horizontal part of the model and the second is the vertical
component.
described by a single grid, specified with :option:`+grids`.
Parameters
-------------------------------------------------------------------------------
.. option:: +xy_grids=<list>
Comma-separated list of grids to load. If a grid is prefixed by an ``@`` the
grid is considered optional and PROJ will the not complain if the grid is
not available.
Grids for the horizontal component of a deformation model is expected to be
in CTable2 format.
.. note:: :option:`+xy_grids` is mutually exclusive with :option:`+grids`
.. option:: +z_grids=<list>
Comma-separated list of grids to load. If a grid is prefixed by an `@` the
grid is considered optional and PROJ will the not complain if the grid is
not available.
Grids for the vertical component of a deformation model is expected to be
in either GTX format.
.. note:: :option:`+z_grids` is mutually exclusive with :option:`+grids`
.. option:: +grids=<list>
.. versionadded:: 7.0.0
@@ -120,7 +94,7 @@ Parameters
grid is considered optional and PROJ will the not complain if the grid is
not available.
Grids should be in GeoTIFF format with the first 3 components being
Grids should be in GeoTIFF format (:ref:`geodetictiffgrids`) with the first 3 components being
respectively the easting, northing and up velocities in mm/year.
Setting the Description and Unit Type GDAL band metadata items is strongly
recommended, so that gdalinfo reports:
@@ -159,6 +133,33 @@ Parameters
.. note:: :option:`+dt` is mutually exclusive with :option:`+t_epoch`
.. option:: +xy_grids=<list>
.. deprecated:: 7.0
Comma-separated list of grids to load. If a grid is prefixed by an ``@`` the
grid is considered optional and PROJ will the not complain if the grid is
not available.
Grids for the horizontal component of a deformation model is expected to be
in CTable2 format.
.. note:: :option:`+xy_grids` is mutually exclusive with :option:`+grids`
.. option:: +z_grids=<list>
.. deprecated:: 7.0
Comma-separated list of grids to load. If a grid is prefixed by an `@` the
grid is considered optional and PROJ will the not complain if the grid is
not available.
Grids for the vertical component of a deformation model is expected to be
in either GTX format.
.. note:: :option:`+z_grids` is mutually exclusive with :option:`+grids`
Mathematical description
-------------------------------------------------------------------------------
@@ -38,7 +38,7 @@ is not found in the PROJ search path. The list of grids is prioritized so that
grids in the start of the list takes precedence over the grids in the back of the
list.
PROJ supports CTable2, NTv1 and NTv2 files for horizontal grid corrections. Details
PROJ supports GeoTIFF (:ref:`geodetictiffgrids`), CTable2 and NTv2 files for horizontal grid corrections. Details
about all three formats can be found in the GDAL documentation and/or driver source
code. GDAL reads and writes all three formats. Using GDAL for construction of
new grids is recommended.
@@ -106,7 +106,8 @@ Required
grid is considered optional and PROJ will the not complain if the grid is
not available.
Grids are expected to be in CTable2, NTv1 or NTv2 format.
Grids are expected to be in GeoTIFF (:ref:`geodetictiffgrids`) or NTv2 format (or CTable2 for legacy
grids)
Optional
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -40,8 +40,8 @@ is not found in the PROJ search path. The list of grids is prioritized so that
grids in the start of the list takes precedence over the grids in the back of the
list.
PROJ supports the GTX file format for vertical grid corrections. Details
about all the format can be found in the GDAL documentation. GDAL both reads and
PROJ supports the GeoTIFF (:ref:`geodetictiffgrids`) and GTX file formats for vertical grid corrections. Details
about all the formats can be found in the GDAL documentation. GDAL both reads and
writes the format. Using GDAL for construction of new grids is recommended.
Temporal gridshifting
@@ -105,7 +105,7 @@ Required
grid is considered optional and PROJ will the not complain if the grid is
not available.
Grids are expected to be in GTX format.
Grids are expected to be in GeoTIFF (:ref:`geodetictiffgrids`) or GTX formats.
Optional
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -68,7 +68,7 @@ Required
grid is considered optional and PROJ will the not complain if the grid is
not available.
Grids are expected to be in GeoTIFF format. If no metadata is provided,
Grids are expected to be in GeoTIFF format (:ref:`geodetictiffgrids`). If no metadata is provided,
the first, second and third samples are assumed to be the geocentric
translation along X, Y and Z axis respectively, in metres.
@@ -214,7 +214,8 @@ is an easy way to inspect such grid files:
- ``HORIZONTAL_OFFSET``: implies the presence of at least two samples.
The first sample must contain the latitude offset and the second
sample must contain the longitude offset.
sample must contain the longitude offset. The offset may also be expressed
as a speed per year for temporal gridshifting.
Corresponds to PROJ :ref:`hgridshift` method.
- ``VERTICAL_OFFSET_GEOGRAPHIC_TO_VERTICAL``: implies the presence of at least one sample.
@@ -330,6 +331,7 @@ is an easy way to inspect such grid files:
- ``degree``
- ``arc-second`` (default value assumed if absent for longitude and latitude offset samples of horizontal shift grid files, and value used for files stored on PROJ CDN)
- ``arc-seconds per year`` (when used with the :ref:`hgridshift` method with temporal gridshifting)
For velocity units:
@@ -643,3 +645,9 @@ been converted from https://github.com/OSGeo/proj-datumgrid/blob/master/north-am
It contains 114 subgrids. All essential metadata to list the subgrids and their
georeferencing is contained within the first 40 KB of the file.
Revisions
+++++++++
* v0.2: addition of "arc-seconds per year" as a valid unit (PROJ 9.1.1)
* v0.1: initial version for PROJ 7.0
+133
View File
@@ -0,0 +1,133 @@
.. _euref2019_answers:
Answers to the PROJ tutorial exercises
++++++++++++++++++++++++++++++++++++++++
Projections1: UTM
-------------------
.. code-block::
1. +proj=utm +zone=35
2. +proj=utm +zone=60 +south
3. +proj=utm +zone=35 +ellps=intl
Projections2: LCC
-------------------
.. code-block::
1. +proj=lcc +lat_1=59.8
2. +proj=lcc +lat_1=59.8 +k_0=0.99998
3. +proj=lcc +lat_1=59.437 +lat_2=60.171
4. +proj=lcc +lat_1=59.8 +lat_0=59.8 +lon_0=24.8
5. +proj=lcc +lat_1=59.8 +lat_0=59.8 +lon_0=24.8 +x_0=1000000 +y_0=1000000
Ellipsoids
-----------
.. code-block::
1. +R=1
2. +ellps=intl
3. +a=6378388.0 +rf=297.0
4. +a=6378206.4 +b=6356583.8
Helmert
--------
.. code-block::
1. +proj=helmert +x=-97 +y=-103 +z=-120
2. +proj=helmert +x=-81.1 +y=-89.4 +z=-115.8 +rx=0.485 +ry=0.024 +rz=0.413 +s=-0.54 +convention=position_vector
3a. +proj=helmert +x=582 +y=105 +z=414 +rx=-1.04 +ry=-0.35 +rz=3.08 +s=8.3
3b. +proj=helmert +x=582 +y=105 +z=414 +rx=1.04 +ry=0.35 +rz=-3.08 +s=8.3
1. +proj=helmert +convention=position_vector +x=-0.0016 +y=-0.0019 +z=-0.0024 +s=2e-05 +dz=0.0001 +ds=-3e-05 +t_epoch=2010
Conversions
------------
.. code-block::
1. +proj=unitconvert +xy_in=m +xy_out=us-ft
2. +proj=axisswap +order=2,1
3. +proj=cart +ellps=intl
Gridshifts
-----------
.. code-block::
1. +proj=hgridshift +grids=de_adv_BETA2007.tif
2. +proj=vgridshift +grids=us_nga_egm96_15.tif
Pipelines
----------
.. code-block::
1. +proj=pipeline +ellps=GRS80
+step +proj=cart
+step +proj=helmert +x=100 +y=200 +z=300 +convention=position_vector
+step +inv +proj=cart
2. +proj=pipeline
+step +proj=hgridshift +grids=de_adv_BETA2007.tif
+step +proj=vgridshift +grids=us_nga_egm96_15.tif
2.1: In principle, yes - practically, no.
2.2: Which grids is applied first depends on how the systems are defined.
If a geoid model is fitted to a certain datum, you need to make sure that
the input to the vgridshift operation is in that datum. That is your
responsibility to check - PROJ can't figure that out on its own. In this
case, the EGM96 geoid is fitted to WGS84. The BETA2007 grid results in
ETRS89 coordinates which for all but the most high accuracy application
can be regarded as equivalent to WGS84. Hence we do the horizontal grid
shift first.
3. +proj=pipeline
+step +inv +proj=utm +zone=32
+step +proj=cart +ellps=intl
+step +proj=helmert +x=-81.1 +y=-89.4 +z=-115.8
+rx=0.485 +ry=0.024 +rz=0.413 +s=-0.54 +convention=position_vector
+step +inv +proj=cart +ellps=GRS80
+step +proj=utm +zone=33
4. +proj=pipeline
+step +proj=axisswap +order=2,1
+step +proj=unitconvert +xy_in=deg +xy_out=rad
+step +proj=push +v_3 +step +proj=cart +ellps=bessel
+step +proj=helmert +x=598.1 +y=73.7 +z=418.2
+rx=0.202 +ry=0.045 +rz=-2.455 +s=6.7 +convention=position_vector
+step +inv +proj=cart +ellps=GRS80
+step +proj=pop +v_3
+step +proj=unitconvert +xy_in=rad +xy_out=deg
+step +proj=axisswap +order=2,1
4.1: Latitude (deg), longitude (deg), height (m)
4.2: Latitude (deg), longitude (deg), height (m)
4.3: Retain the original height of the input coordinate:
Without the push/pop steps the height would be affected by
the Helmert step.
Projections3: Tranverse Mercator
---------------------------------
.. code-block::
1. +proj=tmerc
2. +proj=tmerc +k_0=0.9996 +lon_0=27 +x_0=500000
3a. 1 cm
3b. 250 km
3c. 100 km
3d. 10 km
3e. 500 m
3f. 2 m
3g. 5 um
@@ -0,0 +1,118 @@
###############################################################################
Coordinate Conversions
In ISO19111 terms, a coordinate conversion is an operation that changes
coordinates in a source coordinate reference system to coordinates in a target
coordinate reference system in which both coordinate reference systems are based
on the same datum. Technically this is also true for PROJ although the term is
usually narrowed a bit, excluding projections since those are the origin of
PROJ they get special treatment.
In this exercise we will be looking at three coordinate conversions that in
combination with other operations are very powerful: Unit conversions, axis
swapping and geodetic to cartesian conversion. Here we only look at the
conversions by themselves which isn't particularly useful, apart from the
educational purpose. When used in transformation pipelines they reveal their
true power. We will explore that further in the pipelines.gie exercises.
See [0] for a list of all conversions available in PROJ.
[0] https://proj.org/operations/conversions/index.html
###############################################################################
<gie>
1. Unit conversion from meters to feet
-------------------------------------------------------------------------------
Many projected coordinate systems are defined in terms of units other than the
meter. In this exercise we will transform the horizontal part of a coordinate
from meters to feet.
Hints:
- Consult the documentation to find out how to set up the transformation:
https://proj.org/operations/conversions/unitconvert.html
- You can use `proj -lu` to learn which units is supported by PROJ.
- Note that the horizontal, vertical and temporal parts are treated
separately by the unit convert operator.
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 mm
accept 100.0 123.0 432.0
expect 328.0833 403.5425 432.0
-------------------------------------------------------------------------------
2. Swapping axes
-------------------------------------------------------------------------------
Many coordinate reference systems are defined such that the axis order is
different than the (east, north, up, time) PROJ defaults to. An example of this
is the standard representation of a latitude/longitude-pair, where the north
component of the coordinate comes first. For this reason we need an operation
that can swap the axes around so that a given coordinate reference system can
be represented correctly, conforming to the intention of the defining authority.
Set up an operation that puts a longitude/latitude pair on the standard
latitude/longitude form.
Hints:
- Consult the documentation to find out how to set up the transformation:
https://proj.org/operations/conversions/axisswap.html
- Remember that the axisswap operation doesn't know anything about the
nature of the coordinate that is passed to it - it only cares about the
the order of the input.
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 mm
accept 140.0 75.0 # somewhere in Siberia
expect 75.0 140.0
-------------------------------------------------------------------------------
3. Geodetic to cartesian conversion
-------------------------------------------------------------------------------
Some transformations, most notably the Helmert transformation, operates on
cartesian geocentric coordinates. Geodetic coordinates (latitude and longitude)
is the most commonly used coordinate representation. It is only natural to have
a way to convert between the two representations.
Set up a transformation that convert geodetic coordinates to cartesian
geocentric coordinates on the Hayford ellipsoid.
Hints:
- Consult the documentation to find out how to set up the transformation:
https://proj.org/operations/conversions/cart.html
- Remember that `proj -le` returns a list of available ellipsoid models
- Remember that the Hayford ellipsoid is known under a number of other
names - most of them including the term "international".
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 mm
accept 24.745 59.437 0 # Talinn, Estonia
expect 2952883.7000 1360985.5908 5468966.6589
-------------------------------------------------------------------------------
</gie>
@@ -0,0 +1,94 @@
.. _euref2019_conversions:
Coordinate conversions
++++++++++++++++++++++++++++
In ISO19111 terms, a coordinate conversion is an operation that changes
coordinates in a source coordinate reference system to coordinates in a target
coordinate reference system in which both coordinate reference systems are based
on the same datum. Technically this is also true for PROJ although the term is
usually narrowed a bit, excluding projections since those are the origin of
PROJ they get special treatment.
In this exercise we will be looking at three coordinate conversions that in
combination with other operations are very powerful: Unit conversions, axis
swapping and geodetic to cartesian conversion. Here we only look at the
conversions by themselves which isn't particularly useful, apart from the
educational purpose. When used in transformation pipelines they reveal their
true power. We will explore that further in the pipelines.gie exercises.
See :ref:`conversions_list` for a list of all conversions available in PROJ.
Download the :program:`gie` file for the exercise: :download:`conversions.gie <conversions.gie>`.
1. Unit conversion from meters to feet
----------------------------------------
Many projected coordinate systems are defined in terms of units other than the
meter. In this exercise we will transform the horizontal part of a coordinate
from meters to feet.
.. hint::
Consult :ref:`unitconvert` to find out how to set up the transformation
.. hint:: You can use ``proj -lu`` to learn which units is supported by PROJ.
.. hint::
Note that the horizontal, vertical and temporal parts are treated
separately by the unit convert operator.
.. literalinclude:: conversions.gie
:lines: 45-49
2. Swapping axes
------------------
Many coordinate reference systems are defined such that the axis order is
different than the (east, north, up, time) PROJ defaults to. An example of this
is the standard representation of a latitude/longitude-pair, where the north
component of the coordinate comes first. For this reason we need an operation
that can swap the axes around so that a given coordinate reference system can
be represented correctly, conforming to the intention of the defining authority.
Set up an operation that puts a longitude/latitude pair on the standard
latitude/longitude form.
.. hint::
Consult :ref:`axisswap` to find out how to set up the transformation
.. hint::
Remember that the axisswap operation doesn't know anything about the
nature of the coordinate that is passed to it - it only cares about the
the order of the input.
.. literalinclude:: conversions.gie
:lines: 77-81
3. Geodetic to cartesian conversion
------------------------------------
Some transformations, most notably the Helmert transformation, operate on
cartesian geocentric coordinates. Geodetic coordinates (latitude and longitude)
is the most commonly used coordinate representation. It is only natural to have
a way to convert between the two representations.
Set up a transformation that convert geodetic coordinates to cartesian
geocentric coordinates on the Hayford ellipsoid.
.. hint::
Consult :ref:`cart` to find out how to set up the transformation
.. hint:: Remember that `proj -le` returns a list of available ellipsoid models
.. hint::
Remember that the Hayford ellipsoid is known under a number of other
names - most of them including the term "international".
.. literalinclude:: conversions.gie
:lines: 109-113
@@ -0,0 +1,81 @@
###############################################################################
Specifying ellipsoid models
In this exercise we will introduce some of the many ways one can specify the
ellipsoid model used in projections and transformations.
We will be using the Mercator projection to illustrate the different ellipsoid
settings, but note that the same parameter settings can be used for setting
the ellipsoid used for most PROJ projections and transformations.
###############################################################################
<gie>
1. Use a sphere of radius 1 as the ellipsoid model:
-------------------------------------------------------------------------------
Hints:
* Check the Mercator documentation to find out how to specify an ellipsoid:
https://proj.org/operations/projections/merc.html
-------------------------------------------------------------------------------
operation +proj=merc <your answer here>
tolerance 1 cm
accept 24.745 59.437 # Talinn
expect 0.4319 1.2975
-------------------------------------------------------------------------------
2. Specify the Hayford (International) ellipsoid
-------------------------------------------------------------------------------
Hints:
* Check the Mercator documentation to find out how to specify an ellipsoid:
https://proj.org/operations/projections/merc.html
* Running `proj -le` will return a list of ellipsoids and their parameters.
-------------------------------------------------------------------------------
operation +proj=merc <your answer here>
tolerance 1 cm
accept 24.745 59.437 # Talinn
expect 2754709.2020 8238786.4803
-------------------------------------------------------------------------------
3. Specify the Hayford ellipsoid by its semimajor axis radius and inverse
flattening
-------------------------------------------------------------------------------
Hints:
* Find the parameters in the list returned by `proj -le`
-------------------------------------------------------------------------------
operation +proj=merc <your answer here>
tolerance 1 cm
accept 24.745 59.437 # Talinn
expect 2754709.2020 8238786.4803
-------------------------------------------------------------------------------
4. Set the Clarke 1866 ellipsoid by its semimajor and semiminor axis radii
-------------------------------------------------------------------------------
operation +proj=merc <your answer here>
tolerance 1 cm
accept 24.745 59.437 # Talinn
expect 2754630.7723 8238298.4968
-------------------------------------------------------------------------------
</gie>
@@ -0,0 +1,57 @@
.. euref2019_ellipsoids:
Specifying ellipsoid models
+++++++++++++++++++++++++++
In this exercise we will introduce some of the many ways one can specify the
ellipsoid model used in projections and transformations.
We will be using the Mercator projection to illustrate the different ellipsoid
settings, but note that the same parameter settings can be used for setting
the ellipsoid used for most PROJ projections and transformations.
Download the :program:`gie` file for the exercise: :download:`ellipsoids.gie <ellipsoids.gie>`.
Exercise 1: Ellipsoid radius
-----------------------------
Use a sphere of radius 1 as the ellipsoid model
.. hint::
Check the :ref:`Mercator documentation <merc>` to find out how to specify an ellipsoid
.. literalinclude:: ellipsoids.gie
:lines: 24-28
Exercise 2. Specifying a ellipsoid
-------------------------------------------------------------------------------
Set up a Mercator projection that uses the Hayford (International) ellipsoid
.. hint::
Check the :ref:`Mercator documentation <merc>` to find out how to specify an ellipsoid
.. hint:: Running ``proj -le`` will return a list of ellipsoids and their parameters.
.. literalinclude:: ellipsoids.gie
:lines: 43-47
Exercise 3. Semimajor axis and inverse flattening
---------------------------------------------------------------------------------------------
Specify the Hayford ellipsoid by its semimajor axis radius and inverse flattening
.. hint:: Find the parameters in the list returned by ``proj -le``
.. literalinclude:: ellipsoids.gie
:lines: 61-65
Exercise 4. Semimajor and semiminor ellipsoid axes
------------------------------------------------------------------------------------
Set the Clarke 1866 ellipsoid by its semimajor and semiminor axis radii
.. literalinclude:: ellipsoids.gie
:lines: 73-77
@@ -0,0 +1,10 @@
<gie>
operation +proj=utm +zone=22
#tolerance <your answer here>
tolerance 1 nm
accept -20.0 74 # Daneborg, Greenland (~30 degrees from central meridian)
roundtrip 1000
</gie>
@@ -0,0 +1,86 @@
###############################################################################
Grid shifting
Sometimes it is simpler to define a transformation as a gridded model of
displacements rather than a mathematical model. This approach, pioneered
by the US National Geodetic Survey in their 1980s era transformation from
the old NAD27 datum to the (back then) new NAD83, has become increasingly
popular as disk space and CPU cycles have gotten cheaper.
Gridded models of displacements offer the ability to make local adjustments
that are not possible with e.g. a Helmert transformation. This fact is
especially leveraged in transformations of heights since the geoid is too
bumpy to retain enough detail with a simple mathematical definition.
The main problem with grid shifting is availability of the grids needed for a
given transformation. The PROJ package requires that the PROJ-data package
[0] is installed alongside it.
[0] https://proj.org/resource_files.html
###############################################################################
<gie>
1. Horizontal gridshifting
-------------------------------------------------------------------------------
In this exercise we will apply a horizontal grid shift as it is done in the
transformation from the German DHDN to ETRS89 transformation [0].
Define the operation that converts from DE_DHDN to ETRS89 using a gridshift.
Hints:
- Consult the documentation to find out how to set up the transformation:
https://proj.org/operations/transformations/hgridshift.html
- Find the relevant grid name by inspecting the output of
projinfo -s DHDN -t ETRS89 -o WKT2_2019
Note that two operations are returned, look for the one which uses the
"HORIZONTAL_SHIFT_GTIFF" method.
[0] http://crs.bkg.bund.de/crseu/crs/descrtrans/BeTA/de_dhdn2etrs_beta.php
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 mm
accept 13.0 52.0 0.0
expect 12.9983317082 51.9986488216 0.0
-------------------------------------------------------------------------------
2. Vertical gridshifting
-------------------------------------------------------------------------------
The most common use case for vertical grid shifts is transformation from
ellipsoidal heights to physical heights. In most cases this is equivalent to
applying an offset from a geoid model, which is exactly what we will do in this
exercise.
Set up an operation that transforms ellipsoidal heights to physical heights
using the EGM96 model.
Hints:
- Consult the documentation to find out how to set up the transformation:
https://proj.org/operations/transformations/vgridshift.html
- The relevant grid name is "us_nga_egm96_15.tif"
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 mm
accept 13.0 52.0 100.0
expect 13.0 52.0 58.1917
-------------------------------------------------------------------------------
</gie>
@@ -0,0 +1,62 @@
.. euref2019_gridshift:
Gridshifting
+++++++++++++
Sometimes it is simpler to define a transformation as a gridded model of
displacements rather than a mathematical model. This approach, pioneered
by the US National Geodetic Survey in their 1980s era transformation from
the old NAD27 datum to the (back then) new NAD83, has become increasingly
popular as disk space and CPU cycles have gotten cheaper.
Gridded models of displacements offer the ability to make local adjustments
that are not possible with e.g. a Helmert transformation. This fact is
especially leveraged in transformations of heights since the geoid is too
bumpy to retain enough detail with a simple mathematical definition.
The main problem with grid shifting is availability of the grids needed for a
given transformation. The PROJ package requires that the
:ref:`PROJ-data package <datumgrid>` is installed alongside it.
Download the :program:`gie` file for the exercise: :download:`gridshift.gie <gridshift.gie>`.
Exercises 1. Horizontal gridshifting
-------------------------------------
In this exercise we will apply a horizontal grid shift as it is done in the
transformation from the `German DHDN to ETRS89 transformation <http://crs.bkg.bund.de/crseu/crs/descrtrans/BeTA/de_dhdn2etrs_beta.php>`_.
Define the operation that converts from DE_DHDN to ETRS89 using a gridshift.
.. hint:: See :ref:`hgridshift`
.. hint::
Find the relevant grid name by inspecting the output of
``projinfo -s DHDN -t ETRS89 -o WKT2_2019``
Note that two operations are returned, look for the one which uses the
"NTv2" method.
.. literalinclude:: gridshift.gie
:lines: 49-53
2. Vertical gridshifting
-------------------------
The most common use case for vertical grid shifts is transformation from
ellipsoidal heights to physical heights. In most cases this is equivalent to
applying an offset from a geoid model, which is exactly what we will do in this
exercise.
Set up an operation that transforms ellipsoidal heights to physical heights
using the EGM96 model.
.. hint:: See :ref:`vgridshift`
.. hint:: The relevant grid name is "us_nga_egm96_15.tif"
.. literalinclude:: gridshift.gie
:lines: 78-82
@@ -0,0 +1,172 @@
###############################################################################
The Helmert transformation
In this set of exercises we investigate the Helmert Transformation and some of
its properties. The Helmert transformation covers a wide range of configurations,
from simple translations of coordinates to the fully-fledged spatiotemporal
transformation. Wikipedia [0] and the PROJ documentation offer technical
details on the transformation [1]
The Helmert transformation works on geocentric, cartesian coordinates. See the
"conversions.gie" exercise for more info. In this exercise all coordinates are
already given as cartesian coordinates, so you only need to focus on the actual
transformation setup.
[0] https://en.wikipedia.org/wiki/Helmert_transformation
[1] https://proj.org/operations/transformations/helmert.html
###############################################################################
<gie>
1. Simple coordinate translation
-------------------------------------------------------------------------------
The most basic application of the Helmert transformation is a translation of
the x-, y- and z-components of the coordinate. This is rarely a good fit for
large areas but locally a 3 parameter Helmert shift can be very effective. Even
though the 3 parameter translation doesn't fit particularly well in large areas
of use it is still commonly used between legacy and modern systems. In this
exercise we will use a transformation between ED50 in Italy (Sardinia) and
WGS84.
Hints:
- You can find the transformations parameters by running the following
command:
projinfo -o WKT2_2019 -k operation EPSG:1142
which returns the WKT2 definition of the transformation.
- Remember that the input to the Helmert transform is cartesian geocentric
coordinates (x, y z).
- Consult the documentation to find out how to set up the transformation:
https://proj.org/operations/transformations/helmert.html
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 m
accept 4826177.7574 4049643.9762 991162.2529 # Sardinia (40N, 9E)
expect 4826080.7574 4049540.9762 991042.2529
-------------------------------------------------------------------------------
2. Translation and rotation
-------------------------------------------------------------------------------
For larger areas it is not enough to just rely on translation of coordinates.
In that case the solution is to include rotations of the axes and a scale
adjustment.
The rotational aspect of the transformation is handled by a set of three
rotation matrices. Two conventions for the application of the rotations are
in common use: Position Vector and Coordinate Frame. In this exercise we will
using Position Vector. See the PROJ documentation on the Helmert transformation
for further detail.
Hints:
- You can find the transformations parameters by running the following
command:
projinfo -o WKT2_2019 -k operation EPSG:1626
- Remember to specify the rotation convention with +convention
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 m
accept 3496723.5936 743251.5442 5264442.2361
expect 3496639.7297 743156.3657 5264324.9341
-------------------------------------------------------------------------------
3. Position vector/Coordinate frame
-------------------------------------------------------------------------------
Effectively, the difference between the two rotation conventions is the sign of
the rotation parameters. In this exercise we will examine this property by
looking at a transformation between the German DHDN reference system and ETRS89.
First find the parameters for the EPSG:1309 transformation. In 3a below, enter
the parameters as reported by projinfo (using the coordinate frame convention).
Adapt the parameters to the position vector convention in 3b.
Hints:
- You can find the transformations parameters by running the following
command:
projinfo -o WKT2_2019 -k operation EPSG:1309
-------------------------------------------------------------------------------
* 3a:
operation <your answer here> +convention=coordinate_frame
accept 4067886.6403 571704.1839 4862789.0376
expect 4068519.1921 571728.6671 4863239.3787
* 3b:
operation <your answer here> +convention=position_vector
tolerance 1 m
accept 4067886.6403 571704.1839 4862789.0376
expect 4068519.1921 571728.6671 4863239.3787
-------------------------------------------------------------------------------
4. Kinematic transformation between ITRF2008 and ITRF2014
-------------------------------------------------------------------------------
The Helmert transformation also exists in a kinematic, or spatiotemporal,
version. This takes the evolution of a coordinate reference system over time
into account as well. This is done by pivoting about a reference epoch. The
14-parameter spatiotemporal Helmert is used when super high accuracy
transformations are needed. A good example of such a use case is transformations
between various realizations of ITRS and ETRS89. In this exercise we look at the
transformation from ITRF2008 to ITRF2014.
Hints:
- You can find the transformations parameters by running the following
command:
projinfo -o WKT2_2019 -s ITRF2008 -t ITRF2014
which returns the WKT2 definition of the transformation.
- Not all parameters need to be set.
- Pay attention to the units of the parameteres output by projinfo,
you may have to convert them to standard units (e.g. mm -> m).
- Note that the coordinates in the test now also includes a time tag in the
form of a decimalyear - This is always needed when doing spatiotemporal
transformations in PROJ. The time tag is the observation time of the
coordinate. Note that the time component of the coordinate is never
affected by the transformation.
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 mm
accept 2952736.3768 1360917.6894 5468849.5615 2019.5
expect 2952736.3744 1360917.6871 5468849.5586 2019.5
-------------------------------------------------------------------------------
</gie>
@@ -0,0 +1,132 @@
.. _euref2019_helmert:
The Helmert transformation
++++++++++++++++++++++++++++
In this set of exercises we investigate the Helmert Transformation and some of
its properties. The Helmert transformation covers a wide range of configurations,
from simple translations of coordinates to the fully-fledged spatiotemporal
transformation. Consult `Wikipedia <https://en.wikipedia.org/wiki/Helmert_transformation>`_
and :ref:`helmert` for in-depth technical details on the transformation.
The Helmert transformation works on geocentric, cartesian coordinates. See the
:ref:`euref2019_conversions` exercise for more info. In this exercise all coordinates are
already given as cartesian coordinates, so you only need to focus on the actual
transformation setup.
Download the :program:`gie` file for the exercise: :download:`helmert.gie <helmert.gie>`.
1. Simple coordinate translation
-------------------------------------------------------------------------------
The most basic application of the Helmert transformation is a translation of
the x-, y- and z-components of the coordinate. This is rarely a good fit for
large areas but locally a 3 parameter Helmert shift can be very effective. Even
though the 3 parameter translation doesn't fit particularly well in large areas
of use it is still commonly used between legacy and modern systems. In this
exercise we will use a transformation between ED50 in Italy (Sardinia) and
WGS84.
.. hint::
You can find the transformations parameters by running the following
command::
projinfo -o WKT2_2019 -k operation EPSG:1142
which returns the WKT2 definition of the transformation.
.. hint::
Remember that the input to the Helmert transform is cartesian geocentric
coordinates (x, y z).
.. hint::
See :ref:`helmert` to find out how to set up the transformation
.. literalinclude:: helmert.gie
:lines: 53-57
2. Translation and rotation
------------------------------
For larger areas it is not enough to just rely on translation of coordinates.
In that case the solution is to include rotations of the axes and a scale
adjustment.
The rotational aspect of the transformation is handled by a set of three
rotation matrices. Two conventions for the application of the rotations are
in common use: Position Vector and Coordinate Frame. In this exercise we will
using Position Vector. See the PROJ documentation on the Helmert transformation
for further detail.
.. hint::
You can find the transformations parameters by running the following
command::
projinfo -o WKT2_2019 -k operation EPSG:1626
.. hint:: Remember to specify the rotation convention with +convention
.. literalinclude:: helmert.gie
:lines: 85-89
3. Position vector/Coordinate frame
------------------------------------
Effectively, the difference between the two rotation conventions is the sign of
the rotation parameters. In this exercise we will examine this property by
looking at a transformation between the German DHDN reference system and ETRS89.
First find the parameters for the EPSG:1309 transformation. In 3a below, enter
the parameters as reported by projinfo (using the coordinate frame convention).
Adapt the parameters to the position vector convention in 3b.
.. hint::
You can find the transformations parameters by running the following
command::
projinfo -o WKT2_2019 -k operation EPSG:1309
.. literalinclude:: helmert.gie
:lines: 114-125
4. Kinematic transformation between ITRF2008 and ITRF2014
----------------------------------------------------------
The Helmert transformation also exists in a kinematic, or spatiotemporal,
version. This takes the evolution of a coordinate reference system over time
into account as well. This is done by pivoting about a reference epoch. The
14-parameter spatiotemporal Helmert is used when super high accuracy
transformations are needed. A good example of such a use case is transformations
between various realizations of ITRS and ETRS89. In this exercise we look at the
transformation from ITRF2008 to ITRF2014.
.. hint::
You can find the transformations parameters by running the following
command::
projinfo -o WKT2_2019 -s ITRF2008 -t ITRF2014
which returns the WKT2 definition of the transformation.
.. hint:: Not all parameters need to be set.
.. hint::
Pay attention to the units of the parameters output by projinfo,
you may have to convert them to standard units (e.g. mm -> m).
.. hint::
Note that the coordinates in the test now also includes a time tag in the
form of a decimalyear - This is always needed when doing spatiotemporal
transformations in PROJ. The time tag is the observation time of the
coordinate. Note that the time component of the coordinate is never
affected by the transformation.
.. literalinclude:: helmert.gie
:lines: 164-169
@@ -0,0 +1,171 @@
###############################################################################
Transformation Pipelines
In these exercises we will learn how to use Transformation Pipelines.
Transformation Pipelines is a powerful construct in PROJ that allow users to
combine several operations into one "super operation". Pipelines are used
extensively internally in PROJ when a user asks for a transformation between
two CRS's (for example when using cs2cs). However, users can also write their
own custom pipelines for specific purposes.
Before moving on to the exercises below, familiarize yourself with the pipeline
operation in the documentation [0]. Pay special attention to the rules that
govern the use of the pipeline operation.
[0] https://proj.org/operations/pipeline.html
###############################################################################
<gie>
1. Geodetic -> Helmert -> Geodetic
-------------------------------------------------------------------------------
The signature use case for transformation pipelines is the Helmert
transformation of geodetic coordinates.
As we have seen in the previous exercises, fundamentally, the Helmert
operation works on cartesian coordinates. So when the input coordinates
are geodetic, we must convert them to the cartesian space before
applying the Helmert transformation.
Similarly, we must convert the transformed cartesian coordinates back to
geodetic space to be able to compare the coordinates before and after
transformation.
With that in mind, now create a transformation pipeline that takes geodetic
(longitude/latitude) coordinates, applies a Helmert transform, and returns
geodetic coordinates (in a different datum).
To keep it simple we will use the GRS80 ellipsoid for both input and output
datum, and a basic 3 parameter transformation, with translations 100,200,300,
and using the position vector convention.
Hints:
- Remember that in a pipeline step, the inverse of an operation is
selected by adding "+inv" to the parameter list of the operation.
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 m
accept 12.0 53.0 75.0
expect 12.00260406 53.00062190 398.48468
-------------------------------------------------------------------------------
2. Sequential grid shifts
-------------------------------------------------------------------------------
Create a transformation that applies both a horizontal and a vertical grid
adjustment. Use the de_adv_BETA2007.tif and the us_nga_egm96_15.tif grids.
a. Does it matter which grid is applied first?
b. If yes, which goes first? Why?
Hints:
- Relevant documentation:
https://proj.org/operations/transformations/hgridshift.html
https://proj.org/operations/transformations/vgridshift.html
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 12.0 53.0 75.0
expect 11.99846399 52.99852627 34.541488647
-------------------------------------------------------------------------------
3. ED50/UTM32 -> ETRS89/UTM33
-------------------------------------------------------------------------------
A transformation from one coordinate reference system to another. A very common
use case of transformation pipelines.
In this exercise we have UTM Zone 32 coordinates related to the ED50 datum,
which we want to transform to UTM Zone 33 related to ETRS89.
The transformation goes:
back-projection -> geodetic to cartesian conversion -> Helmert transformation ->
cartesian to geodetic conversion -> re-projection
... a very common recipe for transformations between projected coordinate systems.
Hints:
- Find the relevant Helmert parameters by running:
projinfo -k operation EPSG:1626 -o WKT2_2019
- If you can't remember which ellipsoids is used by ED50 and ETRS89
you can look them up with
projinfo <datum>
- Relevant documentation:
https://proj.org/operations/projections/utm.html
https://proj.org/operations/conversions/cart.html
https://proj.org/operations/transformations/helmert.html
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 687080.63 6210278.55 0
expect 312871.16 6210214.58 34.08
-------------------------------------------------------------------------------
4. A pipeline from the Real World
-------------------------------------------------------------------------------
The transformation between the German DHDN and ETRS89 is a transformation
pipeline consisting of eight steps. Lookup the transformation with projinfo:
projinfo -k operation EPSG:1776
and copy and paste the pipeline definition as your answer below. Try to decipher
the pipeline and answer the following questions:
a. What is the input coordinate type and units?
b. What is the output coordinate type and units?
c. What is the purpose of the +proj=push and +proj=pop steps?
Hints:
- A pipeline definition can span several lines in the gie format. Use this
to your advantage and put each step on it's own separate line for easier
reading
- You can use projinfo to get more knowledge about a particular CRS:
projinfo <CRS name or code>
- Consult the documentation to find out how to set up the transformation:
https://proj.org/operations/conversions/push.html
https://proj.org/operations/conversions/pop.html
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 3 m
accept 12.0 53.0 75.0
expect 12.0032 52.9953 75.0000
-------------------------------------------------------------------------------
</gie>
@@ -0,0 +1,139 @@
.. euref2019_pipelines:
Transformation pipelines
++++++++++++++++++++++++++++
In these exercises we will learn how to use Transformation Pipelines.
Transformation Pipelines is a powerful construct in PROJ that allow users to
combine several operations into one "super operation". Pipelines are used
extensively internally in PROJ when a user asks for a transformation between
two CRS's (for example when using :program:`cs2cs`). However, users can also write their
own custom pipelines for specific purposes.
Before moving on to the exercises below, familiarize yourself with the
:ref:`pipeline operation in the documentation<pipeline>`. Pay special attention to the rules that
govern the use of the pipeline operation.
Download the :program:`gie` file for the exercise: :download:`pipelines.gie <pipelines.gie>`.
1. Geodetic -> Helmert -> Geodetic
-------------------------------------------------------------------------------
The signature use case for transformation pipelines is the Helmert
transformation of geodetic coordinates.
As we have seen in the previous exercises, fundamentally, the Helmert
operation works on cartesian coordinates. So when the input coordinates
are geodetic, we must convert them to the cartesian space before
applying the Helmert transformation.
Similarly, we must convert the transformed cartesian coordinates back to
geodetic space to be able to compare the coordinates before and after
transformation.
With that in mind, now create a transformation pipeline that take geodetic
(longitude/latitude) coordinates, applies a Helmert transform, and returns
geodetic coordinates (in a different datum).
To keep it simple we will use the GRS80 ellipsoid for both input and output
datum, and a basic 3 parameter transformation, with translations 100,200,300,
and using the position vector convention.
.. hint::
Remember that in a pipeline step, the inverse of an operation is
selected by adding ``+inv`` to the parameter list of the operation.
.. literalinclude:: pipelines.gie
:lines: 53-57
2. Sequential grid shifts
-------------------------------------------------------------------------------
Create a transformation that applies both a horizontal and a vertical grid
adjustment. Use the ``de_adv_BETA2007.tif`` and the ``us_nga_egm96_15.tif`` grids.
#. Does it matter which grid is applied first?
#. If yes, which goes first? Why?
.. hint:: See :ref:`hgridshift` and :ref:`vgridshift`
.. literalinclude:: pipelines.gie
:lines: 78-82
3. ED50/UTM32 -> ETRS89/UTM33
-------------------------------
A transformation from one coordinate reference system to another. A very common
use case of transformation pipelines.
In this exercise we have UTM Zone 32 coordinates related to the ED50 datum,
which we want to transform to UTM Zone 33 related to ETRS89.
The transformation goes
#. Back-projection
#. Geodetic to cartesian conversion
#. Helmert transformation
#. Cartesian to geodetic conversion
#. Re-projection
which is a very common recipe for transformations between projected coordinate systems.
.. hint::
Find the relevant Helmert parameters by running::
projinfo -k operation EPSG:1626 -o WKT2_2019
.. hint::
If you can't remember which ellipsoids is used by ED50 and ETRS89
you can look them up with::
projinfo <datum>
.. hint::
Relevant documentation:
#. :ref:`utm`
#. :ref:`cart`
#. :ref:`helmert`
.. literalinclude:: pipelines.gie
:lines: 121-125
4. A pipeline from the Real World
----------------------------------
The transformation between the German DHDN and ETRS89 is a transformation
pipeline consisting of eight steps. Lookup the transformation with projinfo::
projinfo -k operation EPSG:1776
and copy and paste the pipeline definition as your answer below. Try to decipher
the pipeline and answer the following questions:
#. What is the input coordinate type and units?
#. What is the output coordinate type and units?
#. What is the purpose of the +proj=push and +proj=pop steps?
.. hint::
A pipeline definition can span several lines in the gie format. Use this
to your advantage and put each step on it's own separate line for easier
reading
.. hint::
You can use projinfo to get more knowledge about a particular CRS::
projinfo <CRS name or code>
.. hint::
Look at :ref:`push` and :ref:`pop` to find out how to set up the transformation
.. literalinclude:: pipelines.gie
:lines: 162-166
@@ -0,0 +1,71 @@
###############################################################################
The UTM Projection
In this exercise we will learn how to define a simple projection using PROJ.
We will investigate a few aspects of the UTM projection, as well as learn how
to use a different ellipsoid than the default (GRS80).
###############################################################################
<gie>
1. Set up a UTM projection for use in Estonia.
-------------------------------------------------------------------------------
Hints:
* Consult the documentation at
https://proj.org/operations/projections/utm.html
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 24.745 59.437 # Talinn, Estonia
expect 372106.37 6590881.40
-------------------------------------------------------------------------------
2. Set up a UTM projection for use on the North Island of New Zealand
-------------------------------------------------------------------------------
Hints:
* Consult the documentation at
https://proj.org/operations/projections/utm.html
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 174.740 -36.841 # Auckland, New Zealand
expect 298481.34 5920382.04
-------------------------------------------------------------------------------
3. Set up a UTM projection based on the Hayford ellipsoid for use in Estonia
-------------------------------------------------------------------------------
Hints:
* Consult the documentation at
https://proj.org/operations/projections/utm.html
* A list of available ellipsoids can be seen by running the command:
proj -le
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 24.745 59.437 # Talinn, Estonia
expect 372099.99 6591034.35
-------------------------------------------------------------------------------
</gie>
@@ -0,0 +1,44 @@
.. euref2019_projections1:
The UTM projection
++++++++++++++++++
In this exercise we will learn how to define a simple projection using PROJ.
We will investigate a few aspects of the UTM projection, as well as learn how
to use a different ellipsoid than the default (GRS80).
Download the :program:`gie` file for the exercise: :download:`projections1.gie <projections1.gie>`.
Exercise 1: Setting up a projection
-----------------------------------
Set up a UTM projection for use in Estonia.
.. hint:: See :ref:`UTM` for more on the projection
.. literalinclude:: projections1.gie
:lines: 21-25
Exercise 2: UTM on the southern hemisphere
-------------------------------------------
Set up a UTM projection for use on the North Island of New Zealand.
.. hint:: See :ref:`UTM` for more on the projection
.. literalinclude:: projections1.gie
:lines: 40-44
Exercise 3: Using a non-standard ellipsoid
-------------------------------------------
Set up a UTM projection based on the Hayford ellipsoid for use in Estonia.
.. hint:: See :ref:`UTM` for more on the projection
.. hint:: Run ``proj -le`` to get a list of available ellipsoids
.. literalinclude:: projections1.gie
:lines: 63-67
@@ -0,0 +1,173 @@
###############################################################################
The Lambert Conic Conformal projection
In this exercise we will introduce the Lambert Conic Conformal (LCC) projection
as well as general map projection concepts such as projection center, scale
factor, false easting/northing and ellipsoid models.
We will do so by defining various versions of the LCC optimised for use in and
around the Gulf of Finland.
In case you are not familiar with the LCC projection, Wikipedia [0] describes
the Lambert Conic Conformal projection as:
"A Lambert conformal conic projection (LCC) is a conic map projection used for
aeronautical charts, portions of the State Plane Coordinate System, and many
national and regional mapping systems. It is one of seven projections introduced
by Johann Heinrich Lambert in his 1772 publication Anmerkungen und Zusätze zur
Entwerfung der Land- und Himmelscharten (Notes and Comments on the Composition
of Terrestrial and Celestial Maps).
Conceptually, the projection seats a cone over the sphere of the Earth and
projects the surface conformally onto the cone. The cone is unrolled, and the
parallel that was touching the sphere is assigned unit scale. That parallel is
called the reference parallel or standard parallel.
By scaling the resulting map, two parallels can be assigned unit scale, with
scale decreasing between the two parallels and increasing outside them. This
gives the map two standard parallels. In this way, deviation from unit scale can
be minimized within a region of interest that lies largely between the two
standard parallels. Unlike other conic projections, no true secant form of the
projection exists because using a secant cone does not yield the same scale
along both standard parallels"
[0] https://en.wikipedia.org/wiki/Lambert_conformal_conic_projection
###############################################################################
<gie>
1. Set up a LCC projection with one standard parallel placed halfway between
Helsinki and Tallinn.
-------------------------------------------------------------------------------
Hints:
- Approximate location of Helsinki: 60.171N 24.938E
- Approximate location of Tallinn: 59.437N 24.745E
- Approximate mid point between Helsinki and Tallinn: 59.8N 24.8E
- The PROJ documentation for LCC is found at
https://proj.org/operations/projections/lcc.html
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 24.938 60.171 # Helsinki
expect 1351962.01 298663.54
accept 24.745 59.437 # Tallinn
expect 1371811.19 218598.22
-------------------------------------------------------------------------------
2. Improve the distance distortion of the projection.
------------------------------------------------------------------------------
The projection defined above is conformal, i.e. has no angular distortions
for infinitesimal objects - but there is a minor distortion of distances.
This cannot be avoided in general, but locally distortions can be minimized
by adjusting the scale factor.
With the default factor of 1, the distance error is 0 for (infinitesimal)
line segments at the latitude of the standard parallel.
By reducing the scale factor, the line of zero distance distortion degenerates
into two lines, north and south of the standard parallel.
For the abovementioned point in Tallinn, the distance error is around 0.002%,
but this can be reduced to zero by varying the scaling factor.
Even by trial and error it is not hard to reduce it to a few millionths of a
percent. So try to find a more optimal scaling factor by trial and error using
the projection analysis functionality of the proj application.
Hints:
- Modify and use the command below to find a better scaling factor:
. echo 24.745 59.437 | proj -V <your projection setup here>
- Look for the lines displaying the meridian and parallel scale.
- Consult the LCC documentation to find out how to set the scaling factor.
- Scaling factors usually deviates from unity by the order of 1e-3 to 1e-5
------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 um
accept 24.745 59.437
expect 1371783.759883408 218593.850591891
------------------------------------------------------------------------------
3. Set up a similar LCC projection, this time using two standard parallels.
The first passing through Helsinki, the second through Tallinn.
-------------------------------------------------------------------------------
Hints:
- Approximate location of Helsinki: 60.171N 24.938E
- Approximate location of Talinn: 59.437N 24.745E
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 24.8 59.8
expect 1359907.80 8024082.260
------------------------------------------------------------------------------
4. Change the projection center to the midway point between Helsinki and Tallinn
------------------------------------------------------------------------------
By changing the projection center we move the origin of the output
coordinates to be coinciding with the position where the projection is
most accurate.
Hints:
- Start with the projection you designed in exercise 1 above
- The mid point between Helsinki and Tallinn is roughly 59.8N 24.8E
- The LCC documentation explains how to change the projection center
------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 24.8 59.8
expect 0.0 0.0
------------------------------------------------------------------------------
5. Introduce false eastings and northings
------------------------------------------------------------------------------'
Oftentimes it is preferable to keep coordinate values positive even when
moving west and south of the projection center. This can be achieved by
introducing false easting and northing. Add false easting and northing
of 1000000
Hints:
- The LCC documentation explains how to set false easting/northing
------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 cm
accept 24.8 59.8
expect 1000000.00 1000000.00
------------------------------------------------------------------------------
</gie>
@@ -0,0 +1,145 @@
.. euref2019_projections2:
The Lambert Conic Conformal projection
++++++++++++++++++++++++++++++++++++++
In this exercise we will introduce the Lambert Conic Conformal (LCC) projection
as well as general map projection concepts such as projection center, scale
factor, false easting/northing and ellipsoid models.
We will do so by defining various versions of the LCC optimised for use in and
around the Gulf of Finland.
In case you are not familiar with the LCC projection, `Wikipedia`_ describes
the Lambert Conic Conformal projection as:
"A Lambert conformal conic projection (LCC) is a conic map projection used for
aeronautical charts, portions of the State Plane Coordinate System, and many
national and regional mapping systems. It is one of seven projections introduced
by Johann Heinrich Lambert in his 1772 publication Anmerkungen und Zusätze zur
Entwerfung der Land- und Himmelscharten (Notes and Comments on the Composition
of Terrestrial and Celestial Maps).
Conceptually, the projection seats a cone over the sphere of the Earth and
projects the surface conformally onto the cone. The cone is unrolled, and the
parallel that was touching the sphere is assigned unit scale. That parallel is
called the reference parallel or standard parallel.
By scaling the resulting map, two parallels can be assigned unit scale, with
scale decreasing between the two parallels and increasing outside them. This
gives the map two standard parallels. In this way, deviation from unit scale can
be minimized within a region of interest that lies largely between the two
standard parallels. Unlike other conic projections, no true secant form of the
projection exists because using a secant cone does not yield the same scale
along both standard parallels"
.. _`Wikipedia`: https://en.wikipedia.org/wiki/Lambert_conformal_conic_projection
Download the :program:`gie` file for the exercise: :download:`projections2.gie <projections2.gie>`.
Exercise 1: Standard parallel
------------------------------
Set up a LCC projection with one standard parallel placed halfway between
Helsinki and Tallinn.
.. hint::
* Approximate location of Helsinki: 60.171N 24.938E
* Approximate location of Tallinn: 59.437N 24.745E
* Approximate mid point between Helsinki and Tallinn: 59.8N 24.8E
.. hint:: See :ref:`lcc` for more on the Lambert Conformal Conic projection
.. literalinclude:: projections2.gie
:lines: 54-61
Exercise 2: Distance distortion
--------------------------------
Improve the distance distortion of the projection.
The projection defined above is conformal, i.e. has no angular distortions
for infinitesimal objects - but there is a minor distortion of distances.
This cannot be avoided in general, but locally distortions can be minimized
by adjusting the scale factor.
With the default factor of 1, the distance error is 0 for (infinitesimal)
line segments at the latitude of the standard parallel.
By reducing the scale factor, the line of zero distance distortion degenerates
into two lines, north and south of the standard parallel.
For the abovementioned point in Tallinn, the distance error is around 0.002%,
but this can be reduced to zero by varying the scaling factor.
Even by trial and error it is not hard to reduce it to a few millionths of a
percent. So try to find a more optimal scaling factor by trial and error using
the projection analysis functionality of the proj application.
.. hint::
Modify and use the command below to find a better scaling factor::
echo 24.745 59.437 | proj -V <your projection setup here>
.. hint:: Look for the lines displaying the meridian and parallel scale.
.. hint:: Consult the LCC documentation to find out how to set the scaling factor.
.. hint:: Scaling factors usually deviates from unity by the order of 1e-3 to 1e-5
.. literalinclude:: projections2.gie
:lines: 99-103
Exercise 3: Using two standard parallels
-----------------------------------------
Set up a similar LCC projection, this time using two standard parallels.
The first passing through Helsinki, the second through Tallinn.
.. hint::
* Approximate location of Helsinki: 60.171N 24.938E
* Approximate location of Talinn: 59.437N 24.745E
.. literalinclude:: projections2.gie
:lines: 119-123
Exercise 4: Projection center
-----------------------------
Change the projection center to the midway point between Helsinki and Tallinn.
By changing the projection center we move the origin of the output
coordinates to be coinciding with the position where the projection is
most accurate.
.. hint:: Start with the projection you designed in exercise 1 above
.. hint:: The mid point between Helsinki and Tallinn is roughly 59.8N 24.8E
.. hint:: :ref:`LCC` explains how to change the projection center
.. literalinclude:: projections2.gie
:lines: 143-147
Exercie 5: False easting and northing
--------------------------------------
Introduce false eastings and northings.
Oftentimes it is preferable to keep coordinate values positive even when
moving west and south of the projection center. This can be achieved by
introducing false easting and northing. Add false easting and northing
of 1000000
.. hint:: :ref:`LCC` explains how to set false easting/northing
.. literalinclude:: projections2.gie
:lines: 165-169
@@ -0,0 +1,175 @@
###############################################################################
The Transverse Mercator projection
In this exercise we will introduce the Transverse Mercator projection, the
UTM projection and the relationship between the two.
In addition we will investigate the differences between the two Transverse
Mercator implementations available in PROJ and when one should be used in
favour of the other.
###############################################################################
<gie>
1. Set up a Transverse Mercator projection using the default parameters.
-------------------------------------------------------------------------------
Hints:
* Consult the documentation at
https://proj.org/operations/projections/tmerc.html
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 mm
accept 24.745 56.437 # Talinn, Estonia
expect 1506742.2481 6535299.3398
-------------------------------------------------------------------------------
2. Use the Transverse Mercator to model the UTM projection
-------------------------------------------------------------------------------
The backbone of the UTM projection is a Transverse Mercator projection. In
this exercise we will model the behaviour of the UTM projection using the
Transverse Mercator.
Hints:
- Remember that the UTM projection on the Northern Hemisphere uses a scale
factor of 0.9996, a false easting of 500000 and a false northing of 0.
UTM on the Southern Hemisphere is similar but with a false northing of
10000000.
- The projection center is determined from the UTM zone and can be
determined by zone*6 - 183
- Tranverse Mercator parameters are documented at
https://proj.org/operations/projections/tmerc.html
- For more info, see
* https://proj.org/operations/projections/utm.html
* https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 1 mm
accept 24.745 56.437 # Talinn, Estonia
expect 360965.5942 6256998.5609
-------------------------------------------------------------------------------
3. Explore the less accurate, but faster, version of the Tranverse Mercator
-------------------------------------------------------------------------------
As mentioned in the introduction to this set of exercises, two versions of the
Transverse Mercator is implemented in PROJ. The default uses the Engsager/Poder
algorithm which is accurate far away from the central meridian of the
projection. The downside to this accuracy is that the algorithm is slower. The
alternative algorithm, which is toggled by the +approx parameter, is faster but
usage is recommended only within a few degrees away from the central meridian.
In this and the following exercises we will explore the accuracy of the two
algorithms by checking the roundtrip stability of a number of transformations.
A coordinate in Greenland will be used, as it is common practice to store
geospatial data covering the whole country in the same UTM zone. This is only
possible when using the correct algorithm. For the sake of simplicity,
all operations in the following exercises are expressed as UTM projections. The
UTM projection also has the +approx parameter which toggles the use of the
faster, less accurate transverse mercator algorithm.
We will try to determine the approximate roundtrip accuracy of the +approx
algorithm several UTM zones away from the actual zone for the given coordinate.
For all the exercises below the aim is to find the lowest tolerance for each
roundtrip test. You can of course make alle tests pass by setting a tolerance of
1000 km - that's not the point: How low can you go?
After you have answered all ex. 3 questions below, based on your findings
consider in which situation use of each of the algorithms is appropriate.
Hints:
- gie accepts most common SI unit prefixes to the meter when specifying
the tolerance, e.g. km, m, dm, cm, mm, um, nm.
- Look at the output gie produces - the difference between the actual result
and the expected result is reported when tests fail.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
* 3a. As a baseline, determine the roundtrip accuracy of the default algorirthm
using UTM zone 22:
-------------------------------------------------------------------------------
operation +proj=utm +zone=22
tolerance <your answer here> # Hint: You can go *very* low here
accept -20.0 74 # Daneborg, Greenland (~30 degrees from central meridian)
roundtrip 1000
* 3b. Determine the roundtrip accuracy of the "+approx" algorithm using UTM zone 22:
-------------------------------------------------------------------------------
operation +proj=utm +zone=22 +approx
tolerance <your answer here>
accept -20.0 74 # Daneborg, Greenland (~30 degrees from central meridian)
roundtrip 1000
* 3c. Determine the roundtrip accuracy of the "+approx" algorithm using UTM zone 23:
-------------------------------------------------------------------------------
operation +proj=utm +zone=23 +approx
tolerance <your answer here>
accept -20.0 74 # Daneborg, Greenland
roundtrip 1000
* 3d. Determine the roundtrip accuracy of the "+approx" algorithm using UTM zone 24:
-------------------------------------------------------------------------------
operation +proj=utm +zone=24 +approx
tolerance <your answer here>
accept -20.0 74 # Daneborg, Greenland
roundtrip 1000
* 3e. Determine the roundtrip accuracy of the "+approx" algorithm using UTM zone 25:
-------------------------------------------------------------------------------
operation +proj=utm +zone=25 +approx
tolerance <your answer here>
accept -20.0 74 # Daneborg, Greenland
roundtrip 1000
* 3f. Determine the roundtrip accuracy of the "+approx" algorithm using UTM zone 26:
-------------------------------------------------------------------------------
operation +proj=utm +zone=26 +approx
tolerance <your answer here>
accept -20.0 74 # Daneborg, Greenland
roundtrip 1000
* 3g. Determine the roundtrip accuracy of the "+approx" algorithm using UTM zone 27:
-------------------------------------------------------------------------------
operation +proj=utm +zone=27 +approx
tolerance <your answer here>
accept -20.0 74 # Daneborg, Greenland
roundtrip 1000
-------------------------------------------------------------------------------
</gie>
@@ -0,0 +1,141 @@
.. _euref2019_projections3:
The Transverse Mercator projection
+++++++++++++++++++++++++++++++++++
In this exercise we will introduce the Transverse Mercator projection, the
UTM projection and the relationship between the two.
In addition we will investigate the differences between the two Transverse
Mercator implementations available in PROJ and when one should be used in
favour of the other.
Download the :program:`gie` file for the exercise: :download:`projections3.gie <projections3.gie>`.
Exercise 1. Transverse Mercator with default parameters
--------------------------------------------------------
Set up a Transverse Mercator projection using the default parameters.
.. hint:: Consult :ref:`tmerc`
.. literalinclude:: projections3.gie
:lines: 25-29
Exercise 2: Use the Transverse Mercator to model the UTM projection
----------------------------------------------------------------------
The backbone of the UTM projection is a Transverse Mercator projection. In
this exercise we will model the behaviour of the UTM projection using the
Transverse Mercator.
.. hint::
Remember that the UTM projection on the Northern Hemisphere uses a scale
factor of 0.9996, a false easting of 500000 and a false northing of 0.
UTM on the Southern Hemisphere is similar but with a false northing of
10000000.
.. hint::
The projection center is determined from the UTM zone and can be
determined by zone*6 - 183
.. hint:: Tranverse Mercator parameters are documented at :ref:`tmerc`
.. literalinclude:: projections3.gie
:lines: 60-64
Exercise 3: The less accurate, but faster, version of the Tranverse Mercator
-----------------------------------------------------------------------------
As mentioned in the introduction to this set of exercises, two versions of the
Transverse Mercator is implemented in PROJ. The default uses the Engsager/Poder
algorithm which is accurate far away from the central meridian of the
projection. The downside to this accuracy is that the algorithm is slower. The
alternative algorithm, which is toggled by the +approx parameter, is faster but
usage is recommended only within a few degrees away from the central meridian.
In this and the following exercises we will explore the accuracy of the two
algorithms by checking the roundtrip stability of a number of transformations.
A coordinate in Greenland will be used, as it is common practice to store
geospatial data covering the whole country in the same UTM zone. This is only
possible when using the correct algorithm. For the sake of simplicity,
all operations in the following exercises are expressed as UTM projections. The
UTM projection also has the +approx parameter which toggles the use of the
faster, less accurate transverse mercator algorithm.
We will try to determine the approximate roundtrip accuracy of the +approx
algorithm several UTM zones away from the actual zone for the given coordinate.
For all the exercises below the aim is to find the lowest tolerance for each
roundtrip test. You can of course make alle tests pass by setting a tolerance of
1000 km - that's not the point: How low can you go?
After you have answered all exercise 3 questions below, based on your findings
consider in which situation use of each of the algorithms is appropriate.
.. hint::
:program:`gie` accepts most common SI unit prefixes to the meter when
specifying the tolerance, e.g. km, m, dm, cm, mm, um, nm.
.. hint::
Look at the output :program:`gie` produces - the difference between the
actual result and the expected result is reported when tests fail.
Exercise 3a
===========
As a baseline, determine the roundtrip accuracy of the default algorirthm
using UTM zone 22.
.. literalinclude:: projections3.gie
:lines: 112-117
Exercise 3b
===========
Determine the roundtrip accuracy of the ``+approx`` algorithm using UTM zone 22:
.. literalinclude:: projections3.gie
:lines: 121-125
Exercise 3c
===========
Determine the roundtrip accuracy of the ``+approx`` algorithm using UTM zone 23.
.. literalinclude:: projections3.gie
:lines: 130-134
Exercise 3d
===========
Determine the roundtrip accuracy of the ``+approx`` algorithm using UTM zone 24:
.. literalinclude:: projections3.gie
:lines: 139-143
Exercise 3e
============
Determine the roundtrip accuracy of the ``+approx`` algorithm using UTM zone 25:
.. literalinclude:: projections3.gie
:lines: 148-152
Exercise 3f
===========
Determine the roundtrip accuracy of the ``+approx`` algorithm using UTM zone 26:
.. literalinclude:: projections3.gie
:lines: 157-161
Exercise 3g
============
Determine the roundtrip accuracy of the ``+approx`` algorithm using UTM zone 27:
.. literalinclude:: projections3.gie
:lines: 166-170
+98
View File
@@ -0,0 +1,98 @@
.. _transformation_tutorial:
================================================================================
Transformation tutorial
================================================================================
Introduction
------------
This tutorial was developed for the EUREF 2019 Symposium as an introduction
to geodetic transformations in PROJ. The intended audience was geodesist in
governmental geodetic agencies but the tutorial should be of interest to a
broader group of people within GIS, remote sensing and related fields.
The tutorials gives insight into how transformations are set up using the
"PROJ language" as well as introduce most of the command line applications
packaged with PROJ. In the tutorial properties of several common projections
and transformations are investigated.
The tutorial requires a working installation of PROJ. Consult the
:ref:`chapter on installing PROJ <install>`.
How to fill out the PROJ tutorial exercises
-------------------------------------------
All the exercises are made as :program:`gie` tests where one or more inputs are
missing. Replace occurrences of ``<your answer here>`` with the relevant input.
Below is an annotated example of a complete :program:`gie` test. Your objective is to fill
out the exercises from 1 and onwards in a similar fashion.
Below is a simple exercise before the answer has been filled in::
1. Set up an operation that returns the input it is given
-------------------------------------------------------------------------------
operation <your answer here>
tolerance 10 mm
accept 12.3 45.6
expect 12.3 45.6
-------------------------------------------------------------------------------
An annotated answer could look like this::
<gie>
operation +proj=latlon # The latlon "projection" returns the same output as
# given in the input
tolerance 10 mm
accept 12.3 45.6
expect 12.3 45.6
</gie>
The :program:`gie` application can be used to check if the exercise has been answered
correctly::
gie exercises\<exercise_name>.gie
If all answers are correct :program:`gie` will return output similar to::
-------------------------------------------------------------------------------
Reading file 'exercises\instructions.md'
-------------------------------------------------------------------------------
total: 1 tests succeeded, 0 tests skipped, 0 tests failed.
-------------------------------------------------------------------------------
If incorrect, :program:`gie` will output something like::
-------------------------------------------------------------------------------
Reading file 'exercises\instructions.md'
-----
FAILURE in instructions.md(48):
expected: 12.3 45.6
got: 1369229.736757265171 5685937.873489554040
deviation: 999999999.999000 mm, expected: 10.000000 mm
-------------------------------------------------------------------------------
total: 0 tests succeeded, 0 tests skipped, 1 tests FAILED!
-------------------------------------------------------------------------------
Where the number of failing exercises (or tests in :program:`gie` terminology)
is given, as well as the line number of the failing test (in parenthesis after
the file name).
Exercises
----------
.. toctree::
:maxdepth: 1
exercises/projections1
exercises/projections2
exercises/ellipsoids
exercises/gridshift
exercises/helmert
exercises/conversions
exercises/pipelines
exercises/projections3
answers
+165
View File
@@ -0,0 +1,165 @@
###############################################################################
Exercise: Geodesics and planar approximations using PROJ and GEOD
Thomas Knudsen, thokn@sdfe.dk, 2019-05-08
The PROJ system supports computations with geodesics [0], through API calls or
through the "geod" command line interface [1]. The GIE test authoring tool does,
however, not directly support geodesics, so this exercise will proceed mostly
by having you copy sample commands from the text onto the command line, and
copying results from the command line back into this file.
[0] https://proj.org/geodesic.html
[1] https://proj.org/apps/geod.html
------------------------------------------------------------------------------
1. Objective
------------------------------------------------------------------------------
The objective of this exercise is to investigate how well a straight line in
a projected plane approximates the geodesic between the same end points.
------------------------------------------------------------------------------
2. The geodesic
------------------------------------------------------------------------------
The geodesic we will consider runs from Helsinki to Tallinn, using the
coordinates from the LCC exercise:
Helsinki 60.171 N 24.938 E
Tallinn 59.437 N 24.745 E
So to save some typing, let's define some environment variables:
set HEL=60.171 24.938
set TAL=59.437 24.745
(i.e. mark, copy, and paste these lines into the command prompt)
First, we want to solve the "inverse geodetic problem" for the geodesic,
i.e. finding the azimuth and distance between the two points:
echo %HEL% %TAL% | geod -I +ellps=GRS80
where the "-I" option indicates "the inverse geodetic problem".
NOTE: This is Windows syntax - Unix users use $HEL, etc.
geod replies with these 3 numbers:
-172d22'12.772" 7d27'46.693" 82488.500
The first is the forward azimuth from Helsinki to Tallinn, the second is the
return azimuth, while the third is the distance in meters.
We would actually rather have the azimuths in fractional degrees, so we provide
an explicit output format, using the -f option to geod:
echo %HEL% %TAL% | geod -I -f "%.12f" +ellps=GRS80
getting us:
-172.370214337896 7.462970382137 82488.500
We assert that the planar approximation is worst at the midpoint of the
geodesic, i.e. (82488.5 m) / 2 = 41244.25 m, from Helsinki. So now, we
want to find the coordinates of this point, by solving the "direct geodetic
problem":
echo %HEL% -172.370214337896 41244.25 | geod -f "%.12f" +ellps=GRS80
resulting in:
59.804045696236 24.840439590098 7.545306054713
i.e. the latitude, the longitude, and the return azimuth of the mid point
of the geodesic.
Now, for convenience, define this environment variable:
set MID=59.804045696236 24.840439590098
NOTE: You can save a bit of manual copying by capturing the geod output into
the clipboard, using the "clip" command, i.e. by appending
| clip
to the geod command above.
------------------------------------------------------------------------------
3. The planar approximation
------------------------------------------------------------------------------
We will be working on ETRS89/UTM35 coordinates, so first define an environment
variable, to save some typing:
set utm35=proj -rs +proj=utm +zone=35 +ellps=GRS80
NOTE: The -rs option switches the proj coordinate i/o order to latitude/longitude
and northing/easting, respectively. We do this to comply with the expected order
for the geod program.
Now, find the UTM coordinates of the two end points:
echo %HEL% | %utm35%
echo %TAL% | %utm35%
Type the two projected coordinate tuples here:
Helsinki, UTM: <your result here>
Tallinn, UTM: <your result here>
Compute the mean of the northings, and the mean of the eastings, to obtain the
planar approximation of the mid point
NOTE: you can use python as a makeshift command line calculator by saying:
python -c print((4+8)/2)
Now, compute the geographical coordinates corresponding to the UTM mid point:
echo <your northing your easting> | %utm35% -f "%.12f" -I
(note the -I option for doing the inverse projection)
For convenience define:
set MID_APPROX=<your result here>
Finally, compute the distance between the geodesic mid point and its planar
approximation, by stating it as another case of the inverse geodetic problem:
echo %MID% %MID_APPROX% | geod -I +ellps=GRS80
resulting in:
107d0'16.673" -72d59'43.193" 2.527
i.e. a deviation of 2.5 m over a stretch of about 85 km.
------------------------------------------------------------------------------
4. Suggested meditations
------------------------------------------------------------------------------
Consider these aspects:
1. Given that geod is available, fast, and reliable - is it really worth the
effort doing approximate calculations in the projected plane?
2. geod includes functionality for computing intermediate points along a
geodesic. Check the manual ([1] above), especially the description of the
"n_S" option, and try to compute the geodesic mid point directly, by
setting n_S=2.
3. One should actually expect the result of meditation 2 above to be slightly
superior to the result obtained in the exercise. Why?
4. While gie does not directly support tests of geodesic computations, a
number of the partial tasks above could evidently be stated as gie tests.
Try to do that in the <gie>/</gie> section below
###############################################################################
<gie>
</gie>
+179
View File
@@ -0,0 +1,179 @@
.. _geodesics_tutorial:
Geodesics and planar approximations using PROJ and geod
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The PROJ system supports computations with :ref:`geodesic`, through API calls or
through the :ref:`geod` command line interface. This exercise will proceed mostly
by having you copy sample commands from the text onto the command line, and
noting the results.
The tutorial is written with the Windows command line in mind but it should
be straight forward to use it on Unix-based systems as well.
.. hint::
Users of Unix-based systems can replace ``set`` with ``export`` and ``%VAR%``
with ``$VAR`` to follow the tutorial.
1. Objective
------------------------------------------------------------------------------
The objective of this exercise is to investigate how well a straight line in
a projected plane approximates the geodesic between the same end points.
2. The geodesic
------------------------------------------------------------------------------
The geodesic we will consider runs from Helsinki to Tallinn, using the
following coordinates:
.. code-block::
Helsinki 60.171 N 24.938 E
Tallinn 59.437 N 24.745 E
So to save some typing, let's define some environment variables. On Windows:
.. code-block::
set HEL="60.171 24.938"
set TAL="59.437 24.745"
.. code-block::
export HEL="60.171 24.938"
export TAL="59.437 24.745"
(i.e. mark, copy, and paste these lines into the command prompt)
First, we want to solve the "inverse geodetic problem" for the geodesic,
i.e. finding the azimuth and distance between the two points::
echo %HEL% %TAL% | geod -I +ellps=GRS80
where the ``-I`` option indicates "the inverse geodetic problem".
:program:`geod` replies with these 3 numbers::
-172d22'12.772" 7d27'46.693" 82488.500
The first is the forward azimuth from Helsinki to Tallinn, the second is the
return azimuth, while the third is the distance in meters.
We would actually rather have the azimuths in fractional degrees, so we provide
an explicit output format, using the ``-f`` option to geod::
echo %HEL% %TAL% | geod -I -f "%.12f" +ellps=GRS80
getting us::
-172.370214337896 7.462970382137 82488.500
We assert that the planar approximation is worst at the midpoint of the
geodesic, i.e. ``(82488.5 m) / 2 = 41244.25 m``, from Helsinki. So now, we
want to find the coordinates of this point, by solving the "direct geodetic
problem"::
echo %HEL% -172.370214337896 41244.25 | geod -f "%.12f" +ellps=GRS80
resulting in::
59.804045696236 24.840439590098 7.545306054713
i.e. the latitude, the longitude, and the return azimuth of the mid point
of the geodesic.
Now, for convenience, define this environment variable::
set MID="59.804045696236 24.840439590098"
.. note::
You can save a bit of manual copying by capturing the geod output into
the clipboard, using the "clip" command on Windows, i.e. by appending ``| clip``
to the ``geod`` command above.
1. The planar approximation
------------------------------------------------------------------------------
We will be working on ETRS89/UTM35 coordinates, so first define an environment
variable, to save some typing::
set utm35=proj -rs +proj=utm +zone=35 +ellps=GRS80
.. note::
The ``-rs`` option switches the proj coordinate i/o order to latitude/longitude
and northing/easting, respectively. We do this to comply with the expected order
for the geod program.
Now, find the UTM coordinates of the two end points::
echo %HEL% | %utm35%
echo %TAL% | %utm35%
Note your results and compute the mean of the northings, and the mean of the eastings,
to obtain the planar approximation of the mid point
.. hint::
you can use python as a makeshift command line calculator by saying::
python -c print((4+8)/2)
Now, compute the geographical coordinates corresponding to the UTM mid point::
echo <your northing your easting> | %utm35% -f "%.12f" -I
(note the -I option for doing the inverse projection)
For convenience define::
set MID_APPROX=<your result here>
Finally, compute the distance between the geodesic mid point and its planar
approximation, by stating it as another case of the inverse geodetic problem::
echo %MID% %MID_APPROX% | geod -I +ellps=GRS80
resulting in::
107d0'16.673" -72d59'43.193" 2.527
i.e. a deviation of 2.5 m over a stretch of about 85 km.
4. Suggested meditations
------------------------------------------------------------------------------
Consider these aspects:
#. Given that geod is available, fast, and reliable - is it really worth the
effort doing approximate calculations in the projected plane?
#. :program:`geod` includes functionality for computing intermediate points along a
geodesic. Check the manual, especially the description of the
``n_S`` option, and try to compute the geodesic mid point directly, by
setting ``n_S=2``.
#. One should actually expect the result of meditation 2 above to be slightly
superior to the result obtained in the exercise. Why?
Answers
------------
.. code-block::
Helsinki, UTM: 6672241.54 385592.95
Tallinn, UTM: 6590881.40 372106.37
Mid point, UTM: 6631561.47 378849.66
Mid point, GEO: 59.804039062602 24.840482644156
Meditations:
#. Probably not
#. ``geod +lat_1=60.171 +lon_1=24.938 +lat_2=59.437 +lon_2=24.745 +n_S=2 +ellps=GRS80 -f "%.12f"``
#. Avoids a bit of truncation of the azimuth, and *may* use a slightly superior algorithm (check the code!)
+12
View File
@@ -0,0 +1,12 @@
.. _tutorials:
================================================================================
Tutorials
================================================================================
.. toctree::
:maxdepth: 1
EUREF2019/index
geodesics
+36 -4
View File
@@ -38,6 +38,8 @@ documenting the individual :doc:`projections<../operations/projections/index>`.
In the sections below most of the parameters are explained in details.
.. _projection_units:
Units
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -64,6 +66,32 @@ Scaling of output units can be done by applying the ``+k_0`` argument. The
returned coordinates are scaled by the value assigned with the ``+k_0``
parameter.
Input units for parameters that can be understood to be either decimal degrees or
radians are interpreted to be decimal degrees by convention.
Explict specification of input units can be accomplished by adding the appropriate
suffix to input values.
+----------------+---------------------+
| Suffix | Unit |
+================+=====================+
| d | Decimal degrees |
+----------------+ +
| D | |
+----------------+ +
| ° | |
+----------------+---------------------+
| r | Radians |
+----------------+ +
| R | |
+----------------+---------------------+
Example of use. The longitude of the central meridian ``+lon_0=90``, can also be expressed more explictly
with units of decimal degrees as ``+lon_0=90d`` or in radian
units as ``+lon_0=1.5708r`` (approximately).
False Easting/Northing
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -72,16 +100,22 @@ Virtually all coordinate systems allow for the presence of a false easting
meters even if the coordinate system is some other units. Some coordinate
systems (such as UTM) have implicit false easting and northing values.
.. _longitude_wrapping:
Longitude Wrapping
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
By default PROJ wraps output longitudes in the range -180 to 180. The ``+over``
switch can be used to disable the default wrapping which is done at a low level
in ``pj_inv()``. This is particularly useful with projections like the
:doc:`equidistant cylindrical<../operations/projections/eqc>`
where it would be desirable for X values past -20000000 (roughly) to continue
:ref:`eqc` or :ref:`merc`
where it could be desirable for X values past -20000000 (roughly) to continue
past -180 instead of wrapping to +180.
Note however that for most projections where the 180 meridian does not project
to a straight line, ``+over`` will have no effect or will not lead to expected
results.
The ``+lon_wrap`` option can be used to provide an alternative means of doing
longitude wrapping within ``pj_transform()``. The argument to this option is a
center longitude. So ``+lon_wrap=180`` means wrap longitudes in the range 0 to
@@ -159,5 +193,3 @@ They can be combined in +axis in forms like:
The ``+axis`` argument does not work with the :program:`proj` command line
utility.
+1 -1
View File
@@ -15,7 +15,7 @@ geodetic transformations of varying complexity can be performed.
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
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
described in the sections below. Large portions of the text are based on
:cite:`EversKnudsen2017`.
+69
View File
@@ -0,0 +1,69 @@
.. _users:
================================================================================
Software and organizations using or contributing to PROJ
================================================================================
Free and open source software
-----------------------------
- `GDAL <https://gdal.org>`_ Translator library for raster and vector geospatial data formats, used by > 100 other software
- `GRASS GIS <http://grass.osgeo.org>`_ A raster/vector open source GIS
- `libgeotiff <https://github.com/OSGeo/libgeotiff>`_ Library to read/write GeoTIFF keys
- `MapServer <http://mapserver.org/index.html>`_ A popular web mapping application
- `PDAL <https://pdal.io>`_ Point Cloud Data Abstraction Library
- `PostGIS <http://www.postgis.net>`_ Spatial database extender for PostgreSQL
- `QGIS <http://www.qgis.org>`_ A cross platform desktop GIS.
- `QField <http://qfield.org>`_ Mobile data collection app for Android, iOS and Windows.
- `R <http://www.r-project.org>`_ A free software environment for statistical computing and graphics
- `mundipy <https://docs.mundi.ai>`_ A Python framework for spatial data analysis
PROJ bindings in other languages
--------------------------------
See :ref:`bindings`
Proprietary licensed software
-----------------------------
- `FME <http://www.safe.com>`_ A GIS translator package. Includes a PROJ based transformer.
- `Avenza Maps <https://www.avenzamaps.com>`_ Top mobile mapping app for offline navigation and data collection.
- `Bunting Labs <https://buntinglabs.com/>`_ No-code GIS infrastructure
Geodetic organizations
----------------------
- `Agency for Data Supply and Infrastructure of Denmark (SDFI) <https://eng.sdfi.dk/>`_
- `Land Information New Zealand (LINZ) <https://www.linz.govt.nz/>`_
- `National Land Survey of Finland (NLS) <https://www.maanmittauslaitos.fi/en>`_
- `National Land Survey of Iceland (NLS) <https://www.lmi.is/>`_
- `Netherlands Partnership Geodetic Infrastructure (NSGI) <https://www.nsgi.nl/>`_
* `Netherlands' Cadastre, Land Registry and Mapping Agency (Kadaster) <https://www.kadaster.nl/about-us>`_
* `Directorate-General for Public Works and Water Management (Rijkswaterstaat) <https://www.rijkswaterstaat.nl/en>`_
* `Hydrographic Service of the Royal Netherlands Navy <https://english.defensie.nl/organisation/navy/navy-units/hydrographic-service/>`_
- `Nordic Geodetic commission (NKG) <https://www.nordicgeodeticcommission.com/>`_
- `Norwegian Mapping Authority (Kartverket) <https://kartverket.no/en>`_
- `Swedish mapping, cadastral and land registration authority (Lantmäteriet) <https://www.lantmateriet.se/>`_
- `USGS <https://www.usgs.gov/>`_: PROJ initial author, Gerald E. Evenden, worked at USGS
Public organizations
--------------------
- `Istituto Nazioanle di Astrofisica (INAF) <https://www.inaf.it/>`_ : `Planetary Mapping and GIS Laboratory <https://gislab.iaps.inaf.it/>`_
- `Ecole Nationale des Sciences Géographiques (ENSG-géomatique) <https://www.ensg.eu/>`_ : French geomatic school which depends on the National Institute of Geographic and Forest Information (IGN)
(add yourself here if you are a direct user of PROJ API or utilities)
Private organizations
---------------------
(add yourself here if you are a direct user of PROJ API or utilities)
Sponsors
--------
PROJ development, as an upstream dependency of GDAL, benefits from funding
brought by its `sponsors <https://gdal.org/sponsors/>`_
+20
View File
@@ -1376,6 +1376,23 @@ class PROJ_GCC_DLL Conversion : public SingleOperation {
PROJ_DLL static ConversionNNPtr
createGeographicGeocentric(const util::PropertyMap &properties);
PROJ_DLL static ConversionNNPtr
createGeographic2DOffsets(const util::PropertyMap &properties,
const common::Angle &offsetLat,
const common::Angle &offsetLon);
PROJ_DLL static ConversionNNPtr createGeographic3DOffsets(
const util::PropertyMap &properties, const common::Angle &offsetLat,
const common::Angle &offsetLon, const common::Length &offsetHeight);
PROJ_DLL static ConversionNNPtr createGeographic2DWithHeightOffsets(
const util::PropertyMap &properties, const common::Angle &offsetLat,
const common::Angle &offsetLon, const common::Length &offsetHeight);
PROJ_DLL static ConversionNNPtr
createVerticalOffset(const util::PropertyMap &properties,
const common::Length &offsetHeight);
PROJ_DLL ConversionPtr convertToOtherMethod(int targetEPSGCode) const;
PROJ_PRIVATE :
@@ -1617,6 +1634,9 @@ class PROJ_GCC_DLL Transformation : public SingleOperation {
demoteTo2D(const std::string &newName,
const io::DatabaseContextPtr &dbContext) const;
PROJ_INTERNAL static bool
isGeographic3DToGravityRelatedHeight(const OperationMethodNNPtr &method,
bool allowInverse);
//! @endcond
protected:
+4
View File
@@ -1273,6 +1273,10 @@ class PROJ_GCC_DLL DerivedProjectedCRS final : public DerivedCRS {
const operation::ConversionNNPtr &derivingConversionIn,
const cs::CoordinateSystemNNPtr &csIn);
PROJ_DLL DerivedProjectedCRSNNPtr
demoteTo2D(const std::string &newName,
const io::DatabaseContextPtr &dbContext) const;
//! @cond Doxygen_Suppress
PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter)
const override; // throw(io::FormattingException)
+5
View File
@@ -136,6 +136,7 @@ osgeo::proj::crs::DerivedGeographicCRS::demoteTo2D(std::string const&, std::shar
osgeo::proj::crs::DerivedGeographicCRS::~DerivedGeographicCRS()
osgeo::proj::crs::DerivedProjectedCRS::baseCRS() const
osgeo::proj::crs::DerivedProjectedCRS::create(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::ProjectedCRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::Conversion> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystem> > const&)
osgeo::proj::crs::DerivedProjectedCRS::demoteTo2D(std::string const&, std::shared_ptr<osgeo::proj::io::DatabaseContext> const&) const
osgeo::proj::crs::DerivedProjectedCRS::~DerivedProjectedCRS()
osgeo::proj::crs::DerivedVerticalCRS::baseCRS() const
osgeo::proj::crs::DerivedVerticalCRS::create(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::VerticalCRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::operation::Conversion> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::VerticalCS> > const&)
@@ -543,6 +544,9 @@ osgeo::proj::operation::Conversion::createEquidistantCylindrical(osgeo::proj::ut
osgeo::proj::operation::Conversion::createEquidistantCylindricalSpherical(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createGall(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createGaussSchreiberTransverseMercator(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Scale const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createGeographic2DOffsets(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&)
osgeo::proj::operation::Conversion::createGeographic2DWithHeightOffsets(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createGeographic3DOffsets(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createGeographicGeocentric(osgeo::proj::util::PropertyMap const&)
osgeo::proj::operation::Conversion::createGeostationarySatelliteSweepX(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createGeostationarySatelliteSweepY(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
@@ -590,6 +594,7 @@ osgeo::proj::operation::Conversion::createTunisiaMappingGrid(osgeo::proj::util::
osgeo::proj::operation::Conversion::createTwoPointEquidistant(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createUTM(osgeo::proj::util::PropertyMap const&, int, bool)
osgeo::proj::operation::Conversion::createVanDerGrinten(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createVerticalOffset(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createVerticalPerspective(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createWagnerIII(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
osgeo::proj::operation::Conversion::createWagnerII(osgeo::proj::util::PropertyMap const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, osgeo::proj::common::Length const&)
+36 -21
View File
@@ -91,8 +91,9 @@ static void logger(void *data, int level, const char *msg);
static void print(PJ_LOG_LEVEL log_level, const char *fmt, ...);
/* Prototypes from functions in this file */
char *column (char *buf, int n);
PJ_COORD parse_input_line (char *buf, int *columns, double fixed_height, double fixed_time);
static const char *column (const char *buf, int n);
static char *column (char *buf, int n);
PJ_COORD parse_input_line (const char *buf, int *columns, double fixed_height, double fixed_time);
static const char usage[] = {
@@ -203,9 +204,6 @@ int main(int argc, char **argv) {
OPTARGS *o;
char blank_comment[] = "";
char whitespace[] = " ";
char *comment;
char *comment_delimiter;
char *buf;
int i, nfields = 4, skip_lines = 0, verbose;
double fixed_z = HUGE_VAL, fixed_time = HUGE_VAL;
int decimals_angles = 10;
@@ -386,7 +384,8 @@ int main(int argc, char **argv) {
direction = PJ_FWD;
/* Allocate input buffer */
buf = static_cast<char*>(calloc (1, 10000));
constexpr int BUFFER_SIZE = 10000;
char* buf = static_cast<char*>(calloc (1, BUFFER_SIZE));
if (nullptr==buf) {
print (PJ_LOG_ERROR, "%s: Out of memory", o->progname);
proj_destroy (P);
@@ -398,30 +397,43 @@ int main(int argc, char **argv) {
/* Loop over all records of all input files */
int previous_index = -1;
while (opt_input_loop (o, optargs_file_format_text)) {
int err;
void *ret = fgets (buf, 10000, o->input);
char *c = column (buf, 1);
char *bufptr = fgets (buf, BUFFER_SIZE - 1, o->input);
opt_eof_handler (o);
if (nullptr==ret) {
if (nullptr==bufptr) {
print (PJ_LOG_ERROR, "Read error in record %d", (int) o->record_index);
continue;
}
point = parse_input_line (buf, columns_xyzt, fixed_z, fixed_time);
const bool bFirstLine = o->input_index != previous_index;
previous_index = o->input_index;
if( bFirstLine &&
static_cast<uint8_t>(bufptr[0]) == 0xEF &&
static_cast<uint8_t>(bufptr[1]) == 0xBB &&
static_cast<uint8_t>(bufptr[2]) == 0xBF )
{
// Skip UTF-8 Byte Order Marker (BOM)
bufptr += 3;
}
point = parse_input_line (bufptr, columns_xyzt, fixed_z, fixed_time);
if (skip_lines > 0) {
skip_lines--;
continue;
}
/* if it's a comment or blank line, we reflect it */
const char *c = column (bufptr, 1);
if (c && ((*c=='\0') || (*c=='#'))) {
fprintf (fout, "%s", buf);
fprintf (fout, "%s", bufptr);
continue;
}
if (HUGE_VAL==point.xyzt.x) {
/* otherwise, it must be a syntax error */
print (PJ_LOG_NONE, "# Record %d UNREADABLE: %s", (int) o->record_index, buf);
print (PJ_LOG_NONE, "# Record %d UNREADABLE: %s", (int) o->record_index, bufptr);
print (PJ_LOG_ERROR, "%s: Could not parse file '%s' line %d", o->progname, opt_filename (o), opt_record (o));
continue;
}
@@ -437,27 +449,27 @@ int main(int argc, char **argv) {
if (HUGE_VAL==point.xyzt.x) {
/* transformation error */
print (PJ_LOG_NONE, "# Record %d TRANSFORMATION ERROR: %s (%s)",
(int) o->record_index, buf, proj_errno_string (proj_errno(P)));
(int) o->record_index, bufptr, proj_errno_string (proj_errno(P)));
proj_errno_restore (P, err);
continue;
}
proj_errno_restore (P, err);
/* handle comment string */
comment = column(buf, nfields+1);
char* comment = column(bufptr, nfields+1);
if (opt_given(o, "c")) {
/* what number is the last coordinate column in the input data? */
int colmax = 0;
for (i=0; i<4; i++)
colmax = MAX(colmax, columns_xyzt[i]);
comment = column(buf, colmax+1);
comment = column(bufptr, colmax+1);
}
/* remove the line feed from comment, as logger() above, invoked
by print() below (output), will add one */
size_t len = strlen(comment);
if (len >= 1)
comment[len - 1] = '\0';
comment_delimiter = *comment ? whitespace : blank_comment;
const char* comment_delimiter = *comment ? whitespace : blank_comment;
/* Time to print the result */
/* use same arguments to printf format string for both radians and
@@ -500,7 +512,7 @@ int main(int argc, char **argv) {
/* return a pointer to the n'th column of buf */
char *column (char *buf, int n) {
static const char *column (const char *buf, int n) {
int i;
if (n <= 0)
return buf;
@@ -515,19 +527,22 @@ char *column (char *buf, int n) {
return buf;
}
static char *column (char *buf, int n) {
return const_cast<char*>(column(const_cast<const char*>(buf), n));
}
/* column to double */
static double cold (char *args, int col) {
static double cold (const char *args, int col) {
char *endp;
char *target;
double d;
target = column (args, col);
const char* target = column (args, col);
d = proj_strtod (target, &endp);
if (endp==target)
return HUGE_VAL;
return d;
}
PJ_COORD parse_input_line (char *buf, int *columns, double fixed_height, double fixed_time) {
PJ_COORD parse_input_line (const char *buf, int *columns, double fixed_height, double fixed_time) {
PJ_COORD err = proj_coord (HUGE_VAL, HUGE_VAL, HUGE_VAL, HUGE_VAL);
PJ_COORD result = err;
int prev_errno = errno;
+66 -2
View File
@@ -99,13 +99,25 @@ static void process(FILE *fid)
{
char line[MAX_LINE + 3], *s, pline[40];
PJ_UV data;
bool bFirstLine = true;
for (;;) {
for (;; bFirstLine = false ) {
double z;
++emess_dat.File_line;
if (!(s = fgets(line, MAX_LINE, fid)))
break;
if( bFirstLine &&
static_cast<uint8_t>(s[0]) == 0xEF &&
static_cast<uint8_t>(s[1]) == 0xBB &&
static_cast<uint8_t>(s[2]) == 0xBF )
{
// Skip UTF-8 Byte Order Marker (BOM)
s += 3;
}
const char* pszLineAfterBOM = s;
if (!strchr(s, '\n')) { /* overlong line */
int c;
(void)strcat(s, "\n");
@@ -151,7 +163,7 @@ static void process(FILE *fid)
char temp;
temp = *s;
*s = '\0';
(void)fputs(line, stdout);
(void)fputs(pszLineAfterBOM, stdout);
*s = temp;
putchar('\t');
}
@@ -332,6 +344,25 @@ static std::string get_geog_crs_proj_string_from_proj_crs(PJ *src,
return ret;
}
// ---------------------------------------------------------------------------
static bool is3DCRS(const PJ* crs) {
auto type = proj_get_type(crs);
if( type == PJ_TYPE_COMPOUND_CRS )
return true;
if( type == PJ_TYPE_GEOGRAPHIC_3D_CRS )
return true;
if( type == PJ_TYPE_GEODETIC_CRS || type == PJ_TYPE_PROJECTED_CRS )
{
auto cs = proj_crs_get_coordinate_system(nullptr, crs);
assert(cs);
const bool ret = proj_cs_get_axis_count(nullptr, cs) == 3;
proj_destroy(cs);
return ret;
}
return false;
}
/************************************************************************/
/* main() */
/************************************************************************/
@@ -808,6 +839,39 @@ int main(int argc, char **argv) {
proj_destroy(dst);
dst = dst3D;
}
} else {
// Auto-promote source/target CRS if it is specified by its name,
// if it has a known 3D version of it and that the other CRS is 3D.
// e.g cs2cs "WGS 84 + EGM96 height" "WGS 84"
if (is3DCRS(dst) && !is3DCRS(src) &&
proj_get_id_code(src, 0) != nullptr &&
Identifier::isEquivalentName(fromStr.c_str(),
proj_get_name(src))) {
auto promoted = proj_crs_promote_to_3D(nullptr, nullptr, src);
if (promoted)
{
if (proj_get_id_code(promoted, 0) != nullptr) {
proj_destroy(src);
src = promoted;
} else {
proj_destroy(promoted);
}
}
} else if (is3DCRS(src) && !is3DCRS(dst) &&
proj_get_id_code(dst, 0) != nullptr &&
Identifier::isEquivalentName(toStr.c_str(),
proj_get_name(dst))) {
auto promoted = proj_crs_promote_to_3D(nullptr, nullptr, dst);
if (promoted)
{
if (proj_get_id_code(promoted, 0) != nullptr) {
proj_destroy(dst);
dst = promoted;
} else {
proj_destroy(promoted);
}
}
}
}
std::string authorityOption; /* keep this variable in this outer scope ! */
+41 -2
View File
@@ -804,6 +804,20 @@ static void outputOperationSummary(
// ---------------------------------------------------------------------------
static bool is3DCRS(const CRSPtr &crs) {
if (dynamic_cast<CompoundCRS *>(crs.get()))
return true;
auto geodCRS = dynamic_cast<GeodeticCRS *>(crs.get());
if (geodCRS)
return geodCRS->coordinateSystem()->axisList().size() == 3U;
auto projCRS = dynamic_cast<ProjectedCRS *>(crs.get());
if (projCRS)
return projCRS->coordinateSystem()->axisList().size() == 3U;
return false;
}
// ---------------------------------------------------------------------------
static void outputOperations(
DatabaseContextPtr dbContext, const std::string &sourceCRSStr,
const std::string &targetCRSStr, const ExtentPtr &bboxFilter,
@@ -825,7 +839,6 @@ static void outputOperations(
std::cerr << "source CRS string is not a CRS" << std::endl;
std::exit(1);
}
auto nnSourceCRS = NN_NO_CHECK(sourceCRS);
auto targetObj =
buildObject(dbContext, targetCRSStr, "crs", "target CRS", false,
@@ -836,8 +849,34 @@ static void outputOperations(
std::cerr << "target CRS string is not a CRS" << std::endl;
std::exit(1);
}
auto nnTargetCRS = NN_NO_CHECK(targetCRS);
if (dbContext && !promoteTo3D) {
// Auto-promote source/target CRS if it is specified by its name,
// if it has a known 3D version of it and that the other CRS is 3D.
// e.g projinfo -s "WGS 84 + EGM96 height" -t "WGS 84"
if (is3DCRS(targetCRS) && !is3DCRS(sourceCRS) &&
!sourceCRS->identifiers().empty() &&
Identifier::isEquivalentName(sourceCRSStr.c_str(),
sourceCRS->nameStr().c_str())) {
auto promoted =
sourceCRS->promoteTo3D(std::string(), dbContext).as_nullable();
if (!promoted->identifiers().empty()) {
sourceCRS = promoted;
}
} else if (is3DCRS(sourceCRS) && !is3DCRS(targetCRS) &&
!targetCRS->identifiers().empty() &&
Identifier::isEquivalentName(targetCRSStr.c_str(),
targetCRS->nameStr().c_str())) {
auto promoted =
targetCRS->promoteTo3D(std::string(), dbContext).as_nullable();
if (!promoted->identifiers().empty()) {
targetCRS = promoted;
}
}
}
auto nnSourceCRS = NN_NO_CHECK(sourceCRS);
auto nnTargetCRS = NN_NO_CHECK(targetCRS);
std::vector<CoordinateOperationNNPtr> list;
size_t spatialCriterionPartialIntersectionResultCount = 0;
bool spatialCriterionPartialIntersectionMoreRelevant = false;
+2 -1
View File
@@ -2400,7 +2400,8 @@ GTiffHGridShiftSet::open(PJ_CONTEXT *ctx, std::unique_ptr<File> fp,
return nullptr;
}
if (!unitLatShift.empty()) {
if (unitLatShift == "arc-second") {
if (unitLatShift == "arc-second" ||
unitLatShift == "arc-seconds per year") {
convFactorToRadian = ARC_SECOND_TO_RADIAN;
} else if (unitLatShift == "radian") {
convFactorToRadian = 1.0;
+9 -3
View File
@@ -8825,6 +8825,7 @@ PJ *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ *obj) {
pjNew->descr = "Set of coordinate operations";
pjNew->left = obj->left;
pjNew->right = obj->right;
pjNew->over = obj->over;
for (const auto &alt : obj->alternativeCoordinateOperations) {
auto co = dynamic_cast<const CoordinateOperation *>(
@@ -8857,11 +8858,14 @@ PJ *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ *obj) {
std::swap(maxxDst, maxyDst);
}
}
auto pjNormalized =
pj_obj_create(ctx, co->normalizeForVisualization());
pjNormalized->over = alt.pj->over;
pjNew->alternativeCoordinateOperations.emplace_back(
alt.idxInOriginalList, minxSrc, minySrc, maxxSrc,
maxySrc, minxDst, minyDst, maxxDst, maxyDst,
pj_obj_create(ctx, co->normalizeForVisualization()),
co->nameStr(), alt.accuracy, alt.isOffshore);
pjNormalized, co->nameStr(), alt.accuracy,
alt.isOffshore);
}
}
return pjNew.release();
@@ -8890,7 +8894,9 @@ PJ *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ *obj) {
return nullptr;
}
try {
return pj_obj_create(ctx, co->normalizeForVisualization());
auto pjNormalized = pj_obj_create(ctx, co->normalizeForVisualization());
pjNormalized->over = obj->over;
return pjNormalized;
} catch (const std::exception &e) {
proj_log_debug(ctx, __FUNCTION__, e.what());
return nullptr;
+69
View File
@@ -368,6 +368,16 @@ CRSNNPtr CRS::alterCSLinearUnit(const common::UnitOfMeasure &unit) const {
}
}
{
auto derivedProjCRS = dynamic_cast<const DerivedProjectedCRS *>(this);
if (derivedProjCRS) {
return DerivedProjectedCRS::create(
createPropertyMap(this), derivedProjCRS->baseCRS(),
derivedProjCRS->derivingConversion(),
derivedProjCRS->baseCRS()->coordinateSystem()->alterUnit(unit));
}
}
return NN_NO_CHECK(
std::dynamic_pointer_cast<CRS>(shared_from_this().as_nullable()));
}
@@ -1260,6 +1270,23 @@ CRSNNPtr CRS::promoteTo3D(const std::string &newName,
}
}
else if (auto derivedProjCRS =
dynamic_cast<const DerivedProjectedCRS *>(this)) {
const auto &axisList = derivedProjCRS->coordinateSystem()->axisList();
if (axisList.size() == 2) {
auto cs = cs::CartesianCS::create(util::PropertyMap(), axisList[0],
axisList[1],
verticalAxisIfNotAlreadyPresent);
auto baseProj3DCRS = util::nn_dynamic_pointer_cast<ProjectedCRS>(
derivedProjCRS->baseCRS()->promoteTo3D(
std::string(), dbContext, verticalAxisIfNotAlreadyPresent));
return util::nn_static_pointer_cast<CRS>(
DerivedProjectedCRS::create(
createProperties(), NN_CHECK_THROW(baseProj3DCRS),
derivedProjCRS->derivingConversion(), cs));
}
}
else if (auto geogCRS = dynamic_cast<const GeographicCRS *>(this)) {
const auto &axisList = geogCRS->coordinateSystem()->axisList();
if (axisList.size() == 2) {
@@ -1358,6 +1385,11 @@ CRSNNPtr CRS::demoteTo2D(const std::string &newName,
return derivedGeogCRS->demoteTo2D(newName, dbContext);
}
else if (auto derivedProjCRS =
dynamic_cast<const DerivedProjectedCRS *>(this)) {
return derivedProjCRS->demoteTo2D(newName, dbContext);
}
else if (auto geogCRS = dynamic_cast<const GeographicCRS *>(this)) {
return geogCRS->demoteTo2D(newName, dbContext);
}
@@ -3674,6 +3706,10 @@ bool VerticalCRS::_isEquivalentTo(
const util::IComparable *other, util::IComparable::Criterion criterion,
const io::DatabaseContextPtr &dbContext) const {
auto otherVertCRS = dynamic_cast<const VerticalCRS *>(other);
if (otherVertCRS == nullptr ||
!util::isOfExactType<VerticalCRS>(*otherVertCRS)) {
return false;
}
// TODO test geoidModel and velocityModel
return otherVertCRS != nullptr &&
SingleCRS::baseIsEquivalentTo(other, criterion, dbContext);
@@ -6493,6 +6529,39 @@ DerivedProjectedCRSNNPtr DerivedProjectedCRS::create(
// ---------------------------------------------------------------------------
/** \brief Return a variant of this CRS "demoted" to a 2D one, if not already
* the case.
*
*
* @param newName Name of the new CRS. If empty, nameStr() will be used.
* @param dbContext Database context to look for potentially already registered
* 2D CRS. May be nullptr.
* @return a new CRS demoted to 2D, or the current one if already 2D or not
* applicable.
* @since 9.1.1
*/
DerivedProjectedCRSNNPtr
DerivedProjectedCRS::demoteTo2D(const std::string &newName,
const io::DatabaseContextPtr &dbContext) const {
const auto &axisList = coordinateSystem()->axisList();
if (axisList.size() == 3) {
auto cs = cs::CartesianCS::create(util::PropertyMap(), axisList[0],
axisList[1]);
auto baseProj2DCRS = util::nn_dynamic_pointer_cast<ProjectedCRS>(
baseCRS()->demoteTo2D(std::string(), dbContext));
return DerivedProjectedCRS::create(
util::PropertyMap().set(common::IdentifiedObject::NAME_KEY,
!newName.empty() ? newName : nameStr()),
NN_CHECK_THROW(baseProj2DCRS), derivingConversion(), cs);
}
return NN_NO_CHECK(std::dynamic_pointer_cast<DerivedProjectedCRS>(
shared_from_this().as_nullable()));
}
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
void DerivedProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const {
const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2;
+212 -32
View File
@@ -1472,10 +1472,6 @@ struct WKTParser::Private {
CRSPtr buildCRS(const WKTNodeNNPtr &node);
CRSPtr dealWithEPSGCodeForInterpolationCRSParameter(
std::vector<OperationParameterNNPtr> &parameters,
std::vector<ParameterValueNNPtr> &values);
TransformationNNPtr buildCoordinateOperation(const WKTNodeNNPtr &node);
ConcatenatedOperationNNPtr
@@ -3205,6 +3201,14 @@ CRSNNPtr WKTParser::Private::buildDerivedGeodeticCRS(const WKTNodeNNPtr &node) {
auto ellipsoidalCS = nn_dynamic_pointer_cast<EllipsoidalCS>(cs);
if (ellipsoidalCS) {
if (ellipsoidalCS->axisList().size() == 3 &&
baseGeodCRS->coordinateSystem()->axisList().size() == 2) {
baseGeodCRS =
NN_NO_CHECK(util::nn_dynamic_pointer_cast<GeodeticCRS>(
baseGeodCRS->promoteTo3D(std::string(), dbContext_)));
}
return DerivedGeographicCRS::create(buildProperties(node), baseGeodCRS,
derivingConversion,
NN_NO_CHECK(ellipsoidalCS));
@@ -3337,6 +3341,11 @@ void WKTParser::Private::consumeParameters(
// ---------------------------------------------------------------------------
static CRSPtr dealWithEPSGCodeForInterpolationCRSParameter(
DatabaseContextPtr &dbContext,
std::vector<OperationParameterNNPtr> &parameters,
std::vector<ParameterValueNNPtr> &values);
ConversionNNPtr
WKTParser::Private::buildConversion(const WKTNodeNNPtr &node,
const UnitOfMeasure &defaultLinearUnit,
@@ -3371,8 +3380,8 @@ WKTParser::Private::buildConversion(const WKTNodeNNPtr &node,
->inverse()));
}
auto conv = Conversion::create(convProps, methodProps, parameters, values);
auto interpolationCRS =
dealWithEPSGCodeForInterpolationCRSParameter(parameters, values);
auto interpolationCRS = dealWithEPSGCodeForInterpolationCRSParameter(
dbContext_, parameters, values);
if (interpolationCRS)
conv->setInterpolationCRS(interpolationCRS);
return conv;
@@ -3380,12 +3389,13 @@ WKTParser::Private::buildConversion(const WKTNodeNNPtr &node,
// ---------------------------------------------------------------------------
CRSPtr WKTParser::Private::dealWithEPSGCodeForInterpolationCRSParameter(
static CRSPtr dealWithEPSGCodeForInterpolationCRSParameter(
DatabaseContextPtr &dbContext,
std::vector<OperationParameterNNPtr> &parameters,
std::vector<ParameterValueNNPtr> &values) {
// Transform EPSG hacky PARAMETER["EPSG code for Interpolation CRS",
// crs_epsg_code] into proper interpolation CRS
if (dbContext_ != nullptr) {
if (dbContext != nullptr) {
for (size_t i = 0; i < parameters.size(); ++i) {
const auto &l_name = parameters[i]->nameStr();
const auto epsgCode = parameters[i]->getEPSGCode();
@@ -3398,7 +3408,7 @@ CRSPtr WKTParser::Private::dealWithEPSGCodeForInterpolationCRSParameter(
static_cast<int>(values[i]->value().getSIValue());
try {
auto authFactory = AuthorityFactory::create(
NN_NO_CHECK(dbContext_), Identifier::EPSG);
NN_NO_CHECK(dbContext), Identifier::EPSG);
auto interpolationCRS =
authFactory
->createGeographicCRS(internal::toString(code))
@@ -3461,8 +3471,8 @@ WKTParser::Private::buildCoordinateOperation(const WKTNodeNNPtr &node) {
defaultAngularUnit);
if (interpolationCRS == nullptr)
interpolationCRS =
dealWithEPSGCodeForInterpolationCRSParameter(parameters, values);
interpolationCRS = dealWithEPSGCodeForInterpolationCRSParameter(
dbContext_, parameters, values);
std::vector<PositionalAccuracyNNPtr> accuracies;
auto &accuracyNode = nodeP->lookForChild(WKTConstants::OPERATIONACCURACY);
@@ -4883,6 +4893,50 @@ CRSNNPtr WKTParser::Private::buildCompoundCRS(const WKTNodeNNPtr &node) {
// ---------------------------------------------------------------------------
static TransformationNNPtr buildTransformationForBoundCRS(
DatabaseContextPtr &dbContext,
const util::PropertyMap &abridgedNodeProperties,
const util::PropertyMap &methodNodeProperties, const CRSNNPtr &sourceCRS,
const CRSNNPtr &targetCRS, std::vector<OperationParameterNNPtr> &parameters,
std::vector<ParameterValueNNPtr> &values) {
auto interpolationCRS = dealWithEPSGCodeForInterpolationCRSParameter(
dbContext, parameters, values);
const auto sourceTransformationCRS(
createBoundCRSSourceTransformationCRS(sourceCRS, targetCRS));
auto transformation = Transformation::create(
abridgedNodeProperties, sourceTransformationCRS, targetCRS,
interpolationCRS, methodNodeProperties, parameters, values,
std::vector<PositionalAccuracyNNPtr>());
// If the transformation is a "Geographic3D to GravityRelatedHeight" one,
// then the sourceCRS is expected to be a GeographicCRS and the target a
// VerticalCRS. Due to how things work in a BoundCRS, we have the opposite,
// so use our "GravityRelatedHeight to Geographic3D" method instead.
if (Transformation::isGeographic3DToGravityRelatedHeight(
transformation->method(), true) &&
dynamic_cast<VerticalCRS *>(sourceTransformationCRS.get()) &&
dynamic_cast<GeographicCRS *>(targetCRS.get())) {
auto fileParameter = transformation->parameterValue(
EPSG_NAME_PARAMETER_GEOID_CORRECTION_FILENAME,
EPSG_CODE_PARAMETER_GEOID_CORRECTION_FILENAME);
if (fileParameter &&
fileParameter->type() == ParameterValue::Type::FILENAME) {
auto filename = fileParameter->valueFile();
transformation =
Transformation::createGravityRelatedHeightToGeographic3D(
abridgedNodeProperties, sourceTransformationCRS, targetCRS,
interpolationCRS, filename,
std::vector<PositionalAccuracyNNPtr>());
}
}
return transformation;
}
// ---------------------------------------------------------------------------
BoundCRSNNPtr WKTParser::Private::buildBoundCRS(const WKTNodeNNPtr &node) {
const auto *nodeP = node->GP();
auto &abridgedNode =
@@ -4926,15 +4980,11 @@ BoundCRSNNPtr WKTParser::Private::buildBoundCRS(const WKTNodeNNPtr &node) {
consumeParameters(abridgedNode, true, parameters, values, defaultLinearUnit,
defaultAngularUnit);
auto interpolationCRS =
dealWithEPSGCodeForInterpolationCRSParameter(parameters, values);
const auto sourceTransformationCRS(
createBoundCRSSourceTransformationCRS(sourceCRS, targetCRS));
auto transformation = Transformation::create(
buildProperties(abridgedNode), sourceTransformationCRS,
NN_NO_CHECK(targetCRS), interpolationCRS, buildProperties(methodNode),
parameters, values, std::vector<PositionalAccuracyNNPtr>());
const auto nnSourceCRS = NN_NO_CHECK(sourceCRS);
const auto nnTargetCRS = NN_NO_CHECK(targetCRS);
const auto transformation = buildTransformationForBoundCRS(
dbContext_, buildProperties(abridgedNode), buildProperties(methodNode),
nnSourceCRS, nnTargetCRS, parameters, values);
return BoundCRS::create(buildProperties(node, false, false),
NN_NO_CHECK(sourceCRS), NN_NO_CHECK(targetCRS),
@@ -5145,6 +5195,13 @@ WKTParser::Private::buildDerivedProjectedCRS(const WKTNodeNNPtr &node) {
ThrowMissing(WKTConstants::CS_);
}
auto cs = buildCS(csNode, node, UnitOfMeasure::NONE);
if (cs->axisList().size() == 3 &&
baseProjCRS->coordinateSystem()->axisList().size() == 2) {
baseProjCRS = NN_NO_CHECK(util::nn_dynamic_pointer_cast<ProjectedCRS>(
baseProjCRS->promoteTo3D(std::string(), dbContext_)));
}
return DerivedProjectedCRS::create(buildProperties(node), baseProjCRS,
conversion, cs);
}
@@ -6229,12 +6286,9 @@ BoundCRSNNPtr JSONParser::buildBoundCRS(const json &j) {
values.emplace_back(ParameterValue::create(getMeasure(param)));
}
const auto sourceTransformationCRS(
createBoundCRSSourceTransformationCRS(sourceCRS, targetCRS));
auto transformation = Transformation::create(
buildProperties(transformationJ), sourceTransformationCRS, targetCRS,
nullptr, buildProperties(methodJ), parameters, values,
std::vector<PositionalAccuracyNNPtr>());
const auto transformation = buildTransformationForBoundCRS(
dbContext_, buildProperties(transformationJ), buildProperties(methodJ),
sourceCRS, targetCRS, parameters, values);
return BoundCRS::create(buildProperties(j,
/* removeInverseOf= */ false,
@@ -7283,6 +7337,24 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text,
}
}
// If there's exactly only one object whose name is equivalent
// to the user input, return it.
IdentifiedObjectPtr identifiedObj;
for (const auto &obj : res) {
if (Identifier::isEquivalentName(obj->nameStr().c_str(),
objectName.c_str())) {
if (identifiedObj == nullptr) {
identifiedObj = obj.as_nullable();
} else {
identifiedObj = nullptr;
break;
}
}
}
if (identifiedObj) {
return identifiedObj;
}
std::string msg("several objects matching this name: ");
bool first = true;
for (const auto &obj : res) {
@@ -8618,7 +8690,8 @@ const std::string &PROJStringFormatter::toString() const {
iterNext = std::next(iterNext);
}
}
if (ok && iterNext != steps.end()) {
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "axisswap" &&
@@ -8628,7 +8701,8 @@ const std::string &PROJStringFormatter::toString() const {
iterNext = std::next(iterNext);
}
}
if (ok && iterNext != steps.end()) {
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "unitconvert" &&
@@ -8640,7 +8714,8 @@ const std::string &PROJStringFormatter::toString() const {
}
}
auto iterVgridshift = iterNext;
if (ok && iterNext != steps.end()) {
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "vgridshift") {
@@ -8648,7 +8723,8 @@ const std::string &PROJStringFormatter::toString() const {
iterNext = std::next(iterNext);
}
}
if (ok && iterNext != steps.end()) {
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "unitconvert" &&
@@ -8659,7 +8735,8 @@ const std::string &PROJStringFormatter::toString() const {
iterNext = std::next(iterNext);
}
}
if (ok && iterNext != steps.end()) {
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "axisswap" &&
@@ -8669,7 +8746,8 @@ const std::string &PROJStringFormatter::toString() const {
iterNext = std::next(iterNext);
}
}
if (ok && iterNext != steps.end()) {
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "pop" &&
@@ -8677,6 +8755,7 @@ const std::string &PROJStringFormatter::toString() const {
nextStep.paramValues[0].keyEquals("v_1") &&
nextStep.paramValues[1].keyEquals("v_2")) {
ok = true;
// iterNext = std::next(iterNext);
}
}
if (ok) {
@@ -8688,6 +8767,107 @@ const std::string &PROJStringFormatter::toString() const {
}
}
// +step +proj=axisswap +order=2,1
// +step +proj=unitconvert +xy_in=deg +xy_out=rad
// +step +proj=vgridshift ...
// +step +proj=unitconvert +xy_in=rad +xy_out=deg
// +step +proj=axisswap +order=2,1
// +step +proj=push +v_1 +v_2
// +step +proj=axisswap +order=2,1
// +step +proj=unitconvert +xy_in=deg +xy_out=rad
// ==>
// +step +proj=push +v_1 +v_2
// +step +proj=axisswap +order=2,1
// +step +proj=unitconvert +xy_in=deg +xy_out=rad
// +step +proj=vgridshift ...
if (prevStep.name == "axisswap" && prevStepParamCount == 1 &&
prevStep.paramValues[0].equals("order", "2,1") &&
curStep.name == "unitconvert" && curStepParamCount == 2 &&
!curStep.inverted &&
curStep.paramValues[0].equals("xy_in", "deg") &&
curStep.paramValues[1].equals("xy_out", "rad")) {
auto iterNext = std::next(iterCur);
bool ok = false;
auto iterVgridshift = iterNext;
if (iterNext != steps.end()) {
auto &nextStep = *iterNext;
if (nextStep.name == "vgridshift") {
ok = true;
iterNext = std::next(iterNext);
}
}
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "unitconvert" && !nextStep.inverted &&
nextStep.paramValues.size() == 2 &&
nextStep.paramValues[0].equals("xy_in", "rad") &&
nextStep.paramValues[1].equals("xy_out", "deg")) {
ok = true;
iterNext = std::next(iterNext);
}
}
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "axisswap" &&
nextStep.paramValues.size() == 1 &&
nextStep.paramValues[0].equals("order", "2,1")) {
ok = true;
iterNext = std::next(iterNext);
}
}
auto iterPush = iterNext;
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "push" &&
nextStep.paramValues.size() == 2 &&
nextStep.paramValues[0].keyEquals("v_1") &&
nextStep.paramValues[1].keyEquals("v_2")) {
ok = true;
iterNext = std::next(iterNext);
}
}
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "axisswap" &&
nextStep.paramValues.size() == 1 &&
nextStep.paramValues[0].equals("order", "2,1")) {
ok = true;
iterNext = std::next(iterNext);
}
}
ok &= iterNext != steps.end();
if (ok) {
ok = false;
auto &nextStep = *iterNext;
if (nextStep.name == "unitconvert" &&
nextStep.paramValues.size() == 2 &&
!nextStep.inverted &&
nextStep.paramValues[0].equals("xy_in", "deg") &&
nextStep.paramValues[1].equals("xy_out", "rad")) {
ok = true;
// iterNext = std::next(iterNext);
}
}
if (ok) {
auto stepVgridshift = *iterVgridshift;
steps.erase(iterPrev, iterPush);
steps.insert(std::next(iterNext), stepVgridshift);
iterPrev = iterPush;
iterCur = std::next(iterPush);
continue;
}
}
++iterCur;
}
}
+110 -1
View File
@@ -3465,12 +3465,16 @@ void Conversion::_exportToPROJString(
methodEPSGCode == EPSG_CODE_METHOD_AFFINE_PARAMETRIC_TRANSFORMATION;
const bool isGeographicGeocentric =
methodEPSGCode == EPSG_CODE_METHOD_GEOGRAPHIC_GEOCENTRIC;
const bool isGeographicOffsets =
methodEPSGCode == EPSG_CODE_METHOD_GEOGRAPHIC2D_OFFSETS ||
methodEPSGCode == EPSG_CODE_METHOD_GEOGRAPHIC3D_OFFSETS ||
methodEPSGCode == EPSG_CODE_METHOD_GEOGRAPHIC2D_WITH_HEIGHT_OFFSETS;
const bool isHeightDepthReversal =
methodEPSGCode == EPSG_CODE_METHOD_HEIGHT_DEPTH_REVERSAL;
const bool applySourceCRSModifiers =
!isZUnitConversion && !isAffineParametric &&
!isAxisOrderReversal(methodEPSGCode) && !isGeographicGeocentric &&
!isHeightDepthReversal;
!isGeographicOffsets && !isHeightDepthReversal;
bool applyTargetCRSModifiers = applySourceCRSModifiers;
if (formatter->getCRSExport()) {
@@ -4256,5 +4260,110 @@ ConversionNNPtr Conversion::identify() const {
// ---------------------------------------------------------------------------
/** \brief Instantiate a conversion with method Geographic 2D offsets
*
* This method is defined as [EPSG:9619]
* (https://www.epsg-registry.org/export.htm?gml=urn:ogc:def:method:EPSG::9619)
* *
* @param properties See \ref general_properties of the conversion.
* At minimum the name should be defined.
* @param offsetLat Latitude offset to add.
* @param offsetLon Longitude offset to add.
* @return new conversion.
*/
ConversionNNPtr
Conversion::createGeographic2DOffsets(const util::PropertyMap &properties,
const common::Angle &offsetLat,
const common::Angle &offsetLon) {
return create(
properties,
createMethodMapNameEPSGCode(EPSG_CODE_METHOD_GEOGRAPHIC2D_OFFSETS),
VectorOfParameters{
createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_LATITUDE_OFFSET),
createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_LONGITUDE_OFFSET)},
VectorOfValues{offsetLat, offsetLon});
}
// ---------------------------------------------------------------------------
/** \brief Instantiate a conversion with method Geographic 3D offsets
*
* This method is defined as [EPSG:9660]
* (https://www.epsg-registry.org/export.htm?gml=urn:ogc:def:method:EPSG::9660)
* *
* @param properties See \ref general_properties of the Conversion.
* At minimum the name should be defined.
* @param offsetLat Latitude offset to add.
* @param offsetLon Longitude offset to add.
* @param offsetHeight Height offset to add.
* @return new Conversion.
*/
ConversionNNPtr Conversion::createGeographic3DOffsets(
const util::PropertyMap &properties, const common::Angle &offsetLat,
const common::Angle &offsetLon, const common::Length &offsetHeight) {
return create(
properties,
createMethodMapNameEPSGCode(EPSG_CODE_METHOD_GEOGRAPHIC3D_OFFSETS),
VectorOfParameters{
createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_LATITUDE_OFFSET),
createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_LONGITUDE_OFFSET),
createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_VERTICAL_OFFSET)},
VectorOfValues{offsetLat, offsetLon, offsetHeight});
}
// ---------------------------------------------------------------------------
/** \brief Instantiate a conversion with method Geographic 2D with
* height
* offsets
*
* This method is defined as [EPSG:9618]
* (https://www.epsg-registry.org/export.htm?gml=urn:ogc:def:method:EPSG::9618)
* *
* @param properties See \ref general_properties of the Conversion.
* At minimum the name should be defined.
* @param offsetLat Latitude offset to add.
* @param offsetLon Longitude offset to add.
* @param offsetHeight Geoid undulation to add.
* @return new Conversion.
*/
ConversionNNPtr Conversion::createGeographic2DWithHeightOffsets(
const util::PropertyMap &properties, const common::Angle &offsetLat,
const common::Angle &offsetLon, const common::Length &offsetHeight) {
return create(
properties,
createMethodMapNameEPSGCode(
EPSG_CODE_METHOD_GEOGRAPHIC2D_WITH_HEIGHT_OFFSETS),
VectorOfParameters{
createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_LATITUDE_OFFSET),
createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_LONGITUDE_OFFSET),
createOpParamNameEPSGCode(EPSG_CODE_PARAMETER_GEOID_UNDULATION)},
VectorOfValues{offsetLat, offsetLon, offsetHeight});
}
// ---------------------------------------------------------------------------
/** \brief Instantiate a conversion with method Vertical Offset.
*
* This method is defined as [EPSG:9616]
* (https://www.epsg-registry.org/export.htm?gml=urn:ogc:def:method:EPSG::9616)
* *
* @param properties See \ref general_properties of the Conversion.
* At minimum the name should be defined.
* @param offsetHeight Geoid undulation to add.
* @return new Conversion.
*/
ConversionNNPtr
Conversion::createVerticalOffset(const util::PropertyMap &properties,
const common::Length &offsetHeight) {
return create(properties,
createMethodMapNameEPSGCode(EPSG_CODE_METHOD_VERTICAL_OFFSET),
VectorOfParameters{createOpParamNameEPSGCode(
EPSG_CODE_PARAMETER_VERTICAL_OFFSET)},
VectorOfValues{offsetHeight});
}
// ---------------------------------------------------------------------------
} // namespace operation
NS_PROJ_END
@@ -1814,6 +1814,56 @@ CoordinateOperationFactory::Private::findOpsInRegistryDirectTo(
// ---------------------------------------------------------------------------
static std::vector<crs::GeodeticCRSNNPtr>
findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory,
const crs::GeodeticCRS *crs,
const datum::GeodeticReferenceFrame *datum) {
std::vector<crs::GeodeticCRSNNPtr> candidates;
assert(datum);
const auto &ids = datum->identifiers();
const auto &datumName = datum->nameStr();
if (!ids.empty()) {
for (const auto &id : ids) {
const auto &authName = *(id->codeSpace());
const auto &code = id->code();
if (!authName.empty()) {
const auto crsIds = crs->identifiers();
const auto tmpFactory =
(crsIds.size() == 1 &&
*(crsIds.front()->codeSpace()) == authName)
? io::AuthorityFactory::create(
authFactory->databaseContext(), authName)
.as_nullable()
: authFactory;
auto l_candidates = tmpFactory->createGeodeticCRSFromDatum(
authName, code, std::string());
for (const auto &candidate : l_candidates) {
candidates.emplace_back(candidate);
}
}
}
} else if (datumName != "unknown" && datumName != "unnamed") {
auto matches = authFactory->createObjectsFromName(
datumName,
{io::AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, false,
2);
if (matches.size() == 1) {
const auto &match = matches.front();
if (datum->_isEquivalentTo(
match.get(), util::IComparable::Criterion::EQUIVALENT) &&
!match->identifiers().empty()) {
return findCandidateGeodCRSForDatum(
authFactory, crs,
dynamic_cast<const datum::GeodeticReferenceFrame *>(
match.get()));
}
}
}
return candidates;
}
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
// Look in the authority registry for operations from sourceCRS to targetCRS
@@ -1834,9 +1884,59 @@ CoordinateOperationFactory::Private::findsOpsInRegistryWithIntermediate(
assert(authFactory);
std::list<std::pair<std::string, std::string>> sourceIds;
std::list<std::pair<std::string, std::string>> targetIds;
buildCRSIds(sourceCRS, context, sourceIds);
if (sourceIds.empty()) {
auto geodSrc = dynamic_cast<crs::GeodeticCRS *>(sourceCRS.get());
if (geodSrc) {
const auto candidatesSrcGeod(findCandidateGeodCRSForDatum(
authFactory, geodSrc,
geodSrc
->datumNonNull(authFactory->databaseContext().as_nullable())
.get()));
std::vector<CoordinateOperationNNPtr> res;
for (const auto &candidateSrcGeod : candidatesSrcGeod) {
if (candidateSrcGeod->coordinateSystem()->axisList().size() ==
geodSrc->coordinateSystem()->axisList().size() &&
((dynamic_cast<crs::GeographicCRS *>(sourceCRS.get()) !=
nullptr) ==
(dynamic_cast<crs::GeographicCRS *>(
candidateSrcGeod.get()) != nullptr))) {
const auto opsWithIntermediate =
findsOpsInRegistryWithIntermediate(
candidateSrcGeod, targetCRS, context,
useCreateBetweenGeodeticCRSWithDatumBasedIntermediates);
if (!opsWithIntermediate.empty()) {
const auto opsFirst = createOperations(
sourceCRS, candidateSrcGeod, context);
for (const auto &opFirst : opsFirst) {
for (const auto &opSecond : opsWithIntermediate) {
try {
res.emplace_back(
ConcatenatedOperation::
createComputeMetadata(
{opFirst, opSecond},
disallowEmptyIntersection));
} catch (
const InvalidOperationEmptyIntersection &) {
}
}
}
if (!res.empty())
return res;
}
}
}
}
return std::vector<CoordinateOperationNNPtr>();
}
std::list<std::pair<std::string, std::string>> targetIds;
buildCRSIds(targetCRS, context, targetIds);
if (targetIds.empty()) {
return applyInverse(findsOpsInRegistryWithIntermediate(
targetCRS, sourceCRS, context,
useCreateBetweenGeodeticCRSWithDatumBasedIntermediates));
}
const auto gridAvailabilityUse = context.context->getGridAvailabilityUse();
for (const auto &idSrc : sourceIds) {
@@ -2099,7 +2199,17 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final
->demoteTo2D(std::string(), nullptr)
.get(),
util::IComparable::Criterion::EQUIVALENT)) {
const int methodEPSGCode = transf->method()->getEPSGCode();
int methodEPSGCode = transf->method()->getEPSGCode();
if (methodEPSGCode == 0) {
// If the transformation is actually an inverse transformation,
// we will not get the EPSG code. So get the forward
// transformation.
const auto invTrans = transf->inverse();
const auto invTransAsTrans =
dynamic_cast<Transformation *>(invTrans.get());
if (invTransAsTrans)
methodEPSGCode = invTransAsTrans->method()->getEPSGCode();
}
const bool bGeocentricTranslation =
methodEPSGCode ==
@@ -2649,56 +2759,6 @@ static bool hasIdentifiers(const CoordinateOperationNNPtr &op) {
// ---------------------------------------------------------------------------
static std::vector<crs::CRSNNPtr>
findCandidateGeodCRSForDatum(const io::AuthorityFactoryPtr &authFactory,
const crs::GeodeticCRS *crs,
const datum::GeodeticReferenceFrame *datum) {
std::vector<crs::CRSNNPtr> candidates;
assert(datum);
const auto &ids = datum->identifiers();
const auto &datumName = datum->nameStr();
if (!ids.empty()) {
for (const auto &id : ids) {
const auto &authName = *(id->codeSpace());
const auto &code = id->code();
if (!authName.empty()) {
const auto crsIds = crs->identifiers();
const auto tmpFactory =
(crsIds.size() == 1 &&
*(crsIds.front()->codeSpace()) == authName)
? io::AuthorityFactory::create(
authFactory->databaseContext(), authName)
.as_nullable()
: authFactory;
auto l_candidates = tmpFactory->createGeodeticCRSFromDatum(
authName, code, std::string());
for (const auto &candidate : l_candidates) {
candidates.emplace_back(candidate);
}
}
}
} else if (datumName != "unknown" && datumName != "unnamed") {
auto matches = authFactory->createObjectsFromName(
datumName,
{io::AuthorityFactory::ObjectType::GEODETIC_REFERENCE_FRAME}, false,
2);
if (matches.size() == 1) {
const auto &match = matches.front();
if (datum->_isEquivalentTo(
match.get(), util::IComparable::Criterion::EQUIVALENT) &&
!match->identifiers().empty()) {
return findCandidateGeodCRSForDatum(
authFactory, crs,
dynamic_cast<const datum::GeodeticReferenceFrame *>(
match.get()));
}
}
}
return candidates;
}
// ---------------------------------------------------------------------------
void CoordinateOperationFactory::Private::setCRSs(
CoordinateOperation *co, const crs::CRSNNPtr &sourceCRS,
const crs::CRSNNPtr &targetCRS) {
@@ -4001,6 +4061,10 @@ void CoordinateOperationFactory::Private::createOperationsGeodToGeod(
res.emplace_back(
Conversion::createGeographicGeocentric(sourceCRS, targetCRS));
} else if (isSrcGeocentric && geogDst) {
#if 0
// The below logic was used between PROJ >= 6.0 and < 9.2
// It assumed that the geocentric origin of the 2 datums
// matched.
std::string interm_crs_name(geogDst->nameStr());
interm_crs_name += " (geocentric)";
auto interm_crs =
@@ -4017,15 +4081,42 @@ void CoordinateOperationFactory::Private::createOperationsGeodToGeod(
createBallparkGeocentricTranslation(sourceCRS, interm_crs);
auto opSecond =
Conversion::createGeographicGeocentric(interm_crs, targetCRS);
res.emplace_back(ConcatenatedOperation::createComputeMetadata(
{opFirst, opSecond}, disallowEmptyIntersection));
#else
// The below logic is used since PROJ >= 9.2. It emulates the
// behavior of PROJ < 6 by converting from the source geocentric CRS
// to its corresponding geographic CRS, and then doing a null
// geographic offset between that CRS and the target geographic CRS
std::string interm_crs_name(geodSrc->nameStr());
interm_crs_name += " (geographic)";
auto interm_crs = util::nn_static_pointer_cast<crs::CRS>(
crs::GeographicCRS::create(
addDomains(util::PropertyMap().set(
common::IdentifiedObject::NAME_KEY,
interm_crs_name),
geodSrc),
geodSrc->datum(), geodSrc->datumEnsemble(),
cs::EllipsoidalCS::createLongitudeLatitudeEllipsoidalHeight(
common::UnitOfMeasure::DEGREE,
common::UnitOfMeasure::METRE)));
auto opFirst =
Conversion::createGeographicGeocentric(sourceCRS, interm_crs);
auto opsSecond = createOperations(interm_crs, targetCRS, context);
for (const auto &opSecond : opsSecond) {
try {
res.emplace_back(
ConcatenatedOperation::createComputeMetadata(
{opFirst, opSecond}, disallowEmptyIntersection));
} catch (const InvalidOperationEmptyIntersection &) {
}
}
#endif
} else {
// Apply previous case in reverse way
std::vector<CoordinateOperationNNPtr> resTmp;
createOperationsGeodToGeod(targetCRS, sourceCRS, context, geodDst,
geodSrc, resTmp);
assert(resTmp.size() == 1);
res.emplace_back(resTmp.front()->inverse());
resTmp = applyInverse(resTmp);
res.insert(res.end(), resTmp.begin(), resTmp.end());
}
return;
+12 -8
View File
@@ -1842,9 +1842,8 @@ _getHeightToGeographic3DFilename(const SingleOperation *op, bool allowInverse) {
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
static bool
isGeographic3DToGravityRelatedHeight(const OperationMethodNNPtr &method,
bool allowInverse) {
bool Transformation::isGeographic3DToGravityRelatedHeight(
const OperationMethodNNPtr &method, bool allowInverse) {
const auto &methodName = method->nameStr();
static const char *const methodCodes[] = {
"1025", // Geographic3D to GravityRelatedHeight (EGM2008)
@@ -2155,7 +2154,7 @@ TransformationNNPtr SingleOperation::substitutePROJAlternativeGridNames(
}
}
if (isGeographic3DToGravityRelatedHeight(method(), false)) {
if (Transformation::isGeographic3DToGravityRelatedHeight(method(), false)) {
const auto &fileParameter =
parameterValue(EPSG_NAME_PARAMETER_GEOID_CORRECTION_FILENAME,
EPSG_CODE_PARAMETER_GEOID_CORRECTION_FILENAME);
@@ -3648,7 +3647,7 @@ bool SingleOperation::exportToPROJStringGeneric(
return true;
}
if (isGeographic3DToGravityRelatedHeight(method(), true)) {
if (Transformation::isGeographic3DToGravityRelatedHeight(method(), true)) {
auto fileParameter =
parameterValue(EPSG_NAME_PARAMETER_GEOID_CORRECTION_FILENAME,
EPSG_CODE_PARAMETER_GEOID_CORRECTION_FILENAME);
@@ -3752,16 +3751,21 @@ bool SingleOperation::exportToPROJStringGeneric(
double offsetDeg =
parameterValueNumeric(EPSG_CODE_PARAMETER_LONGITUDE_OFFSET,
common::UnitOfMeasure::DEGREE);
auto l_sourceCRS = sourceCRS();
auto sourceCRSGeog =
dynamic_cast<const crs::GeographicCRS *>(sourceCRS().get());
l_sourceCRS ? extractGeographicCRSIfGeographicCRSOrEquivalent(
NN_NO_CHECK(l_sourceCRS))
: nullptr;
if (!sourceCRSGeog) {
throw io::FormattingException(
concat("Can apply ", methodName, " only to GeographicCRS"));
}
auto l_targetCRS = targetCRS();
auto targetCRSGeog =
dynamic_cast<const crs::GeographicCRS *>(targetCRS().get());
l_targetCRS ? extractGeographicCRSIfGeographicCRSOrEquivalent(
NN_NO_CHECK(l_targetCRS))
: nullptr;
if (!targetCRSGeog) {
throw io::FormattingException(
concat("Can apply ", methodName + " only to GeographicCRS"));
+9
View File
@@ -28,6 +28,7 @@
/*! @cond Doxygen_Suppress */
#include <limits>
#include <vector>
#include <string>
@@ -277,6 +278,14 @@ void CPLJSonStreamingWriter::Add(double dfVal, int nPrecision)
{
Print( dfVal > 0 ? "\"Infinity\"" : "\"-Infinity\"" );
}
else if( dfVal >= std::numeric_limits<int>::min() &&
dfVal <= std::numeric_limits<int>::max() &&
static_cast<int>(dfVal) == dfVal )
{
// Avoid rounding issues on some platforms like armel, with numbers
// like 2005. See https://github.com/OSGeo/PROJ/issues/3297
Print(CPLSPrintf("%d", static_cast<int>(dfVal)));
}
else
{
char szFormatting[10];
+3
View File
@@ -2,6 +2,9 @@
add_executable(geodtest geodtest.c)
target_link_libraries(geodtest ${PROJ_LIBRARIES})
if(HAVE_LIBM)
target_link_libraries(geodtest m)
endif()
add_executable(geodsigntest geodsigntest.c)
# geodsigntest includes geodesic.c directly so it doesn't need to link
+1
View File
@@ -0,0 +1 @@
0 3 0
+3
View File
@@ -159,6 +159,9 @@ echo "Test cct with WKT in a file" >> ${OUT}
echo "3541657.3778 948984.2343 5201383.5231 2020.5" | $EXE @in.wkt >>${OUT}
rm in.wkt
echo "Test cct with input file with UTF-8 BOM marker" >> ${OUT}
$EXE +proj=noop ${TEST_CLI_DIR}/input_with_utf8_bom.txt >> ${OUT}
# do 'diff' with distribution results
echo "diff ${OUT} with testcct_out.dist"
diff -u ${OUT} ${TEST_CLI_DIR}/testcct_out.dist
+2
View File
@@ -24,3 +24,5 @@ Test cct with object code initialization and file input
3541658.5334 948984.5160 5201383.7251 2020.5000
Test cct with WKT in a file
3541657.9112 948983.7503 5201383.2482 2020.5000
Test cct with input file with UTF-8 BOM marker
0.0000 3.0000 0.0000 inf
+8
View File
@@ -131,6 +131,14 @@ echo "Testing EPSG:32631 --3d" >> ${OUT}
$EXE EPSG:32631 --3d >>${OUT} 2>&1
echo "" >>${OUT}
echo "Testing -s "WGS 84" -t "WGS 84 + EGM96 height" --hide-ballpark --summary" >> ${OUT}
$EXE -s "WGS 84" -t "WGS 84 + EGM96 height" --hide-ballpark --summary >>${OUT} 2>&1
echo "" >>${OUT}
echo "Testing -s "WGS 84 + EGM96 height" -t "WGS 84" --hide-ballpark --summary" >> ${OUT}
$EXE -s "WGS 84 + EGM96 height" -t "WGS 84" --hide-ballpark --summary >>${OUT} 2>&1
echo "" >>${OUT}
echo "Testing -s EPSG:32631 -t EPSG:4326+3855 --summary" >> ${OUT}
$EXE -s EPSG:32631 -t EPSG:4326+3855 --summary >>${OUT} 2>&1
echo "" >>${OUT}
+8
View File
@@ -1240,6 +1240,14 @@ PROJCRS["WGS 84 / UTM zone 31N",
BBOX[0,0,84,6]],
REMARK["Promoted to 3D from EPSG:32631"]]
Testing -s WGS 84 -t WGS 84 + EGM96 height --hide-ballpark --summary
Candidate operations found: 1
unknown id, WGS 84 to EGM96 height (1), 1 m, World.
Testing -s WGS 84 + EGM96 height -t WGS 84 --hide-ballpark --summary
Candidate operations found: 1
unknown id, Inverse of WGS 84 to EGM96 height (1), 1 m, World.
Testing -s EPSG:32631 -t EPSG:4326+3855 --summary
Candidate operations found: 1
unknown id, Inverse of UTM zone 31N + Inverse of Null geographic offset from WGS 84 to WGS 84, 0 m, World.
+13
View File
@@ -1052,6 +1052,19 @@ $EXE -E EPSG:4326 "NAD83(HARN)" >> ${OUT} <<EOF
34 -120
EOF
echo "##############################################################" >> ${OUT}
echo "Check that we promote CRS specified by name to 3D when the other one is 3D" >> ${OUT}
$EXE -d 3 -E "WGS 84" "WGS 84 + EGM96 height" >> ${OUT} <<EOF
49 2 50
EOF
$EXE -d 3 -E "WGS 84 + EGM96 height" "WGS 84" >> ${OUT} <<EOF
49 2 0
EOF
echo "##############################################################" >> ${OUT}
echo "Test input file with UTF-8 BOM marker" >> ${OUT}
$EXE -d 3 -E EPSG:4326 EPSG:32631 ${TEST_CLI_DIR}/input_with_utf8_bom.txt >> ${OUT}
# Done!
# do 'diff' with distribution results
+7
View File
@@ -506,3 +506,10 @@ Check that we can use a transformation spanning the antimeridian (should use Pul
##############################################################
Check that we select the operation that has the smallest area of use, when 2 have the same accuracy
34 -120 33d59'59.983"N 119d59'59.955"W 0.000
##############################################################
Check that we promote CRS specified by name to 3D when the other one is 3D
49 2 50 49.000 2.000 4.936
49 2 0 49.000 2.000 45.064
##############################################################
Test input file with UTF-8 BOM marker
0 3 0 500000.000 0.000 0.000
+11
View File
@@ -1105,6 +1105,10 @@ TEST(gie, proj_create_crs_to_crs_from_pj_force_over) {
EXPECT_NEAR(input_over.xyz.x, input_over_inv.xyz.x, 1e-8);
EXPECT_NEAR(input_over.xyz.y, input_over_inv.xyz.y, 1e-8);
auto Pnormalized = proj_normalize_for_visualization(ctx, P);
ASSERT_TRUE(Pnormalized->over);
proj_destroy(Pnormalized);
proj_destroy(P);
}
@@ -1196,6 +1200,13 @@ TEST(gie, proj_create_crs_to_crs_from_pj_force_over) {
EXPECT_NEAR(output_over.xyz.x, 4980122.749364435, 1e-8);
EXPECT_NEAR(output_over.xyz.y, 14467212.882603768, 1e-8);
auto Pnormalized = proj_normalize_for_visualization(ctx, P);
ASSERT_TRUE(Pnormalized->over);
for (const auto &op : Pnormalized->alternativeCoordinateOperations) {
ASSERT_TRUE(op.pj->over);
}
proj_destroy(Pnormalized);
proj_destroy(P);
}
+67 -4
View File
@@ -5962,6 +5962,19 @@ TEST(crs, parametricCRS_WKT1) {
// ---------------------------------------------------------------------------
TEST(crs, derivedVerticalCRS_basic) {
auto crs = createDerivedVerticalCRS();
EXPECT_TRUE(crs->isEquivalentTo(crs.get()));
EXPECT_TRUE(crs->shallowClone()->isEquivalentTo(crs.get()));
EXPECT_TRUE(!crs->isEquivalentTo(createUnrelatedObject().get()));
EXPECT_FALSE(crs->isEquivalentTo(crs->baseCRS().get()));
EXPECT_FALSE(crs->baseCRS()->isEquivalentTo(crs.get()));
}
// ---------------------------------------------------------------------------
TEST(crs, DerivedVerticalCRS_WKT2) {
auto expected = "VERTCRS[\"Derived vertCRS\",\n"
@@ -5976,10 +5989,6 @@ TEST(crs, DerivedVerticalCRS_WKT2) {
" ID[\"EPSG\",9001]]]]";
auto crs = createDerivedVerticalCRS();
EXPECT_TRUE(crs->isEquivalentTo(crs.get()));
EXPECT_TRUE(crs->shallowClone()->isEquivalentTo(crs.get()));
EXPECT_TRUE(!crs->isEquivalentTo(createUnrelatedObject().get()));
EXPECT_EQ(crs->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT2).get()),
expected);
@@ -6484,6 +6493,19 @@ TEST(crs, crs_alterCSLinearUnit) {
EXPECT_EQ(cs->axisList()[1]->unit().conversionToSI(), 2);
}
{
auto crs = createDerivedProjectedCRS()->alterCSLinearUnit(
UnitOfMeasure("my unit", 2));
auto derivedProjCRS = dynamic_cast<DerivedProjectedCRS *>(crs.get());
ASSERT_TRUE(derivedProjCRS != nullptr);
auto cs = derivedProjCRS->coordinateSystem();
ASSERT_EQ(cs->axisList().size(), 2U);
EXPECT_EQ(cs->axisList()[0]->unit().name(), "my unit");
EXPECT_EQ(cs->axisList()[0]->unit().conversionToSI(), 2);
EXPECT_EQ(cs->axisList()[1]->unit().name(), "my unit");
EXPECT_EQ(cs->axisList()[1]->unit().conversionToSI(), 2);
}
{
auto crs = GeodeticCRS::EPSG_4978->alterCSLinearUnit(
UnitOfMeasure("my unit", 2));
@@ -6791,6 +6813,47 @@ TEST(crs, promoteTo3D_and_demoteTo2D) {
EXPECT_TRUE(demoted->demoteTo2D(std::string(), nullptr)
->isEquivalentTo(demoted.get()));
}
{
auto crs = createDerivedProjectedCRS();
auto crs3D = crs->promoteTo3D(std::string(), dbContext);
auto crs3DAsDerivedProj =
nn_dynamic_pointer_cast<DerivedProjectedCRS>(crs3D);
ASSERT_TRUE(crs3DAsDerivedProj != nullptr);
EXPECT_EQ(crs3DAsDerivedProj->baseCRS()
->coordinateSystem()
->axisList()
.size(),
3U);
EXPECT_EQ(crs3DAsDerivedProj->coordinateSystem()->axisList().size(),
3U);
EXPECT_TRUE(crs3DAsDerivedProj->promoteTo3D(std::string(), nullptr)
->isEquivalentTo(crs3DAsDerivedProj.get()));
// Check that importing an exported DerivedProjected 3D CRS as WKT keeps
// the 3D aspect of the baseCRS (see #3340)
{
WKTFormatterNNPtr f(
WKTFormatter::create(WKTFormatter::Convention::WKT2_2019));
crs3DAsDerivedProj->exportToWKT(f.get());
auto obj = WKTParser().createFromWKT(f->toString());
auto crsFromWkt = nn_dynamic_pointer_cast<DerivedProjectedCRS>(obj);
ASSERT_TRUE(crsFromWkt != nullptr);
EXPECT_EQ(crsFromWkt->coordinateSystem()->axisList().size(), 3U);
EXPECT_EQ(
crsFromWkt->baseCRS()->coordinateSystem()->axisList().size(),
3U);
}
auto demoted = crs3DAsDerivedProj->demoteTo2D(std::string(), dbContext);
EXPECT_EQ(demoted->baseCRS()->coordinateSystem()->axisList().size(),
2U);
EXPECT_EQ(demoted->coordinateSystem()->axisList().size(), 2U);
EXPECT_TRUE(demoted->isEquivalentTo(
crs.get(), IComparable::Criterion::EQUIVALENT));
EXPECT_TRUE(demoted->demoteTo2D(std::string(), nullptr)
->isEquivalentTo(demoted.get()));
}
}
// ---------------------------------------------------------------------------
+63 -9
View File
@@ -8942,6 +8942,49 @@ TEST(io, projstringformatter_optim_hgridshift_vgridshift_hgridshift_inv) {
// ---------------------------------------------------------------------------
TEST(io, projstringformatter_optim_as_uc_vgridshift_uc_as_push_as_uc) {
// Nominal case
{
auto fmt = PROJStringFormatter::create();
fmt->addStep("axisswap");
fmt->addParam("order", "2,1");
fmt->addStep("unitconvert");
fmt->addParam("xy_in", "deg");
fmt->addParam("xy_out", "rad");
fmt->addStep("vgridshift");
fmt->addParam("grids", "foo");
fmt->addStep("unitconvert");
fmt->addParam("xy_in", "rad");
fmt->addParam("xy_out", "deg");
fmt->addStep("axisswap");
fmt->addParam("order", "2,1");
fmt->addStep("push");
fmt->addParam("v_1");
fmt->addParam("v_2");
fmt->addStep("axisswap");
fmt->addParam("order", "2,1");
fmt->addStep("unitconvert");
fmt->addParam("xy_in", "deg");
fmt->addParam("xy_out", "rad");
EXPECT_EQ(fmt->toString(),
"+proj=pipeline "
"+step +proj=push +v_1 +v_2 "
"+step +proj=axisswap +order=2,1 "
"+step +proj=unitconvert +xy_in=deg +xy_out=rad "
"+step +proj=vgridshift +grids=foo");
}
}
// ---------------------------------------------------------------------------
TEST(io, projparse_longlat) {
auto expected = "GEODCRS[\"unknown\",\n"
@@ -11062,10 +11105,11 @@ TEST(io, projparse_cart_unit) {
GeographicCRS::EPSG_4326, NN_NO_CHECK(crs));
ASSERT_TRUE(op != nullptr);
EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
"+proj=pipeline +step +proj=axisswap +order=2,1 +step "
"+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart "
"+ellps=WGS84 +step +proj=unitconvert +xy_in=m +z_in=m "
"+xy_out=km +z_out=km");
"+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=cart +ellps=WGS84 "
"+step +proj=unitconvert +xy_in=m +z_in=m +xy_out=km +z_out=km");
}
// ---------------------------------------------------------------------------
@@ -11080,11 +11124,13 @@ TEST(io, projparse_cart_unit_numeric) {
auto op = CoordinateOperationFactory::create()->createOperation(
GeographicCRS::EPSG_4326, NN_NO_CHECK(crs));
ASSERT_TRUE(op != nullptr);
EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
"+proj=pipeline +step +proj=axisswap +order=2,1 +step "
"+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart "
"+ellps=WGS84 +step +proj=unitconvert +xy_in=m +z_in=m "
"+xy_out=500 +z_out=500");
EXPECT_EQ(
op->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=cart +ellps=WGS84 "
"+step +proj=unitconvert +xy_in=m +z_in=m +xy_out=500 +z_out=500");
}
// ---------------------------------------------------------------------------
@@ -11865,6 +11911,14 @@ TEST(io, createFromUserInput) {
EXPECT_NO_THROW(createFromUserInput("WGS84 UTM zone 31N", dbContext));
EXPECT_NO_THROW(createFromUserInput("ID74", dbContext));
{
// Approximate match of a vertical CRS
auto obj = createFromUserInput("NGF IGN69 height", dbContext);
auto crs = nn_dynamic_pointer_cast<VerticalCRS>(obj);
EXPECT_TRUE(crs != nullptr);
EXPECT_EQ(crs->nameStr(), "NGF-IGN69 height");
}
{
// Exact match on each piece of the compound CRS
auto obj = createFromUserInput("WGS 84 + EGM96 height", dbContext);
+364 -13
View File
@@ -550,7 +550,7 @@ TEST(operation, geogCRS_to_geogCRS_context_helmert_geog3D_to_geocentirc) {
authFactory->createCoordinateReferenceSystem("4939"),
// GDA2020 geocentric
authFactory->createCoordinateReferenceSystem("7842"), ctxt);
ASSERT_EQ(list.size(), 1U);
ASSERT_GE(list.size(), 1U);
// Check there is no push / pop of v_3
EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
@@ -635,6 +635,73 @@ TEST(operation, geogCRS_to_geogCRS_context_datum_ensemble) {
// ---------------------------------------------------------------------------
TEST(operation, geogCRS_to_derived_geogCRS_3D) {
auto authFactory =
AuthorityFactory::create(DatabaseContext::create(), "EPSG");
auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
ctxt->setSpatialCriterion(
CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
auto dst_wkt =
"GEOGCRS[\"CH1903+ with 10m offset on ellipsoidal height\",\n"
" BASEGEOGCRS[\"CH1903+\",\n"
" DATUM[\"CH1903+\",\n"
" ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128,\n"
" LENGTHUNIT[\"metre\",1]],\n"
" ID[\"EPSG\",6150]],\n"
" PRIMEM[\"Greenwich\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8901]]],\n"
" DERIVINGCONVERSION[\"Offset on ellipsoidal height\",\n"
" METHOD[\"Geographic3D offsets\",\n"
" ID[\"EPSG\",9660]],\n"
" PARAMETER[\"Latitude offset\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8601]],\n"
" PARAMETER[\"Longitude offset\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8602]],\n"
" PARAMETER[\"Vertical Offset\",10,\n"
" LENGTHUNIT[\"metre\",1],\n"
" ID[\"EPSG\",8603]]],\n"
" CS[ellipsoidal,3],\n"
" AXIS[\"geodetic latitude (Lat)\",north,\n"
" ORDER[1],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433,\n"
" ID[\"EPSG\",9122]]],\n"
" AXIS[\"geodetic longitude (Lon)\",east,\n"
" ORDER[2],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433,\n"
" ID[\"EPSG\",9122]]],\n"
" AXIS[\"ellipsoidal height (h)\",up,\n"
" ORDER[3],\n"
" LENGTHUNIT[\"metre\",1,\n"
" ID[\"EPSG\",9001]]]]";
auto dstObj = WKTParser().createFromWKT(dst_wkt);
auto dstCRS = nn_dynamic_pointer_cast<CRS>(dstObj);
ASSERT_TRUE(dstCRS != nullptr);
auto list = CoordinateOperationFactory::create()->createOperations(
authFactory->createCoordinateReferenceSystem("4979"), // WGS 84 3D
NN_NO_CHECK(dstCRS), ctxt);
ASSERT_GE(list.size(), 1U);
EXPECT_EQ(
list[0]->nameStr(),
"Inverse of CH1903+ to WGS 84 (1) + Offset on ellipsoidal height");
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=cart +ellps=WGS84 "
"+step +proj=helmert +x=-674.374 +y=-15.056 +z=-405.346 "
"+step +inv +proj=cart +ellps=bessel "
"+step +proj=geogoffset +dlat=0 +dlon=0 +dh=10 "
"+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m "
"+step +proj=axisswap +order=2,1");
}
// ---------------------------------------------------------------------------
TEST(operation, vertCRS_to_geogCRS_context) {
auto authFactory =
AuthorityFactory::create(DatabaseContext::create(), "EPSG");
@@ -1331,13 +1398,13 @@ TEST(operation, geocentricCRS_to_geogCRS_different_datum) {
createGeocentricDatumWGS84(), GeographicCRS::EPSG_4269);
ASSERT_TRUE(op != nullptr);
EXPECT_EQ(op->nameStr(),
"Ballpark geocentric translation from WGS 84 to NAD83 "
"(geocentric) + Conversion from NAD83 "
"(geocentric) to NAD83");
"Conversion from WGS 84 to WGS 84 (geographic) + "
"Ballpark geographic offset from WGS 84 (geographic) to NAD83");
EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
"+proj=pipeline +step +inv +proj=cart +ellps=GRS80 +step "
"+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
"+order=2,1");
"+proj=pipeline "
"+step +inv +proj=cart +ellps=WGS84 "
"+step +proj=unitconvert +xy_in=rad +xy_out=deg "
"+step +proj=axisswap +order=2,1");
}
// ---------------------------------------------------------------------------
@@ -1347,13 +1414,14 @@ TEST(operation, geogCRS_to_geocentricCRS_different_datum) {
auto op = CoordinateOperationFactory::create()->createOperation(
GeographicCRS::EPSG_4269, createGeocentricDatumWGS84());
ASSERT_TRUE(op != nullptr);
EXPECT_EQ(op->nameStr(), "Conversion from NAD83 to NAD83 (geocentric) + "
"Ballpark geocentric translation from NAD83 "
"(geocentric) to WGS 84");
EXPECT_EQ(op->nameStr(),
"Ballpark geographic offset from NAD83 to WGS 84 (geographic) + "
"Conversion from WGS 84 (geographic) to WGS 84");
EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
"+proj=pipeline +step +proj=axisswap +order=2,1 +step "
"+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart "
"+ellps=GRS80");
"+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=cart +ellps=WGS84");
}
// ---------------------------------------------------------------------------
@@ -1766,6 +1834,87 @@ TEST(operation, geogCRS_to_geogCRS_WGS84_to_GDA2020) {
// ---------------------------------------------------------------------------
TEST(operation, geogCRS_to_geogCRS_with_intermediate_no_ids) {
auto dbContext = DatabaseContext::create();
auto authFactory = AuthorityFactory::create(dbContext, std::string());
auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
ctxt->setSpatialCriterion(
CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
ctxt->setGridAvailabilityUse(
CoordinateOperationContext::GridAvailabilityUse::
IGNORE_GRID_AVAILABILITY);
auto objSrc = WKTParser().createFromWKT(
"GEOGCRS[\"input\",\n"
" DATUM[\"International Terrestrial Reference Frame 2014\",\n"
" ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
" LENGTHUNIT[\"metre\",1]],\n"
" ID[\"EPSG\",1165]],\n"
" PRIMEM[\"Greenwich\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8901]],\n"
" CS[ellipsoidal,3],\n"
" AXIS[\"longitude\",east,\n"
" ORDER[1],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433,\n"
" ID[\"EPSG\",9122]]],\n"
" AXIS[\"latitude\",north,\n"
" ORDER[2],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433,\n"
" ID[\"EPSG\",9122]]],\n"
" AXIS[\"ellipsoidal height (h)\",up,\n"
" ORDER[3],\n"
" LENGTHUNIT[\"metre\",1]]]");
auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
ASSERT_TRUE(src != nullptr);
auto objDest = WKTParser().createFromWKT(
"GEOGCRS[\"output\",\n"
" DATUM[\"Estonia 1997\",\n"
" ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
" LENGTHUNIT[\"metre\",1]],\n"
" ID[\"EPSG\",6180]],\n"
" PRIMEM[\"Greenwich\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8901]],\n"
" CS[ellipsoidal,3],\n"
" AXIS[\"longitude\",east,\n"
" ORDER[1],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433,\n"
" ID[\"EPSG\",9122]]],\n"
" AXIS[\"latitude\",north,\n"
" ORDER[2],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433,\n"
" ID[\"EPSG\",9122]]],\n"
" AXIS[\"ellipsoidal height (h)\",up,\n"
" ORDER[3],\n"
" LENGTHUNIT[\"metre\",1]]]");
auto dest = nn_dynamic_pointer_cast<CRS>(objDest);
ASSERT_TRUE(dest != nullptr);
{
auto list = CoordinateOperationFactory::create()->createOperations(
NN_NO_CHECK(src), NN_NO_CHECK(dest), ctxt);
ASSERT_GE(list.size(), 1U);
// Test that a non-noop operation is returned
EXPECT_EQ(
list[0]->nameStr(),
"axis order change (geographic3D horizontal) + "
"Conversion from ITRF2014 (geog3D) to ITRF2014 (geocentric) + "
"ITRF2014 to ETRF2014 (1) + "
"Inverse of NKG_ETRF14 to ETRF2014 + "
"NKG_ETRF14 to ETRF96@2000.0 + "
"ETRF96@2000.0 to ETRF96@1997.56 + "
"Conversion from ETRS89 (geocentric) to ETRS89 (geog2D) + "
"Inverse of EST97 to ETRS89 (1) + "
"Null geographic offset from EST97 (geog2D) to EST97 (geog3D) + "
"axis order change (geographic3D horizontal)");
}
}
// ---------------------------------------------------------------------------
static ProjectedCRSNNPtr createUTM31_WGS84() {
return ProjectedCRS::create(
PropertyMap(), GeographicCRS::EPSG_4326,
@@ -4991,6 +5140,63 @@ TEST(operation, compoundCRS_to_compoundCRS_issue_2720) {
// ---------------------------------------------------------------------------
TEST(operation, compoundCRS_to_compoundCRS_issue_3328) {
auto authFactory =
AuthorityFactory::create(DatabaseContext::create(), std::string());
// "WGS 84 + EGM96 height"
auto srcObj = createFromUserInput("EPSG:4326+5773",
authFactory->databaseContext(), false);
auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
ASSERT_TRUE(src != nullptr);
// "WGS 84 + CGVD28 height"
auto dstObj = createFromUserInput("EPSG:4326+5713",
authFactory->databaseContext(), false);
auto dst = nn_dynamic_pointer_cast<CRS>(dstObj);
ASSERT_TRUE(dst != nullptr);
auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
ctxt->setGridAvailabilityUse(
CoordinateOperationContext::GridAvailabilityUse::
IGNORE_GRID_AVAILABILITY);
ctxt->setSpatialCriterion(
CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
auto list = CoordinateOperationFactory::create()->createOperations(
NN_NO_CHECK(src), NN_NO_CHECK(dst), ctxt);
ASSERT_GE(list.size(), 1U);
EXPECT_EQ(list[0]->nameStr(), "Inverse of WGS 84 to EGM96 height (1) + "
"Inverse of NAD83(CSRS) to WGS 84 (2) + "
"NAD83(CSRS) to CGVD28 height (1) + "
"NAD83(CSRS) to WGS 84 (2)");
EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
"+proj=pipeline "
"+step +proj=push +v_1 +v_2 "
"+step +proj=axisswap +order=2,1 "
"+step +proj=unitconvert +xy_in=deg +xy_out=rad "
"+step +proj=vgridshift +grids=us_nga_egm96_15.tif +multiplier=1 "
"+step +proj=cart +ellps=WGS84 "
"+step +inv +proj=helmert +x=-0.991 +y=1.9072 +z=0.5129 "
"+rx=-0.0257899075194932 "
"+ry=-0.0096500989602704 +rz=-0.0116599432323421 +s=0 "
"+convention=coordinate_frame "
"+step +inv +proj=cart +ellps=GRS80 "
"+step +inv +proj=vgridshift +grids=ca_nrc_HT2_2010v70.tif "
"+multiplier=1 "
"+step +proj=push +v_3 "
"+step +proj=cart +ellps=GRS80 "
"+step +proj=helmert +x=-0.991 +y=1.9072 +z=0.5129 "
"+rx=-0.0257899075194932 "
"+ry=-0.0096500989602704 +rz=-0.0116599432323421 +s=0 "
"+convention=coordinate_frame "
"+step +inv +proj=cart +ellps=WGS84 "
"+step +proj=pop +v_3 "
"+step +proj=unitconvert +xy_in=rad +xy_out=deg "
"+step +proj=axisswap +order=2,1 "
"+step +proj=pop +v_1 +v_2");
}
// ---------------------------------------------------------------------------
TEST(
operation,
compoundCRS_to_compoundCRS_concatenated_operation_with_two_vert_transformation_and_ballpark_geog) {
@@ -6593,6 +6799,151 @@ TEST(operation,
// ---------------------------------------------------------------------------
TEST(operation, compoundCRS_of_bound_horizCRS_and_bound_vertCRS_to_geogCRS) {
auto authFactory =
AuthorityFactory::create(DatabaseContext::create(), "EPSG");
auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
ctxt->setGridAvailabilityUse(
CoordinateOperationContext::GridAvailabilityUse::
IGNORE_GRID_AVAILABILITY);
auto wkt =
"COMPOUNDCRS[\"CH1903 / LV03 + EGM96 height\",\n"
" BOUNDCRS[\n"
" SOURCECRS[\n"
" PROJCRS[\"CH1903 / LV03\",\n"
" BASEGEOGCRS[\"CH1903\",\n"
" DATUM[\"CH1903\",\n"
" ELLIPSOID[\"Bessel "
"1841\",6377397.155,299.1528128,\n"
" LENGTHUNIT[\"metre\",1]]],\n"
" PRIMEM[\"Greenwich\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
" ID[\"EPSG\",4149]],\n"
" CONVERSION[\"Swiss Oblique Mercator 1903M\",\n"
" METHOD[\"Hotine Oblique Mercator (variant B)\",\n"
" ID[\"EPSG\",9815]],\n"
" PARAMETER[\"Latitude of projection "
"centre\",46.9524055555556,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8811]],\n"
" PARAMETER[\"Longitude of projection "
"centre\",7.43958333333333,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8812]],\n"
" PARAMETER[\"Azimuth of initial line\",90,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8813]],\n"
" PARAMETER[\"Angle from Rectified to Skew "
"Grid\",90,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433],\n"
" ID[\"EPSG\",8814]],\n"
" PARAMETER[\"Scale factor on initial line\",1,\n"
" SCALEUNIT[\"unity\",1],\n"
" ID[\"EPSG\",8815]],\n"
" PARAMETER[\"Easting at projection "
"centre\",600000,\n"
" LENGTHUNIT[\"metre\",1],\n"
" ID[\"EPSG\",8816]],\n"
" PARAMETER[\"Northing at projection "
"centre\",200000,\n"
" LENGTHUNIT[\"metre\",1],\n"
" ID[\"EPSG\",8817]]],\n"
" CS[Cartesian,2],\n"
" AXIS[\"easting (Y)\",east,\n"
" ORDER[1],\n"
" LENGTHUNIT[\"metre\",1]],\n"
" AXIS[\"northing (X)\",north,\n"
" ORDER[2],\n"
" LENGTHUNIT[\"metre\",1]]]],\n"
" TARGETCRS[\n"
" GEOGCRS[\"WGS 84\",\n"
" DATUM[\"World Geodetic System 1984\",\n"
" ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
" LENGTHUNIT[\"metre\",1]]],\n"
" PRIMEM[\"Greenwich\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
" CS[ellipsoidal,2],\n"
" AXIS[\"latitude\",north,\n"
" ORDER[1],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
" AXIS[\"longitude\",east,\n"
" ORDER[2],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
" ID[\"EPSG\",4326]]],\n"
" ABRIDGEDTRANSFORMATION[\"CH1903 to WGS 84 (2)\",\n"
" VERSION[\"BfL-CH 2\"],\n"
" METHOD[\"Geocentric translations (geog2D domain)\",\n"
" ID[\"EPSG\",9603]],\n"
" PARAMETER[\"X-axis translation\",674.374,\n"
" ID[\"EPSG\",8605]],\n"
" PARAMETER[\"Y-axis translation\",15.056,\n"
" ID[\"EPSG\",8606]],\n"
" PARAMETER[\"Z-axis translation\",405.346,\n"
" ID[\"EPSG\",8607]]]],\n"
" BOUNDCRS[\n"
" SOURCECRS[\n"
" VERTCRS[\"EGM96 height\",\n"
" VDATUM[\"EGM96 geoid\"],\n"
" CS[vertical,1],\n"
" AXIS[\"gravity-related height (H)\",up,\n"
" LENGTHUNIT[\"metre\",1]],\n"
" USAGE[\n"
" SCOPE[\"Geodesy.\"],\n"
" AREA[\"World.\"],\n"
" BBOX[-90,-180,90,180]],\n"
" ID[\"EPSG\",5773]]],\n"
" TARGETCRS[\n"
" GEOGCRS[\"WGS 84\",\n"
" DATUM[\"World Geodetic System 1984\",\n"
" ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
" LENGTHUNIT[\"metre\",1]]],\n"
" PRIMEM[\"Greenwich\",0,\n"
" ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
" CS[ellipsoidal,3],\n"
" AXIS[\"latitude\",north,\n"
" ORDER[1],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
" AXIS[\"longitude\",east,\n"
" ORDER[2],\n"
" ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
" AXIS[\"ellipsoidal height\",up,\n"
" ORDER[3],\n"
" LENGTHUNIT[\"metre\",1]],\n"
" ID[\"EPSG\",4979]]],\n"
" ABRIDGEDTRANSFORMATION[\"WGS 84 to EGM96 height (1)\",\n"
" METHOD[\"Geographic3D to GravityRelatedHeight (EGM)\",\n"
" ID[\"EPSG\",9661]],\n"
" PARAMETERFILE[\"Geoid (height correction) model "
"file\",\"us_nga_egm96_15.tif\"]]]]";
auto srcObj =
createFromUserInput(wkt, authFactory->databaseContext(), false);
auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
ASSERT_TRUE(src != nullptr);
// WGS 84 3D
auto dst = authFactory->createCoordinateReferenceSystem("4979");
auto list = CoordinateOperationFactory::create()->createOperations(
NN_NO_CHECK(src), dst, ctxt);
ASSERT_EQ(list.size(), 1U);
auto op_proj =
list[0]->exportToPROJString(PROJStringFormatter::create().get());
EXPECT_EQ(op_proj,
"+proj=pipeline "
"+step +inv +proj=somerc +lat_0=46.9524055555556 "
"+lon_0=7.43958333333333 +k_0=1 "
"+x_0=600000 +y_0=200000 +ellps=bessel "
"+step +proj=push +v_3 "
"+step +proj=cart +ellps=bessel "
"+step +proj=helmert +x=674.374 +y=15.056 +z=405.346 "
"+step +inv +proj=cart +ellps=WGS84 "
"+step +proj=pop +v_3 "
"+step +proj=vgridshift +grids=us_nga_egm96_15.tif +multiplier=1 "
"+step +proj=unitconvert +xy_in=rad +xy_out=deg "
"+step +proj=axisswap +order=2,1");
}
// ---------------------------------------------------------------------------
TEST(operation, compoundCRS_from_WKT2_to_geogCRS_3D_context) {
auto authFactory =
AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+1 -1
View File
@@ -5,7 +5,7 @@ set -e
echo "$TRAVIS_SECURE_ENV_VARS"
./travis/build_docs.sh
# Only build and publish docs when changes are made on most recent maintenance branch
if test "$TRAVIS_SECURE_ENV_VARS" = "true" -a "$TRAVIS_BRANCH" = "9.0"; then
if test "$TRAVIS_SECURE_ENV_VARS" = "true" -a "$TRAVIS_BRANCH" = "9.1"; then
echo "publish website";
./travis/add_deploy_key.sh;
./travis/deploy_website.sh $TRAVIS_BUILD_DIR/docs/build /tmp;